summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/functions.h6
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/interface.c46
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/structures.h3
-rw-r--r--usr/src/cmd/cmd-inet/lib/nwamd/wireless.c117
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c55
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h19
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c114
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c77
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h5
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c136
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/defs.h4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c53
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c9
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c4
-rw-r--r--usr/src/cmd/dladm/Makefile7
-rw-r--r--usr/src/cmd/dladm/dladm.c2801
-rw-r--r--usr/src/cmd/dladm/dladm.xcl9
-rw-r--r--usr/src/cmd/dlmgmtd/Makefile77
-rw-r--r--usr/src/cmd/dlmgmtd/datalink.conf (renamed from usr/src/cmd/dladm/linkprop.conf)2
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt.xml90
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_db.c949
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_door.c1075
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_impl.h134
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_main.c345
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_util.c748
-rw-r--r--usr/src/cmd/dlmgmtd/svc-dlmgmtd (renamed from usr/src/cmd/dladm/aggregation.conf)30
-rw-r--r--usr/src/cmd/rcm_daemon/Makefile.com12
-rw-r--r--usr/src/cmd/rcm_daemon/common/aggr_rcm.c1455
-rw-r--r--usr/src/cmd/rcm_daemon/common/ip_rcm.c585
-rw-r--r--usr/src/cmd/rcm_daemon/common/network_rcm.c513
-rw-r--r--usr/src/cmd/rcm_daemon/common/vlan_rcm.c1327
-rw-r--r--usr/src/cmd/rpcsvc/rstat_proc.c15
-rw-r--r--usr/src/cmd/svc/milestone/manifest-import19
-rw-r--r--usr/src/cmd/svc/milestone/net-nwam17
-rw-r--r--usr/src/cmd/svc/milestone/net-physical16
-rw-r--r--usr/src/cmd/svc/seed/Makefile3
-rw-r--r--usr/src/cmd/svc/seed/inc.flg3
-rw-r--r--usr/src/cmd/svc/shell/net_include.sh64
-rw-r--r--usr/src/cmd/truss/codes.c20
-rw-r--r--usr/src/cmd/vna/vna.c152
-rw-r--r--usr/src/cmd/zoneadmd/Makefile4
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c150
44 files changed, 9454 insertions, 1824 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 01c00817c7..6402d952e2 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -21,7 +21,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -223,6 +223,7 @@ COMMON_SUBDIRS= \
lgrpinfo \
line \
link \
+ dlmgmtd \
listen \
loadkeys \
locale \
@@ -800,6 +801,7 @@ MANIFEST_TOPDIRS= \
ipf \
keyserv \
ldapcachemgr \
+ dlmgmtd \
nscd \
oplhpd \
power \
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/functions.h b/usr/src/cmd/cmd-inet/lib/nwamd/functions.h
index 96f4c50a63..bb88f4d2d9 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/functions.h
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/functions.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -62,9 +62,9 @@ extern int lookup_count_property(const char *, const char *, uint64_t *);
/* wireless.c: wifi link handling */
extern void init_mutexes(void);
-extern boolean_t connect_chosen_lan(struct wireless_lan *, const char *);
+extern boolean_t connect_chosen_lan(struct wireless_lan *, struct interface *);
extern struct wireless_lan *prompt_for_visited(void);
-extern boolean_t handle_wireless_lan(const char *);
+extern boolean_t handle_wireless_lan(struct interface *);
extern boolean_t scan_wireless_nets(struct interface *);
extern void create_known_wifi_nets_file(void);
extern void update_known_wifi_nets_file(const char *, const char *);
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/interface.c b/usr/src/cmd/cmd-inet/lib/nwamd/interface.c
index b66dee45f5..304cb78467 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/interface.c
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/interface.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -558,7 +558,7 @@ bringupinterface(const char *ifname, const char *host, const char *ipv6addr,
}
if (intf->if_type == IF_WIRELESS) {
- if (!handle_wireless_lan(ifname)) {
+ if (!handle_wireless_lan(intf)) {
syslog(LOG_INFO, "Could not connect to any WLAN, not "
"bringing %s up", ifname);
return (B_FALSE);
@@ -631,8 +631,8 @@ takedowninterface(const char *ifname, boolean_t popup, boolean_t v6onlink)
(void) start_child(IFCONFIG, ifname, "inet6", "unplumb", NULL);
}
- if (find_if_type(ifname) == IF_WIRELESS)
- (void) dladm_wlan_disconnect(ifname);
+ if (ifp->if_type == IF_WIRELESS)
+ (void) dladm_wlan_disconnect(ifp->if_linkid);
dprintf("takedown interface, free cached ip address");
if (ifp != NULL) {
@@ -751,6 +751,7 @@ struct interface *
add_interface(sa_family_t family, const char *name, uint64_t flags)
{
struct interface *i;
+ datalink_id_t linkid = DATALINK_INVALID_LINKID;
enum interface_type iftype;
if (name == NULL)
@@ -801,6 +802,13 @@ add_interface(sa_family_t family, const char *name, uint64_t flags)
i->if_lflags = 0;
i->if_timer_expire = 0;
+ /*
+ * If linkid is DATALINK_INVALID_LINKID, it is an IP-layer only
+ * interface.
+ */
+ (void) dladm_name2info(name, &linkid, NULL, NULL, NULL);
+ i->if_linkid = linkid;
+
dprintf("added interface %s of type %s af %d; is %savailable",
i->if_name, if_type_str(i->if_type), i->if_family,
((i->if_type == IF_WIRELESS) ||
@@ -1077,7 +1085,7 @@ initialize_interfaces(void)
wait_time = NWAM_IF_WAIT_DELTA_MAX;
}
- (void) dladm_init_linkprop();
+ (void) dladm_init_linkprop(DATALINK_ALL_LINKID);
(void) icfg_iterate_if(AF_INET, ICFG_PLUMBED, NULL, do_add_interface);
@@ -1167,6 +1175,7 @@ check_interface_timer(struct interface *ifp, void *arg)
enum interface_type
find_if_type(const char *name)
{
+ uint32_t media;
enum interface_type type;
if (name == NULL) {
@@ -1174,20 +1183,19 @@ find_if_type(const char *name)
return (IF_UNKNOWN);
}
- if (strncmp(name, "ip.tun", 6) == 0) {
- /*
- * We'll need to update our tunnel detection once
- * clearview/uv and clearview/tun driver projects
- * go back; tunnel names won't necessarily be ip.tunN
- */
- type = IF_TUN;
- } else {
- /*
- * We didn't recognize it. Try the libdladm function
- * to decide if it is wireless or not; if not, assume
- * that it's wired.
- */
- type = dladm_wlan_is_valid(name) ? IF_WIRELESS : IF_WIRED;
+ type = IF_WIRED;
+ if (dladm_name2info(name, NULL, NULL, NULL, &media) !=
+ DLADM_STATUS_OK) {
+ if (strncmp(name, "ip.tun", 6) == 0) {
+ /*
+ * We'll need to update our tunnel detection once
+ * clearview/uv and clearview/tun driver projects
+ * go back; tunnel names won't necessarily be ip.tunN
+ */
+ type = IF_TUN;
+ }
+ } else if (media == DL_WIFI) {
+ type = IF_WIRELESS;
}
return (type);
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/structures.h b/usr/src/cmd/cmd-inet/lib/nwamd/structures.h
index 0f232cd70b..caf0815d32 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/structures.h
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/structures.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -89,6 +89,7 @@ struct np_event {
*/
struct interface {
char *if_name;
+ datalink_id_t if_linkid;
sa_family_t if_family;
uint64_t if_flags;
uint32_t if_lflags;
diff --git a/usr/src/cmd/cmd-inet/lib/nwamd/wireless.c b/usr/src/cmd/cmd-inet/lib/nwamd/wireless.c
index 78cd0f4c74..f99d103dd3 100644
--- a/usr/src/cmd/cmd-inet/lib/nwamd/wireless.c
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/wireless.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -152,10 +152,10 @@ static dladm_wlan_key_t *retrieve_key(const char *, const char *,
static boolean_t add_wlan_entry(struct interface *, char *, char *, char *,
dladm_wlan_secmode_t);
static boolean_t already_in_visited_wlan_list(const struct wireless_lan *);
-static boolean_t check_wlan(const char *, const char *);
-static boolean_t connect_or_autoconf(struct wireless_lan *, const char *);
+static boolean_t check_wlan(struct interface *, const char *);
+static boolean_t connect_or_autoconf(struct wireless_lan *, struct interface *);
static return_vals_t connect_to_new_wlan(const struct wireless_lan *, int,
- const char *);
+ struct interface *);
static boolean_t find_wlan_entry(struct interface *, char *, char *);
static void free_wireless_lan(struct wireless_lan *);
static struct wireless_lan *get_specific_lan(void);
@@ -167,7 +167,7 @@ static void free_argv(char **);
static char **build_wlanlist_zargv(const struct wireless_lan *, int,
const char *, int, const char **, int);
static char *get_zenity_response(char *const *);
-static boolean_t wlan_autoconf(const char *ifname);
+static boolean_t wlan_autoconf(struct interface *);
static int zenity_height(int);
static boolean_t get_scan_results(void *, dladm_wlan_attr_t *);
static boolean_t known_wifi_nets_lookup(const char *, const char *, char *);
@@ -438,20 +438,21 @@ clear_lan_entries(void)
* to disassociate with it and then return false.
*/
static boolean_t
-check_wlan(const char *intf, const char *exp_essid)
+check_wlan(struct interface *intf, const char *exp_essid)
{
dladm_wlan_linkattr_t attr;
dladm_status_t status;
char cur_essid[DLADM_STRSIZE];
char errmsg[DLADM_STRSIZE];
- status = dladm_wlan_get_linkattr(intf, &attr);
+ status = dladm_wlan_get_linkattr(intf->if_linkid, &attr);
if (status != DLADM_STATUS_OK) {
- dprintf("check_wlan: dladm_wlan_get_linkattr() failed: %s",
+ dprintf("check_wlan: dladm_wlan_get_linkattr() for %s "
+ "failed: %s", intf->if_name,
dladm_status2str(status, errmsg));
return (B_FALSE);
}
- if (attr.la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED)
+ if (attr.la_status == DLADM_WLAN_LINK_DISCONNECTED)
return (B_FALSE);
if (exp_essid == NULL)
return (B_TRUE);
@@ -462,8 +463,10 @@ check_wlan(const char *intf, const char *exp_essid)
return (B_TRUE);
/* Tell the driver to disassociate with the current AP. */
- if (dladm_wlan_disconnect(intf) != DLADM_STATUS_OK)
- dprintf("check_wlan: dladm_wlan_disconnect() fails");
+ if (dladm_wlan_disconnect(intf->if_linkid) != DLADM_STATUS_OK) {
+ dprintf("check_wlan: dladm_wlan_disconnect() for %s fails",
+ intf->if_name);
+ }
return (B_FALSE);
}
@@ -505,7 +508,7 @@ scan_wireless_nets(struct interface *intf)
* a lock in checking wireless_lan_used.
*/
num_ap = wireless_lan_used;
- status = dladm_wlan_scan(intf->if_name, intf, get_scan_results);
+ status = dladm_wlan_scan(intf->if_linkid, intf, get_scan_results);
if (status != DLADM_STATUS_OK)
syslog(LOG_NOTICE, "cannot scan link '%s'", intf->if_name);
else
@@ -570,6 +573,8 @@ get_scan_results(void *arg, dladm_wlan_attr_t *attrp)
void *
periodic_wireless_scan(void *arg)
{
+ datalink_id_t linkid;
+
/*
* No periodic scan if the "-i" option is used to change the
* interval to 0.
@@ -601,13 +606,18 @@ periodic_wireless_scan(void *arg)
*/
if (ret == 0) {
if (cur_llp != NULL) {
- if (cur_llp->llp_type != IF_WIRELESS ||
- dladm_wlan_get_linkattr(cur_llp->llp_lname,
- &attr) != DLADM_STATUS_OK) {
+ if (cur_llp->llp_type != IF_WIRELESS)
+ continue;
+
+ if (dladm_name2info(cur_llp->llp_lname, &linkid,
+ NULL, NULL, NULL) != DLADM_STATUS_OK ||
+ dladm_wlan_get_linkattr(linkid, &attr) !=
+ DLADM_STATUS_OK) {
continue;
}
+
if (attr.la_status ==
- DLADM_WLAN_LINKSTATUS_CONNECTED &&
+ DLADM_WLAN_LINK_CONNECTED &&
attr.la_wlan_attr.wa_strength >
wireless_scan_level) {
continue;
@@ -771,7 +781,7 @@ store_key(struct wireless_lan *wlan)
status = dladm_set_secobj(obj_name, class,
obj_val, obj_len,
- DLADM_OPT_CREATE | DLADM_OPT_PERSIST | DLADM_OPT_TEMP);
+ DLADM_OPT_CREATE | DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK) {
syslog(LOG_ERR, "store_key: could not create secure object "
"'%s' for key: %s", obj_name,
@@ -826,7 +836,7 @@ retrieve_key(const char *essid, const char *bssid, dladm_secobj_class_t req)
/* Try the kernel first, then fall back to persistent storage. */
status = dladm_get_secobj(cooked_key->wk_name, &class,
cooked_key->wk_val, &cooked_key->wk_len,
- DLADM_OPT_TEMP);
+ DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK) {
dprintf("retrieve_key: dladm_get_secobj(TEMP) failed: %s",
dladm_status2str(status, errmsg));
@@ -1007,7 +1017,7 @@ known_wifi_nets_lookup(const char *new_essid, const char *new_bssid,
* reqlan->bssid is optional (i.e., may be NULL)
*/
boolean_t
-connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
+connect_chosen_lan(struct wireless_lan *reqlan, struct interface *intf)
{
uint_t keycount;
dladm_wlan_key_t *key;
@@ -1022,17 +1032,17 @@ connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
if (reqlan->essid == NULL)
return (B_FALSE);
dprintf("connect_chosen_lan(%s, %s, %s)", reqlan->essid,
- STRING(reqlan->bssid), ifname);
+ STRING(reqlan->bssid), intf->if_name);
/* If it is already connected to the required AP, just return. */
- if (check_wlan(ifname, reqlan->essid))
+ if (check_wlan(intf, reqlan->essid))
return (B_TRUE);
if (dladm_wlan_str2essid(reqlan->essid, &attr.wa_essid) !=
DLADM_STATUS_OK) {
syslog(LOG_ERR,
"connect_chosen_lan: invalid ESSID '%s' for '%s'",
- reqlan->essid, ifname);
+ reqlan->essid, intf->if_name);
return (B_FALSE);
}
attr.wa_valid = DLADM_WLAN_ATTR_ESSID;
@@ -1041,7 +1051,7 @@ connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
DLADM_STATUS_OK) {
syslog(LOG_ERR,
"connect_chosen_lan: invalid BSSID '%s' for '%s'",
- reqlan->bssid, ifname);
+ reqlan->bssid, intf->if_name);
return (B_FALSE);
}
attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
@@ -1068,8 +1078,8 @@ connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
* try a second time with just the ESSID.
*/
- status = dladm_wlan_connect(ifname, &attr, timeout, key, keycount,
- flags);
+ status = dladm_wlan_connect(intf->if_linkid, &attr, timeout, key,
+ keycount, flags);
dprintf("connect_chosen_lan: dladm_wlan_connect returned %s",
dladm_status2str(status, errmsg));
if (status == DLADM_STATUS_TIMEDOUT && reqlan->bssid != NULL) {
@@ -1078,13 +1088,14 @@ connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
reqlan->essid, reqlan->bssid, reqlan->essid);
attr.wa_valid &= ~DLADM_WLAN_ATTR_BSSID;
flags = 0;
- status = dladm_wlan_connect(ifname, &attr, timeout, key,
- keycount, flags);
+ status = dladm_wlan_connect(intf->if_linkid, &attr, timeout,
+ key, keycount, flags);
}
if (status != DLADM_STATUS_OK) {
syslog(LOG_ERR,
"connect_chosen_lan: connect to '%s' failed on '%s': %s",
- reqlan->essid, ifname, dladm_status2str(status, errmsg));
+ reqlan->essid, intf->if_name,
+ dladm_status2str(status, errmsg));
return (B_FALSE);
}
return (B_TRUE);
@@ -1095,13 +1106,13 @@ connect_chosen_lan(struct wireless_lan *reqlan, const char *ifname)
* If that fails, attempt to connect using autoconf.
*/
static boolean_t
-connect_or_autoconf(struct wireless_lan *reqlan, const char *ifname)
+connect_or_autoconf(struct wireless_lan *reqlan, struct interface *intf)
{
- if (!connect_chosen_lan(reqlan, ifname)) {
+ if (!connect_chosen_lan(reqlan, intf)) {
syslog(LOG_WARNING,
"Could not connect to chosen WLAN %s, going to auto-conf",
reqlan->essid);
- return (wlan_autoconf(ifname));
+ return (wlan_autoconf(intf));
}
return (B_TRUE);
}
@@ -1198,9 +1209,8 @@ build_wlanlist_zargv(const struct wireless_lan *lanlist, int nlans,
static return_vals_t
connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
- const char *ifname)
+ struct interface *intf)
{
- struct interface *intf;
int i, dlist_cnt;
int rtn;
char **zargv;
@@ -1209,19 +1219,13 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
struct wireless_lan *dlist, *reqlan;
boolean_t autoconf = B_FALSE;
- dprintf("connect_to_new_wlan(..., %d, %s)", nlans, ifname);
+ dprintf("connect_to_new_wlan(..., %d, %s)", nlans, intf->if_name);
if (nlans == 0) {
display(gettext("No Wifi networks found; continuing in case "
"you know of any which do not broadcast."));
}
- if ((intf = get_interface(ifname)) == NULL) {
- dprintf("connect_to_new_wlan: cannot find wireless interface: "
- "%s", ifname);
- return (FAILURE);
- }
-
/* build list of wlans to be displayed */
if ((dlist = calloc(nlans, sizeof (struct wireless_lan))) == NULL)
return (FAILURE);
@@ -1236,10 +1240,10 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
/*
* Only use the interface which finds the AP to connect to it.
*/
- if (strcmp(lanlist[i].wl_if_name, ifname) != 0) {
+ if (strcmp(lanlist[i].wl_if_name, intf->if_name) != 0) {
dprintf("connect_to_new_wlan: wrong interface (%s) for "
- "%s (should be %s)", ifname, lanlist[i].essid,
- lanlist[i].wl_if_name);
+ "%s (should be %s)", intf->if_name,
+ lanlist[i].essid, lanlist[i].wl_if_name);
continue;
}
@@ -1279,7 +1283,7 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
if ((reqlan == NULL) || (reqlan->essid == NULL)) {
dprintf("did not get user preference; attempting autoconf");
- rtn = wlan_autoconf(ifname) ? SUCCESS : FAILURE;
+ rtn = wlan_autoconf(intf) ? SUCCESS : FAILURE;
goto cleanup;
}
dprintf("get_user_preference() returned essid %s, bssid %s, encr %s",
@@ -1295,7 +1299,7 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
* now attempt to connect to selection, backing
* off to autoconf if the connect fails
*/
- if (connect_chosen_lan(reqlan, ifname)) {
+ if (connect_chosen_lan(reqlan, intf)) {
/*
* Succeeded, so add entry to known_essid_list_file;
* but first make sure the reqlan->bssid isn't empty.
@@ -1305,7 +1309,8 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
dladm_wlan_linkattr_t attr;
char bssid[DLADM_STRSIZE];
- status = dladm_wlan_get_linkattr(ifname, &attr);
+ status = dladm_wlan_get_linkattr(intf->if_linkid,
+ &attr);
if (status == DLADM_STATUS_OK) {
(void) dladm_wlan_bssid2str(
@@ -1326,7 +1331,7 @@ connect_to_new_wlan(const struct wireless_lan *lanlist, int nlans,
free_wireless_lan(reqlan);
if (autoconf)
- rtn = wlan_autoconf(ifname) ? SUCCESS : FAILURE;
+ rtn = wlan_autoconf(intf) ? SUCCESS : FAILURE;
else
rtn = SUCCESS;
@@ -1391,7 +1396,7 @@ prompt_for_visited(void)
}
static boolean_t
-wlan_autoconf(const char *ifname)
+wlan_autoconf(struct interface *intf)
{
dladm_status_t status;
boolean_t autoconf;
@@ -1402,7 +1407,7 @@ wlan_autoconf(const char *ifname)
}
/* If the NIC is already associated with something, just return. */
- if (check_wlan(ifname, NULL))
+ if (check_wlan(intf, NULL))
return (B_TRUE);
/*
@@ -1410,14 +1415,14 @@ wlan_autoconf(const char *ifname)
* to cycle through WLANs detected in priority order, attempting
* to connect.
*/
- status = dladm_wlan_connect(ifname, NULL,
+ status = dladm_wlan_connect(intf->if_linkid, NULL,
DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT, NULL, 0, 0);
if (status != DLADM_STATUS_OK) {
char errmsg[DLADM_STRSIZE];
syslog(LOG_ERR,
"wlan_autoconf: dladm_wlan_connect failed for '%s': %s",
- ifname, dladm_status2str(status, errmsg));
+ intf->if_name, dladm_status2str(status, errmsg));
return (B_FALSE);
}
return (B_TRUE);
@@ -1720,7 +1725,7 @@ cleanup:
* B_FALSE if we were unable to connect to anything
*/
boolean_t
-handle_wireless_lan(const char *ifname)
+handle_wireless_lan(struct interface *intf)
{
const struct wireless_lan *cur_wlans;
int i, num_wlans;
@@ -1839,7 +1844,7 @@ start_over:
if (strength < strongest)
goto connect_any;
}
- result = connect_or_autoconf(target, ifname);
+ result = connect_or_autoconf(target, intf);
connect_result = result ? SUCCESS : FAILURE;
} else if (visited_wlan_list->total > 1) {
@@ -1848,21 +1853,21 @@ start_over:
* prompt user for which one should we connect to
*/
if ((req_conf = prompt_for_visited()) != NULL) {
- result = connect_or_autoconf(req_conf, ifname);
+ result = connect_or_autoconf(req_conf, intf);
connect_result = result ? SUCCESS : FAILURE;
} else {
/*
* The user didn't make a choice; offer the full list.
*/
connect_result = connect_to_new_wlan(cur_wlans,
- num_wlans, ifname);
+ num_wlans, intf);
result = (connect_result == SUCCESS);
}
} else {
connect_any:
/* last case, no previously visited wlan found */
connect_result = connect_to_new_wlan(cur_wlans, num_wlans,
- ifname);
+ intf);
result = (connect_result == SUCCESS);
}
diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
index 1a964f0ce2..b9a02b54e7 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2632,9 +2632,17 @@ if_report(mib_item_t *item, char *matchname,
continue; /* 'for' loop 2a */
new_ifindex =
if_nametoindex(logintname);
+ /*
+ * First lookup the "link" kstats in
+ * case the link is renamed. Then
+ * fallback to the legacy kstats for
+ * those non-GLDv3 links.
+ */
if (new_ifindex != ifindex_v4 &&
- (ksp = kstat_lookup(kc, NULL, -1,
- ifname)) != NULL) {
+ (((ksp = kstat_lookup(kc, "link", 0,
+ ifname)) != NULL) ||
+ ((ksp = kstat_lookup(kc, NULL, -1,
+ ifname)) != NULL))) {
(void) safe_kstat_read(kc, ksp,
NULL);
stat.ipackets =
@@ -2774,11 +2782,20 @@ if_report(mib_item_t *item, char *matchname,
continue;
}
- ksp = kstat_lookup(kc, NULL, -1, buf);
- if (ksp &&
- ksp->ks_type == KSTAT_TYPE_NAMED)
+ /*
+ * First lookup the "link" kstats in
+ * case the link is renamed. Then
+ * fallback to the legacy kstats for
+ * those non-GLDv3 links.
+ */
+ if (((ksp = kstat_lookup(kc, "link",
+ 0, buf)) != NULL ||
+ (ksp = kstat_lookup(kc, NULL, -1,
+ buf)) != NULL) && (ksp->ks_type ==
+ KSTAT_TYPE_NAMED)) {
(void) safe_kstat_read(kc, ksp,
NULL);
+ }
t.ipackets = kstat_named_value(ksp,
"ipackets");
@@ -2926,9 +2943,18 @@ if_report(mib_item_t *item, char *matchname,
continue; /* 'for' loop 2d */
new_ifindex =
if_nametoindex(logintname);
+
+ /*
+ * First lookup the "link" kstats in
+ * case the link is renamed. Then
+ * fallback to the legacy kstats for
+ * those non-GLDv3 links.
+ */
if (new_ifindex != ifindex_v6 &&
+ ((ksp = kstat_lookup(kc, "link", 0,
+ ifname)) != NULL ||
(ksp = kstat_lookup(kc, NULL, -1,
- ifname)) != NULL) {
+ ifname)) != NULL)) {
(void) safe_kstat_read(kc, ksp,
NULL);
stat.ipackets =
@@ -3071,11 +3097,20 @@ if_report(mib_item_t *item, char *matchname,
continue;
}
- ksp = kstat_lookup(kc, NULL, -1, buf);
- if (ksp && ksp->ks_type ==
- KSTAT_TYPE_NAMED)
+ /*
+ * First lookup the "link" kstats in
+ * case the link is renamed. Then
+ * fallback to the legacy kstats for
+ * those non-GLDv3 links.
+ */
+ if (((ksp = kstat_lookup(kc, "link",
+ 0, buf)) != NULL ||
+ (ksp = kstat_lookup(kc, NULL, -1,
+ buf)) != NULL) && (ksp->ks_type ==
+ KSTAT_TYPE_NAMED)) {
(void) safe_kstat_read(kc,
ksp, NULL);
+ }
t.ipackets = kstat_named_value(ksp,
"ipackets");
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h b/usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h
index dc13c719ce..1169c82263 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -14,6 +14,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libdlwlan.h>
+#include <libdllink.h>
#ifdef __cplusplus
extern "C" {
@@ -25,15 +26,15 @@ typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE } wpa_key_mgmt;
struct wpa_driver_ops {
- int (*get_bssid)(const char *, char *);
- int (*get_ssid)(const char *ifname, char *);
- int (*set_wpa)(const char *, boolean_t);
- int (*set_key)(const char *, wpa_alg, uint8_t *,
+ int (*get_bssid)(datalink_id_t, char *);
+ int (*get_ssid)(datalink_id_t, char *);
+ int (*set_wpa)(datalink_id_t, boolean_t);
+ int (*set_key)(datalink_id_t, wpa_alg, uint8_t *,
int, boolean_t, uint8_t *, uint32_t, uint8_t *, uint32_t);
- int (*scan)(const char *);
- int (*get_scan_results)(const char *, dladm_wlan_ess_t *, uint32_t);
- int (*disassociate)(const char *, int);
- int (*associate)(const char *, const char *, uint8_t *, uint32_t);
+ int (*scan)(datalink_id_t);
+ int (*get_scan_results)(datalink_id_t, dladm_wlan_ess_t *, uint32_t);
+ int (*disassociate)(datalink_id_t, int);
+ int (*associate)(datalink_id_t, const char *, uint8_t *, uint32_t);
};
#ifdef __cplusplus
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c b/usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c
index 4ab82a2669..01ca5cea5e 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,7 +28,7 @@
/*
* get_bssid - get the current BSSID
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @bssid: buffer for BSSID (IEEE80211_ADDR_LEN = 6 bytes)
*
* Returns: 0 on success, -1 on failure
@@ -38,14 +38,14 @@
* associated.
*/
int
-wpa_driver_wifi_get_bssid(const char *ifname, char *bssid)
+wpa_driver_wifi_get_bssid(datalink_id_t linkid, char *bssid)
{
- int ret;
+ dladm_status_t status;
dladm_wlan_linkattr_t attr;
dladm_wlan_attr_t *wl_attrp;
- ret = dladm_wlan_get_linkattr(ifname, &attr);
- if (ret != DLADM_STATUS_OK)
+ status = dladm_wlan_get_linkattr(linkid, &attr);
+ if (status != DLADM_STATUS_OK)
return (-1);
wl_attrp = &attr.la_wlan_attr;
@@ -58,12 +58,12 @@ wpa_driver_wifi_get_bssid(const char *ifname, char *bssid)
wpa_printf(MSG_DEBUG, "wpa_driver_wifi_get_bssid: " MACSTR,
MAC2STR((unsigned char *)bssid));
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* get_ssid - get the current SSID
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @ssid: buffer for SSID (at least 32 bytes)
*
* Returns: length of the SSID on success, -1 on failure
@@ -72,14 +72,15 @@ wpa_driver_wifi_get_bssid(const char *ifname, char *bssid)
* Returning zero is recommended if the STA is not associated.
*/
int
-wpa_driver_wifi_get_ssid(const char *ifname, char *ssid)
+wpa_driver_wifi_get_ssid(datalink_id_t linkid, char *ssid)
{
int ret;
+ dladm_status_t status;
dladm_wlan_linkattr_t attr;
dladm_wlan_attr_t *wl_attrp;
- ret = dladm_wlan_get_linkattr(ifname, &attr);
- if (ret != DLADM_STATUS_OK)
+ status = dladm_wlan_get_linkattr(linkid, &attr);
+ if (status != DLADM_STATUS_OK)
return (-1);
wl_attrp = &attr.la_wlan_attr;
@@ -97,20 +98,20 @@ wpa_driver_wifi_get_ssid(const char *ifname, char *ssid)
}
static int
-wpa_driver_wifi_set_wpa_ie(const char *ifname,
- uint8_t *wpa_ie, uint32_t wpa_ie_len)
+wpa_driver_wifi_set_wpa_ie(datalink_id_t linkid, uint8_t *wpa_ie,
+ uint32_t wpa_ie_len)
{
- int ret;
+ dladm_status_t status;
wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_set_wpa_ie");
- ret = dladm_wlan_wpa_set_ie(ifname, wpa_ie, wpa_ie_len);
+ status = dladm_wlan_wpa_set_ie(linkid, wpa_ie, wpa_ie_len);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* set_wpa - enable/disable WPA support
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @enabled: 1 = enable, 0 = disable
*
* Returns: 0 on success, -1 on failure
@@ -122,38 +123,38 @@ wpa_driver_wifi_set_wpa_ie(const char *ifname,
* allow wpa_supplicant to control roaming).
*/
static int
-wpa_driver_wifi_set_wpa(const char *ifname, boolean_t enabled)
+wpa_driver_wifi_set_wpa(datalink_id_t linkid, boolean_t enabled)
{
- int ret;
+ dladm_status_t status;
wpa_printf(MSG_DEBUG, "wpa_driver_wifi_set_wpa: enable=%d", enabled);
- if (!enabled && wpa_driver_wifi_set_wpa_ie(ifname, NULL, 0) < 0)
+ if (!enabled && wpa_driver_wifi_set_wpa_ie(linkid, NULL, 0) < 0)
return (-1);
- ret = dladm_wlan_wpa_set_wpa(ifname, enabled);
+ status = dladm_wlan_wpa_set_wpa(linkid, enabled);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
static int
-wpa_driver_wifi_del_key(const char *ifname, int key_idx, unsigned char *addr)
+wpa_driver_wifi_del_key(datalink_id_t linkid, int key_idx, unsigned char *addr)
{
- int ret;
+ dladm_status_t status;
dladm_wlan_bssid_t bss;
wpa_printf(MSG_DEBUG, "%s: id=%d", "wpa_driver_wifi_del_key",
key_idx);
(void) memcpy(bss.wb_bytes, addr, DLADM_WLAN_BSSID_LEN);
- ret = dladm_wlan_wpa_del_key(ifname, key_idx, &bss);
+ status = dladm_wlan_wpa_del_key(linkid, key_idx, &bss);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* set_key - configure encryption key
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
* %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
@@ -185,19 +186,18 @@ wpa_driver_wifi_del_key(const char *ifname, int key_idx, unsigned char *addr)
* configuration.
*/
static int
-wpa_driver_wifi_set_key(const char *ifname, wpa_alg alg,
- unsigned char *addr, int key_idx,
- boolean_t set_tx, uint8_t *seq, uint32_t seq_len,
- uint8_t *key, uint32_t key_len)
+wpa_driver_wifi_set_key(datalink_id_t linkid, wpa_alg alg,
+ unsigned char *addr, int key_idx, boolean_t set_tx, uint8_t *seq,
+ uint32_t seq_len, uint8_t *key, uint32_t key_len)
{
char *alg_name;
dladm_wlan_cipher_t cipher;
dladm_wlan_bssid_t bss;
- int ret;
+ dladm_status_t status;
wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_set_key");
if (alg == WPA_ALG_NONE)
- return (wpa_driver_wifi_del_key(ifname, key_idx, addr));
+ return (wpa_driver_wifi_del_key(linkid, key_idx, addr));
switch (alg) {
case WPA_ALG_WEP:
@@ -230,36 +230,36 @@ wpa_driver_wifi_set_key(const char *ifname, wpa_alg alg,
}
(void) memcpy(bss.wb_bytes, addr, DLADM_WLAN_BSSID_LEN);
- ret = dladm_wlan_wpa_set_key(ifname, cipher, &bss, set_tx,
+ status = dladm_wlan_wpa_set_key(linkid, cipher, &bss, set_tx,
*(uint64_t *)seq, key_idx, key, key_len);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* disassociate - request driver to disassociate
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @reason_code: 16-bit reason code to be sent in the disassociation
* frame
*
* Return: 0 on success, -1 on failure
*/
static int
-wpa_driver_wifi_disassociate(const char *ifname, int reason_code)
+wpa_driver_wifi_disassociate(datalink_id_t linkid, int reason_code)
{
- int ret;
+ dladm_status_t status;
wpa_printf(MSG_DEBUG, "wpa_driver_wifi_disassociate");
- ret = dladm_wlan_wpa_set_mlme(ifname, DLADM_WLAN_MLME_DISASSOC,
+ status = dladm_wlan_wpa_set_mlme(linkid, DLADM_WLAN_MLME_DISASSOC,
reason_code, NULL);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* associate - request driver to associate
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @bssid: BSSID of the selected AP
* @wpa_ie: WPA information element to be included in (Re)Association
* Request (including information element id and length). Use of
@@ -277,10 +277,10 @@ wpa_driver_wifi_disassociate(const char *ifname, int reason_code)
* Return: 0 on success, -1 on failure
*/
static int
-wpa_driver_wifi_associate(const char *ifname, const char *bssid,
+wpa_driver_wifi_associate(datalink_id_t linkid, const char *bssid,
uint8_t *wpa_ie, uint32_t wpa_ie_len)
{
- int ret;
+ dladm_status_t status;
dladm_wlan_bssid_t bss;
wpa_printf(MSG_DEBUG, "wpa_driver_wifi_associate : "
@@ -291,19 +291,19 @@ wpa_driver_wifi_associate(const char *ifname, const char *bssid,
* this is implied by the bssid which is used to locate
* the scanned node state which holds it.
*/
- if (wpa_driver_wifi_set_wpa_ie(ifname, wpa_ie, wpa_ie_len) < 0)
+ if (wpa_driver_wifi_set_wpa_ie(linkid, wpa_ie, wpa_ie_len) < 0)
return (-1);
(void) memcpy(bss.wb_bytes, bssid, DLADM_WLAN_BSSID_LEN);
- ret = dladm_wlan_wpa_set_mlme(ifname, DLADM_WLAN_MLME_ASSOC,
+ status = dladm_wlan_wpa_set_mlme(linkid, DLADM_WLAN_MLME_ASSOC,
0, &bss);
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* scan - request the driver to initiate scan
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
*
* Return: 0 on success, -1 on failure
*
@@ -312,9 +312,9 @@ wpa_driver_wifi_associate(const char *ifname, const char *bssid,
* results with wpa_driver_get_scan_results().
*/
static int
-wpa_driver_wifi_scan(const char *ifname)
+wpa_driver_wifi_scan(datalink_id_t linkid)
{
- int ret;
+ dladm_status_t status;
wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_scan");
/*
@@ -322,18 +322,18 @@ wpa_driver_wifi_scan(const char *ifname)
* to get ieee80211_begin_scan called. We really want to scan w/o
* altering the current state but that's not possible right now.
*/
- (void) wpa_driver_wifi_disassociate(ifname,
+ (void) wpa_driver_wifi_disassociate(linkid,
DLADM_WLAN_REASON_DISASSOC_LEAVING);
- ret = dladm_wlan_scan(ifname, NULL, NULL);
+ status = dladm_wlan_scan(linkid, NULL, NULL);
wpa_printf(MSG_DEBUG, "%s: return", "wpa_driver_wifi_scan");
- return (WPA_STATUS(ret));
+ return (WPA_STATUS(status));
}
/*
* get_scan_results - fetch the latest scan results
- * @ifname: interface name, e.g., wlan0
+ * @linkid: linkid of the given interface
* @results: pointer to buffer for scan results
* @max_size: maximum number of entries (buffer size)
*
@@ -344,15 +344,15 @@ wpa_driver_wifi_scan(const char *ifname)
* buffer.
*/
int
-wpa_driver_wifi_get_scan_results(const char *ifname,
+wpa_driver_wifi_get_scan_results(datalink_id_t linkid,
dladm_wlan_ess_t *results, uint32_t max_size)
{
uint_t ret;
- wpa_printf(MSG_DEBUG, "%s: interface name =%s max size=%d\n",
- "wpa_driver_wifi_get_scan_results", ifname, max_size);
+ wpa_printf(MSG_DEBUG, "%s: max size=%d\n",
+ "wpa_driver_wifi_get_scan_results", max_size);
- if (dladm_wlan_wpa_get_sr(ifname, results, max_size, &ret)
+ if (dladm_wlan_wpa_get_sr(linkid, results, max_size, &ret)
!= DLADM_STATUS_OK) {
return (-1);
}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c
index 7a7fbed6a8..999e80cfb1 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -760,13 +760,13 @@ wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
uint8_t bssid[IEEE80211_ADDR_LEN];
(void) memset(ssid, 0, MAX_ESSID_LENGTH);
- ssid_len = wpa_s->driver->get_ssid(wpa_s->ifname, (char *)ssid);
+ ssid_len = wpa_s->driver->get_ssid(wpa_s->linkid, (char *)ssid);
if (ssid_len < 0) {
wpa_printf(MSG_WARNING, "Could not read SSID from driver.");
return (NULL);
}
- if (wpa_s->driver->get_bssid(wpa_s->ifname, (char *)bssid) < 0) {
+ if (wpa_s->driver->get_bssid(wpa_s->linkid, (char *)bssid) < 0) {
wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
return (NULL);
}
@@ -814,7 +814,7 @@ wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
- if (wpa_s->driver->get_bssid(wpa_s->ifname, (char *)bssid) < 0) {
+ if (wpa_s->driver->get_bssid(wpa_s->linkid, (char *)bssid) < 0) {
wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
"request");
return;
@@ -838,7 +838,7 @@ wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
reply = (struct wpa_eapol_key *)(hdr + 1);
reply->type = wpa_s->proto == WPA_PROTO_RSN ?
- EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (wpa_s->ptk_set)
key_info |= WPA_KEY_INFO_MIC;
@@ -849,7 +849,7 @@ wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
reply->key_info = BE_16(key_info);
reply->key_length = 0;
(void) memcpy(reply->replay_counter, wpa_s->request_counter,
- WPA_REPLAY_COUNTER_LEN);
+ WPA_REPLAY_COUNTER_LEN);
inc_byte_array(wpa_s->request_counter, WPA_REPLAY_COUNTER_LEN);
reply->key_data_length = BE_16(0);
@@ -908,10 +908,10 @@ wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
break;
}
if (pos[0] == GENERIC_INFO_ELEM &&
- pos + 1 + RSN_SELECTOR_LEN < end &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- memcmp(pos + 2, RSN_KEY_DATA_PMKID,
- RSN_SELECTOR_LEN) == 0) {
+ pos + 1 + RSN_SELECTOR_LEN < end &&
+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ memcmp(pos + 2, RSN_KEY_DATA_PMKID,
+ RSN_SELECTOR_LEN) == 0) {
pmkid = pos + 2 + RSN_SELECTOR_LEN;
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", pmkid, PMKID_LEN);
@@ -949,12 +949,11 @@ wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
reply = (struct wpa_eapol_key *)(hdr + 1);
reply->type = wpa_s->proto == WPA_PROTO_RSN ?
- EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE |
- WPA_KEY_INFO_MIC);
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
reply->key_length = key->key_length;
(void) memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ WPA_REPLAY_COUNTER_LEN);
reply->key_data_length = BE_16(wpa_ie_len);
(void) memcpy(reply + 1, wpa_ie, wpa_ie_len);
@@ -986,7 +985,7 @@ wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
(void) memcpy(ptk->u.auth.rx_mic_key, buf, 8);
wpa_s->tptk_set = 1;
wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, (uint8_t *)hdr,
- rlen - sizeof (*ethhdr), reply->key_mic);
+ rlen - sizeof (*ethhdr), reply->key_mic);
wpa_hexdump(MSG_DEBUG, "WPA: EAPOL-Key MIC", reply->key_mic, 16);
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
@@ -1080,23 +1079,21 @@ wpa_supplicant_process_3_of_4_gtk(struct wpa_supplicant *wpa_s,
(void) memcpy(gtk + 24, tmpbuf, 8);
}
if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
- if (wpa_s->driver->set_key(wpa_s->ifname, alg,
+ if (wpa_s->driver->set_key(wpa_s->linkid, alg,
(uint8_t *)"\xff\xff\xff\xff\xff\xff",
keyidx, 1, key->key_rsc,
key_rsc_len, gtk, gtk_len) < 0)
wpa_printf(MSG_WARNING, "WPA: Failed to set "
"GTK to the driver (Group only).");
- } else if (wpa_s->driver->set_key(wpa_s->ifname, alg,
- (uint8_t *)"\xff\xff\xff\xff\xff\xff",
- keyidx, tx,
- key->key_rsc, key_rsc_len,
- gtk, gtk_len) < 0) {
+ } else if (wpa_s->driver->set_key(wpa_s->linkid, alg,
+ (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, tx,
+ key->key_rsc, key_rsc_len, gtk, gtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
"the driver.");
}
wpa_printf(MSG_INFO, "WPA: Key negotiation completed with "
- MACSTR, MAC2STR(src_addr));
+ MACSTR, MAC2STR(src_addr));
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_s->wpa_state = WPA_COMPLETED;
@@ -1136,10 +1133,10 @@ wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
ie = pos;
ie_len = pos[1] + 2;
} else if (pos[0] == GENERIC_INFO_ELEM &&
- pos + 1 + RSN_SELECTOR_LEN < end &&
- pos[1] > RSN_SELECTOR_LEN + 2 &&
- memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
- RSN_SELECTOR_LEN) == 0) {
+ pos + 1 + RSN_SELECTOR_LEN < end &&
+ pos[1] > RSN_SELECTOR_LEN + 2 &&
+ memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
+ RSN_SELECTOR_LEN) == 0) {
if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_printf(MSG_WARNING, "WPA: GTK IE "
"in unencrypted key data");
@@ -1165,7 +1162,7 @@ wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
if (wpa_s->ap_wpa_ie &&
(wpa_s->ap_wpa_ie_len != ie_len ||
- memcmp(wpa_s->ap_wpa_ie, ie, ie_len) != 0)) {
+ memcmp(wpa_s->ap_wpa_ie, ie, ie_len) != 0)) {
wpa_printf(MSG_WARNING, "WPA: WPA IE in 3/4 msg does not match"
" with WPA IE in Beacon/ProbeResp (src=" MACSTR ")",
MAC2STR(src_addr));
@@ -1222,13 +1219,12 @@ wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
reply = (struct wpa_eapol_key *)(hdr + 1);
reply->type = wpa_s->proto == WPA_PROTO_RSN ?
- EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE |
- WPA_KEY_INFO_MIC |
- (key_info & WPA_KEY_INFO_SECURE));
+ WPA_KEY_INFO_MIC | (key_info & WPA_KEY_INFO_SECURE));
reply->key_length = key->key_length;
(void) memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ WPA_REPLAY_COUNTER_LEN);
reply->key_data_length = BE_16(0);
@@ -1279,7 +1275,7 @@ wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_s->driver->set_key(wpa_s->ifname, alg, src_addr,
+ if (wpa_s->driver->set_key(wpa_s->linkid, alg, src_addr,
0, 1, key_rsc, rsclen,
(uint8_t *)&wpa_s->ptk.tk1, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the"
@@ -1342,9 +1338,9 @@ wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
gtk_ie = pos + 2 + RSN_SELECTOR_LEN;
gtk_ie_len = pos[1] - RSN_SELECTOR_LEN;
break;
- } else if (pos[0] == GENERIC_INFO_ELEM &&
- pos[1] == 0)
+ } else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0) {
break;
+ }
pos += 2 + pos[1];
}
@@ -1423,7 +1419,7 @@ wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
(void) memcpy(gtk, gtk_ie + 2, gtk_ie_len - 2);
} else {
keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
- WPA_KEY_INFO_KEY_INDEX_SHIFT;
+ WPA_KEY_INFO_KEY_INDEX_SHIFT;
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
(void) memcpy(ek, key->key_iv, 16);
(void) memcpy(ek + 16, wpa_s->ptk.encr_key, 16);
@@ -1436,7 +1432,7 @@ wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
return;
}
if (aes_unwrap(wpa_s->ptk.encr_key, maxkeylen / 8,
- (uint8_t *)(key + 1), gtk)) {
+ (uint8_t *)(key + 1), gtk)) {
wpa_printf(MSG_WARNING, "WPA: AES unwrap "
"failed - could not decrypt GTK");
return;
@@ -1470,13 +1466,13 @@ wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
(void) memcpy(gtk + 24, tmpbuf, 8);
}
if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
- if (wpa_s->driver->set_key(wpa_s->ifname, alg,
+ if (wpa_s->driver->set_key(wpa_s->linkid, alg,
(uint8_t *)"\xff\xff\xff\xff\xff\xff",
keyidx, 1, key->key_rsc,
key_rsc_len, gtk, keylen) < 0)
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the"
" driver (Group only).");
- } else if (wpa_s->driver->set_key(wpa_s->ifname, alg,
+ } else if (wpa_s->driver->set_key(wpa_s->linkid, alg,
(uint8_t *)"\xff\xff\xff\xff\xff\xff",
keyidx, tx,
key->key_rsc, key_rsc_len,
@@ -1730,9 +1726,10 @@ wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
}
if ((key_info & WPA_KEY_INFO_MIC) &&
- wpa_supplicant_verify_eapol_key_mic(wpa_s, key, ver, buf,
- data_len))
+ wpa_supplicant_verify_eapol_key_mic(wpa_s, key, ver, buf,
+ data_len)) {
return;
+ }
extra_len = data_len - sizeof (*hdr) - sizeof (*key);
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h
index e5e6f8f808..7745ec1c7f 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -14,6 +14,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <net/wpa.h>
+#include <libdladm.h>
#ifdef __cplusplus
extern "C" {
@@ -164,7 +165,7 @@ struct wpa_supplicant {
struct l2_packet_data *l2;
unsigned char own_addr[IEEE80211_ADDR_LEN];
- char ifname[WPA_STRSIZE];
+ datalink_id_t linkid;
char kname[WPA_STRSIZE];
uint8_t pmk[PMK_LEN];
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c
index 270b9133ed..06663383f7 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -141,7 +141,7 @@ wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid);
}
- if (wpa_s->driver->scan(wpa_s->ifname)) {
+ if (wpa_s->driver->scan(wpa_s->linkid)) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
}
}
@@ -213,16 +213,16 @@ wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
static void
wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr)
{
- wpa_s->driver->set_key(wpa_s->ifname, WPA_ALG_NONE,
+ wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
(uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0);
- wpa_s->driver->set_key(wpa_s->ifname, WPA_ALG_NONE,
+ wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
(uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0);
- wpa_s->driver->set_key(wpa_s->ifname, WPA_ALG_NONE,
+ wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
(uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0);
- wpa_s->driver->set_key(wpa_s->ifname, WPA_ALG_NONE,
+ wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
(uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0);
if (addr) {
- wpa_s->driver->set_key(wpa_s->ifname, WPA_ALG_NONE, addr,
+ wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, addr,
0, 0, NULL, 0, NULL, 0);
}
}
@@ -357,7 +357,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes);
wpa_s->wpa_state = WPA_ASSOCIATING;
- wpa_s->driver->associate(wpa_s->ifname,
+ wpa_s->driver->associate(wpa_s->linkid,
(const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len);
/* Timeout for IEEE 802.11 authentication and association */
@@ -371,7 +371,7 @@ wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code)
wpa_s->wpa_state = WPA_DISCONNECTED;
if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00",
IEEE80211_ADDR_LEN) != 0) {
- wpa_s->driver->disassociate(wpa_s->ifname, reason_code);
+ wpa_s->driver->disassociate(wpa_s->linkid, reason_code);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
@@ -453,7 +453,7 @@ wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
struct wpa_ssid *ssid;
(void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS);
- num = wpa_s->driver->get_scan_results(wpa_s->ifname, results,
+ num = wpa_s->driver->get_scan_results(wpa_s->linkid, results,
MAX_SCANRESULTS);
wpa_printf(MSG_DEBUG, "Scan results: %d", num);
if (num < 0)
@@ -506,7 +506,7 @@ wpa_event_handler(void *cookie, wpa_event_type event)
WPA_REPLAY_COUNTER_LEN);
wpa_s->rx_replay_counter_set = 0;
wpa_s->renew_snonce = 1;
- if (wpa_s->driver->get_bssid(wpa_s->ifname,
+ if (wpa_s->driver->get_bssid(wpa_s->linkid,
(char *)bssid) >= 0 &&
memcmp(bssid, wpa_s->bssid, IEEE80211_ADDR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "Associated to a new BSS: "
@@ -550,9 +550,9 @@ wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx)
}
static int
-wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s)
{
- wpa_s->l2 = l2_packet_init(wpa_s->ifname, ETHERTYPE_EAPOL,
+ wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL,
wpa_supplicant_rx_eapol, wpa_s);
if (wpa_s->l2 == NULL)
return (-1);
@@ -562,7 +562,7 @@ wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
return (-1);
}
- if (wpa_s->driver->set_wpa(wpa_s->ifname, 1) < 0) {
+ if (wpa_s->driver->set_wpa(wpa_s->linkid, 1) < 0) {
wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver.");
return (-1);
}
@@ -641,6 +641,9 @@ wpa_supplicant_door_destroy(char *doorname)
{
wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
+ if (door_id == -1)
+ return;
+
if (door_revoke(door_id) == -1) {
wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
door_id, strerror(errno));
@@ -701,13 +704,13 @@ wpa_config_read_network(struct wpa_supplicant *wpa_s)
ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
(void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
- wpa_s->driver->get_ssid(wpa_s->ifname, (char *)buf);
+ wpa_s->driver->get_ssid(wpa_s->linkid, (char *)buf);
(void) wpa_config_parse_ssid(ssid, 0, buf);
key_len = sizeof (psk);
(void) dladm_get_secobj((const char *)wpa_s->kname, &cl, psk, &key_len,
- DLADM_OPT_TEMP);
+ DLADM_OPT_ACTIVE);
psk[key_len] = '\0';
ssid->passphrase = strdup((const char *)psk);
@@ -760,9 +763,11 @@ wpa_config_free(struct wpa_config *config)
{
struct wpa_ssid *ssid = config->ssid;
- free(ssid->ssid);
- free(ssid->passphrase);
- free(ssid);
+ if (ssid != NULL) {
+ free(ssid->ssid);
+ free(ssid->passphrase);
+ free(ssid);
+ }
free(config);
}
@@ -798,13 +803,12 @@ static void
usage(void)
{
(void) printf("%s\n\n"
- "usage:\n"
- " wpa_supplicant [-hv] -i<ifname> -k<keyname>"
- "\n"
- "options:\n"
- " -h = show this help text\n"
- " -v = show version\n",
- wpa_supplicant_version);
+ "usage:\n"
+ " wpa_supplicant [-hv] -i<ifname> -k<keyname>\n"
+ "options:\n"
+ " -h = show this help text\n"
+ " -v = show version\n",
+ wpa_supplicant_version);
}
int
@@ -813,12 +817,13 @@ main(int argc, char *argv[])
struct wpa_supplicant wpa_s;
char *link = NULL;
char *key = NULL;
+ dlpi_handle_t dh = NULL;
+ datalink_id_t linkid;
+ dladm_phys_attr_t dpa;
int c;
int exitcode;
char door_file[WPA_STRSIZE];
- (void) memset(&wpa_s, 0, sizeof (wpa_s));
-
for (;;) {
c = getopt(argc, argv, "Dk:hi:v");
if (c < 0)
@@ -845,8 +850,6 @@ main(int argc, char *argv[])
}
}
- wpa_s.driver = &wpa_driver_wifi_ops;
- eloop_init(&wpa_s);
/*
* key name is required to retrieve PSK value through libwdladm APIs.
* key is saved by dladm command by keyname
@@ -857,22 +860,48 @@ main(int argc, char *argv[])
return (-1);
}
- if ((strlen(link) >= sizeof (wpa_s.ifname)) ||
- (strlen(key) >= sizeof (wpa_s.kname))) {
- wpa_printf(MSG_ERROR, "Too long link/key name '%s', '%s'.",
- link, key);
+ if ((strlen(key) >= sizeof (wpa_s.kname))) {
+ wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
return (-1);
}
- (void) strlcpy(wpa_s.ifname, link, sizeof (wpa_s.ifname));
- (void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
+ if (daemon(0, 0))
+ return (-1);
/*
- * Setup door file to communicate with driver
- * Since this is multiple instance service, different instance
- * has different doors.
+ * Hold this link open to prevent a link renaming operation.
*/
- (void) snprintf(door_file, WPA_STRSIZE, "%s_%s", WPA_DOOR, link);
+ if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
+ return (-1);
+ }
+
+ if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
+ DLADM_STATUS_OK) {
+ wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
+ dlpi_close(dh);
+ return (-1);
+ }
+
+ /*
+ * Get the device name of the link, which will be used as the door
+ * file name used to communicate with the driver. Note that different
+ * links use different doors.
+ */
+ if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
+ DLADM_STATUS_OK) {
+ wpa_printf(MSG_ERROR,
+ "Failed to get device name of link '%s'.", link);
+ dlpi_close(dh);
+ return (-1);
+ }
+ (void) snprintf(door_file, WPA_STRSIZE, "%s_%s", WPA_DOOR, dpa.dp_dev);
+
+ (void) memset(&wpa_s, 0, sizeof (wpa_s));
+ wpa_s.driver = &wpa_driver_wifi_ops;
+ wpa_s.linkid = linkid;
+ (void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
+ eloop_init(&wpa_s);
/*
* Setup default WPA/WPA2 configuration
@@ -881,16 +910,15 @@ main(int argc, char *argv[])
wpa_s.conf = wpa_config_read(&wpa_s);
if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
- return (-1);
- }
-
- exitcode = 0;
-
- if (daemon(0, 0)) {
exitcode = -1;
goto cleanup;
}
+ exitcode = 0;
+
+ /*
+ * Setup door file to communicate with driver
+ */
if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
exitcode = -1;
@@ -898,11 +926,18 @@ main(int argc, char *argv[])
}
wpa_s.renew_snonce = 1;
- if (wpa_supplicant_driver_init(&wpa_s) < 0) {
+ if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
exitcode = -1;
goto cleanup;
}
+ /*
+ * This link is hold again in wpa_supplicant_driver_init(), so that
+ * we release the first reference.
+ */
+ dlpi_close(dh);
+ dh = NULL;
+
wpa_printf(MSG_DEBUG, "=> eloop_run");
(void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
@@ -914,14 +949,17 @@ main(int argc, char *argv[])
wpa_printf(MSG_DEBUG, "<= eloop_run()");
wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
-cleanup:
- if (wpa_s.driver->set_wpa(wpa_s.ifname, 0) < 0) {
+ if (wpa_s.driver->set_wpa(wpa_s.linkid, 0) < 0) {
wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
}
+cleanup:
wpa_supplicant_door_destroy(door_file);
wpa_supplicant_cleanup(&wpa_s);
eloop_destroy();
+ if (dh != NULL)
+ dlpi_close(dh);
+
return (exitcode);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
index 3011207150..4924d2fe4e 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -39,7 +39,7 @@ COMMONSRCS= $(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c)
SRCS= $(LOCALSRCS) $(COMMONSRCS)
CPPFLAGS += -I$(CMDINETCOMMONDIR) -I$(SRC)/common/net/dhcp
-LDLIBS += -ldevinfo -ldhcpagent -linetcfg -ldlpi
+LDLIBS += -ldhcpagent -linetcfg -ldlpi
LINTFLAGS += -m
ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%)
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/defs.h b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/defs.h
index c40dac4648..c993baeb02 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/defs.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -17,6 +17,7 @@
extern "C" {
#endif
+#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -24,7 +25,6 @@ extern "C" {
#include <ctype.h>
#include <string.h>
#include <syslog.h>
-#include <libdevinfo.h>
#include <zone.h>
#include <sys/types.h>
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
index ed8ab462f5..877d275947 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -164,7 +164,7 @@ static void in6_configinfo(int force, uint64_t flags);
/*
* Misc support functions
*/
-static int devfs_entry(di_node_t node, di_minor_t minor, void *arg);
+static boolean_t ni_entry(const char *, void *);
static void foreachinterface(void (*func)(), int argc, char *argv[],
int af, int64_t onflags, int64_t offflags,
int64_t lifc_flags);
@@ -490,7 +490,7 @@ foreachinterface(void (*func)(), int argc, char *argv[], int af,
/*
* Special case:
* ifconfig -a plumb should find all network interfaces
- * in the machine by traversing the devinfo tree for global zone.
+ * in the machine for the global zone.
* For non-global zones, only find the assigned interfaces.
* Also, there is no need to SIOCGLIF* ioctls, since
* those interfaces have already been plumbed
@@ -1755,8 +1755,7 @@ updownifs(iface_t *ifs, int up)
* static int find_all_global_interfaces(struct lifconf *lifcp, char **buf,
* int64_t lifc_flags)
*
- * It finds all interfaces for the global zone, that is all
- * the physical interfaces, using the kernel's devinfo tree.
+ * It finds all data links for the global zone.
*
* It takes in input a pointer to struct lifconf to receive interfaces
* informations, a **char to hold allocated buffer, and a lifc_flags.
@@ -1771,23 +1770,10 @@ find_all_global_interfaces(struct lifconf *lifcp, char **buf,
{
unsigned bufsize;
int n;
- di_node_t root;
ni_t *nip;
struct lifreq *lifrp;
- /*
- * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR |
- * DINFOPROP | DINFOFORCE.
- */
- if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
- (void) fprintf(stderr, "ifconfig: di_init "
- "failed; check the devinfo driver.\n");
- exit(1);
- }
-
- (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS,
- NULL, devfs_entry);
- di_fini(root);
+ (void) dlpi_walk(ni_entry, NULL, 0);
/*
* Now, translate the linked list into
@@ -4516,7 +4502,7 @@ strioctl(int s, int cmd, char *buf, int buflen)
}
static void
-add_ni(char *name)
+add_ni(const char *name)
{
ni_t **pp;
ni_t *p;
@@ -4545,35 +4531,18 @@ add_ni(char *name)
}
/* ARGSUSED2 */
-static int
-devfs_entry(di_node_t node, di_minor_t minor, void *arg)
+static boolean_t
+ni_entry(const char *linkname, void *arg)
{
- char *provider;
- char linkname[DLPI_LINKNAME_MAX];
dlpi_handle_t dh;
- provider = di_minor_name(minor);
- if (debug > 2)
- (void) fprintf(stderr, "provider = %s\n", provider);
-
- if (dlpi_makelink(linkname, provider,
- di_instance(node)) != DLPI_SUCCESS)
- return (DI_WALK_CONTINUE);
-
if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS)
- return (DI_WALK_CONTINUE);
+ return (_B_FALSE);
- if (di_minor_type(minor) == DDM_ALIAS) {
- if (debug > 2)
- (void) fprintf(stderr, "alias node, using instance\n");
- add_ni(linkname);
- } else {
- if (debug > 2)
- (void) fprintf(stderr, "non-alias node, ignoring\n");
- }
+ add_ni(linkname);
dlpi_close(dh);
- return (DI_WALK_CONTINUE);
+ return (_B_FALSE);
}
/*
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c
index 2913f44669..455b4102a4 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983, 1993
@@ -1902,7 +1902,12 @@ get_if_kstats(struct interface *ifp, struct phyi_data *newdata)
if ((kc = kstat_open()) == NULL)
return (-1);
- if ((ksp = kstat_lookup(kc, NULL, -1, phyi->phyi_name)) == NULL) {
+ /*
+ * First we try to query the "link" kstats in case the link is renamed.
+ * If that fails, fallback to legacy ktats for those non-GLDv3 links.
+ */
+ if (((ksp = kstat_lookup(kc, "link", 0, phyi->phyi_name)) == NULL) &&
+ ((ksp = kstat_lookup(kc, NULL, -1, phyi->phyi_name)) == NULL)) {
(void) kstat_close(kc);
return (-1);
}
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c
index a5bfeb5fbf..e2dfed2871 100644
--- a/usr/src/cmd/devfsadm/devfsadm.c
+++ b/usr/src/cmd/devfsadm/devfsadm.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -7822,7 +7822,7 @@ process_rcm_events(void *arg)
static int
rcm_init(void)
{
-#define LIBRCM_PATH "/usr/lib/librcm.so"
+#define LIBRCM_PATH "/lib/librcm.so"
rcm_handle_t *hdl = NULL;
int err;
diff --git a/usr/src/cmd/dladm/Makefile b/usr/src/cmd/dladm/Makefile
index 881a839ebb..94e6842ff3 100644
--- a/usr/src/cmd/dladm/Makefile
+++ b/usr/src/cmd/dladm/Makefile
@@ -19,14 +19,14 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
#
PROG= dladm
-CFGFILES= aggregation.conf linkprop.conf secobj.conf
+CFGFILES= secobj.conf
ROOTFS_PROG= $(PROG)
ROOTCFGDIR= $(ROOTETC)/dladm
@@ -35,12 +35,11 @@ ROOTCFGFILES= $(CFGFILES:%=$(ROOTCFGDIR)/%)
include ../Makefile.cmd
XGETFLAGS += -a -x $(PROG).xcl
-LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -linetutil
+LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -linetutil -ldevinfo
$(ROOTCFGFILES) := OWNER= dladm
$(ROOTCFGFILES) := GROUP= sys
-$(ROOTCFGDIR)/aggregation.conf $(ROOTCFGDIR)/linkprop.conf := FILEMODE= 644
$(ROOTCFGDIR)/secobj.conf := FILEMODE= 600
.KEEP_STATE:
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c
index 17a3d53e6a..22cc5c515e 100644
--- a/usr/src/cmd/dladm/dladm.c
+++ b/usr/src/cmd/dladm/dladm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,6 +34,7 @@
#include <fcntl.h>
#include <string.h>
#include <stropts.h>
+#include <sys/stat.h>
#include <errno.h>
#include <kstat.h>
#include <strings.h>
@@ -45,18 +46,24 @@
#include <auth_attr.h>
#include <auth_list.h>
#include <libintl.h>
+#include <libdevinfo.h>
#include <libdlpi.h>
#include <libdllink.h>
#include <libdlaggr.h>
#include <libdlwlan.h>
+#include <libdlvlan.h>
+#include <libdlvnic.h>
#include <libinetutil.h>
#include <bsm/adt.h>
#include <bsm/adt_event.h>
-#define AGGR_DRV "aggr"
-#define MAXPORT 256
-#define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \
- "%-5s %-4s %-4s %-9s %-7s\n"
+#define AGGR_DRV "aggr"
+#define MAXPORT 256
+#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
+#define MAXLINELEN 1024
+#define SMF_UPGRADE_FILE "/var/svc/profile/upgrade"
+#define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink"
+#define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)"
typedef struct pktsum_s {
uint64_t ipackets;
@@ -67,54 +74,56 @@ typedef struct pktsum_s {
uint32_t oerrors;
} pktsum_t;
-typedef struct show_link_state {
+typedef struct show_state {
boolean_t ls_firstonly;
boolean_t ls_donefirst;
- boolean_t ls_stats;
pktsum_t ls_prevstats;
boolean_t ls_parseable;
-} show_link_state_t;
+ uint32_t ls_flags;
+ dladm_status_t ls_status;
+} show_state_t;
typedef struct show_grp_state {
- uint32_t gs_key;
boolean_t gs_lacp;
- boolean_t gs_found;
+ boolean_t gs_extended;
boolean_t gs_stats;
boolean_t gs_firstonly;
+ boolean_t gs_donefirst;
pktsum_t gs_prevstats[MAXPORT];
boolean_t gs_parseable;
+ uint32_t gs_flags;
+ dladm_status_t gs_status;
} show_grp_state_t;
-typedef struct show_mac_state {
- boolean_t ms_firstonly;
- boolean_t ms_donefirst;
- pktsum_t ms_prevstats;
- boolean_t ms_parseable;
-} show_mac_state_t;
-
-typedef void cmdfunc_t(int, char **);
+typedef void cmdfunc_t(int, char **);
-static cmdfunc_t do_show_link, do_show_dev, do_show_wifi;
+static cmdfunc_t do_show_link, do_show_dev, do_show_wifi, do_show_phys;
static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
-static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr;
+static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
static cmdfunc_t do_init_linkprop, do_init_secobj;
+static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
+static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
+static cmdfunc_t do_show_linkmap;
-static void show_linkprop_onelink(void *, const char *);
+static void altroot_cmd(char *, int, char **);
+static int show_linkprop_onelink(datalink_id_t, void *);
-static void link_stats(const char *, uint_t);
-static void aggr_stats(uint32_t, uint_t);
+static void link_stats(datalink_id_t, uint_t);
+static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
static void dev_stats(const char *dev, uint32_t);
+static int get_one_kstat(const char *, const char *, uint8_t,
+ void *, boolean_t);
static void get_mac_stats(const char *, pktsum_t *);
static void get_link_stats(const char *, pktsum_t *);
-static uint64_t mac_ifspeed(const char *);
+static uint64_t get_ifspeed(const char *, boolean_t);
static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
-static const char *mac_link_state(const char *, char *);
-static const char *mac_link_duplex(const char *, char *);
+static const char *get_linkstate(const char *, boolean_t, char *);
+static const char *get_linkduplex(const char *, boolean_t, char *);
static boolean_t str2int(const char *, int *);
static void die(const char *, ...);
@@ -139,7 +148,6 @@ static cmd_t cmds[] = {
{ "modify-aggr", do_modify_aggr },
{ "show-aggr", do_show_aggr },
{ "up-aggr", do_up_aggr },
- { "down-aggr", do_down_aggr },
{ "scan-wifi", do_scan_wifi },
{ "connect-wifi", do_connect_wifi },
{ "disconnect-wifi", do_disconnect_wifi },
@@ -151,50 +159,67 @@ static cmd_t cmds[] = {
{ "delete-secobj", do_delete_secobj },
{ "show-secobj", do_show_secobj },
{ "init-linkprop", do_init_linkprop },
- { "init-secobj", do_init_secobj }
+ { "init-secobj", do_init_secobj },
+ { "create-vlan", do_create_vlan },
+ { "delete-vlan", do_delete_vlan },
+ { "show-vlan", do_show_vlan },
+ { "up-vlan", do_up_vlan },
+ { "rename-link", do_rename_link },
+ { "delete-phys", do_delete_phys },
+ { "show-phys", do_show_phys },
+ { "init-phys", do_init_phys },
+ { "show-linkmap", do_show_linkmap }
+};
+
+static const struct option lopts[] = {
+ {"vlan-id", required_argument, 0, 'v'},
+ {"dev", required_argument, 0, 'd'},
+ {"policy", required_argument, 0, 'P'},
+ {"lacp-mode", required_argument, 0, 'L'},
+ {"lacp-timer", required_argument, 0, 'T'},
+ {"unicast", required_argument, 0, 'u'},
+ {"temporary", no_argument, 0, 't'},
+ {"root-dir", required_argument, 0, 'R'},
+ {"link", required_argument, 0, 'l'},
+ {"forcible", no_argument, 0, 'f'},
+ { 0, 0, 0, 0 }
};
-static const struct option longopts[] = {
- {"vlan-id", required_argument, 0, 'v' },
- {"dev", required_argument, 0, 'd' },
- {"policy", required_argument, 0, 'P' },
- {"lacp-mode", required_argument, 0, 'l' },
- {"lacp-timer", required_argument, 0, 'T' },
- {"unicast", required_argument, 0, 'u' },
- {"statistics", no_argument, 0, 's' },
- {"interval", required_argument, 0, 'i' },
- {"lacp", no_argument, 0, 'L' },
- {"temporary", no_argument, 0, 't' },
- {"root-dir", required_argument, 0, 'r' },
- {"parseable", no_argument, 0, 'p' },
+static const struct option show_lopts[] = {
+ {"statistics", no_argument, 0, 's'},
+ {"interval", required_argument, 0, 'i'},
+ {"parseable", no_argument, 0, 'p'},
+ {"extended", no_argument, 0, 'x'},
+ {"persistent", no_argument, 0, 'P'},
+ {"lacp", no_argument, 0, 'L'},
{ 0, 0, 0, 0 }
};
static const struct option prop_longopts[] = {
- {"temporary", no_argument, 0, 't' },
- {"root-dir", required_argument, 0, 'R' },
- {"prop", required_argument, 0, 'p' },
- {"parseable", no_argument, 0, 'c' },
- {"persistent", no_argument, 0, 'P' },
+ {"temporary", no_argument, 0, 't' },
+ {"root-dir", required_argument, 0, 'R' },
+ {"prop", required_argument, 0, 'p' },
+ {"parseable", no_argument, 0, 'c' },
+ {"persistent", no_argument, 0, 'P' },
{ 0, 0, 0, 0 }
};
static const struct option wifi_longopts[] = {
- {"parseable", no_argument, 0, 'p' },
- {"output", required_argument, 0, 'o' },
- {"essid", required_argument, 0, 'e' },
- {"bsstype", required_argument, 0, 'b' },
- {"mode", required_argument, 0, 'm' },
- {"key", required_argument, 0, 'k' },
- {"sec", required_argument, 0, 's' },
- {"auth", required_argument, 0, 'a' },
- {"create-ibss", required_argument, 0, 'c' },
- {"timeout", required_argument, 0, 'T' },
- {"all-links", no_argument, 0, 'a' },
- {"temporary", no_argument, 0, 't' },
- {"root-dir", required_argument, 0, 'R' },
- {"persistent", no_argument, 0, 'P' },
- {"file", required_argument, 0, 'f' },
+ {"parseable", no_argument, 0, 'p' },
+ {"output", required_argument, 0, 'o' },
+ {"essid", required_argument, 0, 'e' },
+ {"bsstype", required_argument, 0, 'b' },
+ {"mode", required_argument, 0, 'm' },
+ {"key", required_argument, 0, 'k' },
+ {"sec", required_argument, 0, 's' },
+ {"auth", required_argument, 0, 'a' },
+ {"create-ibss", required_argument, 0, 'c' },
+ {"timeout", required_argument, 0, 'T' },
+ {"all-links", no_argument, 0, 'a' },
+ {"temporary", no_argument, 0, 't' },
+ {"root-dir", required_argument, 0, 'R' },
+ {"persistent", no_argument, 0, 'P' },
+ {"file", required_argument, 0, 'f' },
{ 0, 0, 0, 0 }
};
@@ -205,25 +230,33 @@ static void
usage(void)
{
(void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n"
- "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n"
- "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n"
+ "\tshow-link [-pP] [-s [-i <interval>]] [<link>]\n"
+ "\trename-link [-R <root-dir>] <oldlink> <newlink>\n"
+ "\n"
+ "\tdelete-phys <link>\n"
+ "\tshow-phys [-pP] [<link>]\n"
+ "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n"
"\n"
- "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
- "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n"
- "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n"
- "\t [-T <time>] [-u <address>] <key>\n"
- "\tdelete-aggr [-t] [-R <root-dir>] <key>\n"
- "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n"
- "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n"
- "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n"
+ "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
+ "\t [-T <time>] [-u <address>] [-l <link>] ... <link>\n"
+ "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n"
+ "\t [-T <time>] [-u <address>] <link>\n"
+ "\tdelete-aggr [-t] [-R <root-dir>] <link>\n"
+ "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n"
+ "\tremove-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>"
+ "\n\tshow-aggr [-pPLx][-s [-i <interval>]] [<link>]\n"
"\n"
- "\tscan-wifi [-p] [-o <field>,...] [<name>]\n"
+ "\tcreate-vlan [-ft] [-R <root-dir>] -l <link> -v <vid> [link]"
+ "\n\tdelete-vlan [-t] [-R <root-dir>] <link>\n"
+ "\tshow-vlan [-pP] [<link>]\n"
+ "\n"
+ "\tscan-wifi [-p] [-o <field>,...] [<link>]\n"
"\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]"
" [-s wep|wpa]\n"
"\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n"
- "\t [-T <time>] [<name>]\n"
- "\tdisconnect-wifi [-a] [<name>]\n"
- "\tshow-wifi [-p] [-o <field>,...] [<name>]\n"
+ "\t [-T <time>] [<link>]\n"
+ "\tdisconnect-wifi [-a] [<link>]\n"
+ "\tshow-wifi [-p] [-o <field>,...] [<link>]\n"
"\n"
"\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]"
" <name>\n"
@@ -276,36 +309,35 @@ main(int argc, char *argv[])
static void
do_create_aggr(int argc, char *argv[])
{
- char option;
- int key;
- uint32_t policy = AGGR_POLICY_L4;
- aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF;
- aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT;
+ char option;
+ int key = 0;
+ uint32_t policy = AGGR_POLICY_L4;
+ aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF;
+ aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT;
dladm_aggr_port_attr_db_t port[MAXPORT];
- uint_t nport = 0;
- uint8_t mac_addr[ETHERADDRL];
- boolean_t mac_addr_fixed = B_FALSE;
- boolean_t P_arg = B_FALSE;
- boolean_t l_arg = B_FALSE;
- boolean_t t_arg = B_FALSE;
- boolean_t u_arg = B_FALSE;
- boolean_t T_arg = B_FALSE;
- char *altroot = NULL;
- dladm_status_t status;
+ uint_t n, ndev, nlink;
+ uint8_t mac_addr[ETHERADDRL];
+ boolean_t mac_addr_fixed = B_FALSE;
+ boolean_t P_arg = B_FALSE;
+ boolean_t l_arg = B_FALSE;
+ boolean_t u_arg = B_FALSE;
+ boolean_t T_arg = B_FALSE;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ char *altroot = NULL;
+ char name[MAXLINKNAMELEN];
+ char *devs[MAXPORT];
+ char *links[MAXPORT];
+ dladm_status_t status;
- opterr = 0;
- while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:",
- longopts, NULL)) != -1) {
+ ndev = nlink = opterr = 0;
+ while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:",
+ lopts, NULL)) != -1) {
switch (option) {
case 'd':
- if (nport >= MAXPORT)
- die("too many <dev> arguments");
-
- if (strlcpy(port[nport].lp_devname, optarg,
- MAXNAMELEN) >= MAXNAMELEN)
- die("device name too long");
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
- nport++;
+ devs[ndev++] = optarg;
break;
case 'P':
if (P_arg)
@@ -325,6 +357,19 @@ do_create_aggr(int argc, char *argv[])
die("invalid MAC address '%s'", optarg);
break;
case 'l':
+ if (isdigit(optarg[strlen(optarg) - 1])) {
+
+ /*
+ * Ended with digit, possibly a link name.
+ */
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
+
+ links[nlink++] = optarg;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'L':
if (l_arg)
die_optdup(option);
@@ -341,7 +386,10 @@ do_create_aggr(int argc, char *argv[])
die("invalid LACP timer value '%s'", optarg);
break;
case 't':
- t_arg = B_TRUE;
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'f':
+ flags |= DLADM_OPT_FORCE;
break;
case 'R':
altroot = optarg;
@@ -352,37 +400,100 @@ do_create_aggr(int argc, char *argv[])
}
}
- if (nport == 0)
+ if (ndev + nlink == 0)
usage();
- /* get key value (required last argument) */
+ /* get key value or the aggregation name (required last argument) */
if (optind != (argc-1))
usage();
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ if (!str2int(argv[optind], &key)) {
+ if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
+ MAXLINKNAMELEN) {
+ die("link name too long '%s'", argv[optind]);
+ }
- status = dladm_aggr_create(key, nport, port, policy, mac_addr_fixed,
- mac_addr, lacp_mode, lacp_timer, t_arg, altroot);
- if (status != DLADM_STATUS_OK)
- die_dlerr(status, "create operation failed");
+ if (!dladm_valid_linkname(name))
+ die("invalid link name '%s'", argv[optind]);
+ } else {
+ (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
+ }
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ for (n = 0; n < ndev; n++) {
+ if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) !=
+ DLADM_STATUS_OK) {
+ die("invalid dev name '%s'", devs[n]);
+ }
+ }
+
+ for (n = 0; n < nlink; n++) {
+ if (dladm_name2info(links[n], &port[ndev + n].lp_linkid,
+ NULL, NULL, NULL) != DLADM_STATUS_OK) {
+ die("invalid link name '%s'", links[n]);
+ }
+ }
+
+ status = dladm_aggr_create(name, key, ndev + nlink, port, policy,
+ mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
+ lacp_timer, flags);
+done:
+ if (status != DLADM_STATUS_OK) {
+ if (status == DLADM_STATUS_NONOTIF) {
+ die_dlerr(status, "not all links have link up/down "
+ "detection; must use -f (see dladm(1M))\n");
+ } else {
+ die_dlerr(status, "create operation failed");
+ }
+ }
+}
+
+/*
+ * arg is either the key or the aggr name. Validate it and convert it to
+ * the linkid if altroot is NULL.
+ */
+static dladm_status_t
+i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
+ datalink_id_t *linkidp, uint32_t flags)
+{
+ int key = 0;
+ char *aggr = NULL;
+ dladm_status_t status;
+
+ if (!str2int(arg, &key))
+ aggr = (char *)arg;
+
+ if (aggr == NULL && key == 0)
+ return (DLADM_STATUS_LINKINVAL);
+
+ if (altroot != NULL)
+ return (DLADM_STATUS_OK);
+
+ if (aggr != NULL) {
+ status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL);
+ } else {
+ status = dladm_key2linkid(key, linkidp, flags);
+ }
+
+ return (status);
}
static void
do_delete_aggr(int argc, char *argv[])
{
- int key;
char option;
- boolean_t t_arg = B_FALSE;
char *altroot = NULL;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
dladm_status_t status;
+ datalink_id_t linkid;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":R:t", longopts,
- NULL)) != -1) {
+ while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
switch (option) {
case 't':
- t_arg = B_TRUE;
+ flags &= ~DLADM_OPT_PERSIST;
break;
case 'R':
altroot = optarg;
@@ -393,14 +504,19 @@ do_delete_aggr(int argc, char *argv[])
}
}
- /* get key value (required last argument) */
+ /* get key value or the aggregation name (required last argument) */
if (optind != (argc-1))
usage();
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
- status = dladm_aggr_delete(key, t_arg, altroot);
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ status = dladm_aggr_delete(linkid, flags);
+done:
if (status != DLADM_STATUS_OK)
die_dlerr(status, "delete operation failed");
}
@@ -408,30 +524,37 @@ do_delete_aggr(int argc, char *argv[])
static void
do_add_aggr(int argc, char *argv[])
{
- char option;
- int key;
+ char option;
+ uint_t n, ndev, nlink;
+ char *altroot = NULL;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ datalink_id_t linkid;
+ dladm_status_t status;
dladm_aggr_port_attr_db_t port[MAXPORT];
- uint_t nport = 0;
- boolean_t t_arg = B_FALSE;
- char *altroot = NULL;
- dladm_status_t status;
+ char *devs[MAXPORT];
+ char *links[MAXPORT];
- opterr = 0;
- while ((option = getopt_long(argc, argv, ":d:R:t", longopts,
+ ndev = nlink = opterr = 0;
+ while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
NULL)) != -1) {
switch (option) {
case 'd':
- if (nport >= MAXPORT)
- die("too many <dev> arguments");
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
- if (strlcpy(port[nport].lp_devname, optarg,
- MAXNAMELEN) >= MAXNAMELEN)
- die("device name too long");
+ devs[ndev++] = optarg;
+ break;
+ case 'l':
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
- nport++;
+ links[nlink++] = optarg;
break;
case 't':
- t_arg = B_TRUE;
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'f':
+ flags |= DLADM_OPT_FORCE;
break;
case 'R':
altroot = optarg;
@@ -442,17 +565,38 @@ do_add_aggr(int argc, char *argv[])
}
}
- if (nport == 0)
+ if (ndev + nlink == 0)
usage();
- /* get key value (required last argument) */
+ /* get key value or the aggregation name (required last argument) */
if (optind != (argc-1))
usage();
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
+ flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
+ DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
- status = dladm_aggr_add(key, nport, port, t_arg, altroot);
+ for (n = 0; n < ndev; n++) {
+ if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
+ DLADM_STATUS_OK) {
+ die("invalid <dev> '%s'", devs[n]);
+ }
+ }
+
+ for (n = 0; n < nlink; n++) {
+ if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
+ NULL, NULL, NULL) != DLADM_STATUS_OK) {
+ die("invalid <link> '%s'", links[n]);
+ }
+ }
+
+ status = dladm_aggr_add(linkid, ndev + nlink, port, flags);
+done:
if (status != DLADM_STATUS_OK) {
/*
* checking DLADM_STATUS_NOTSUP is a temporary workaround
@@ -462,10 +606,14 @@ do_add_aggr(int argc, char *argv[])
(void) fprintf(stderr,
gettext("%s: add operation failed: %s\n"),
progname,
- gettext("device capabilities don't match"));
+ gettext("link capabilities don't match"));
exit(ENOTSUP);
+ } else if (status == DLADM_STATUS_NONOTIF) {
+ die_dlerr(status, "not all links have link up/down "
+ "detection; must use -f (see dladm(1M))\n");
+ } else {
+ die_dlerr(status, "add operation failed");
}
- die_dlerr(status, "add operation failed");
}
}
@@ -473,29 +621,34 @@ static void
do_remove_aggr(int argc, char *argv[])
{
char option;
- int key;
dladm_aggr_port_attr_db_t port[MAXPORT];
- uint_t nport = 0;
- boolean_t t_arg = B_FALSE;
+ uint_t n, ndev, nlink;
+ char *devs[MAXPORT];
+ char *links[MAXPORT];
char *altroot = NULL;
+ uint32_t flags;
+ datalink_id_t linkid;
dladm_status_t status;
- opterr = 0;
- while ((option = getopt_long(argc, argv, ":d:R:t",
- longopts, NULL)) != -1) {
+ flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ ndev = nlink = opterr = 0;
+ while ((option = getopt_long(argc, argv, ":d:l:R:t",
+ lopts, NULL)) != -1) {
switch (option) {
case 'd':
- if (nport >= MAXPORT)
- die("too many <dev> arguments");
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
- if (strlcpy(port[nport].lp_devname, optarg,
- MAXNAMELEN) >= MAXNAMELEN)
- die("device name too long");
+ devs[ndev++] = optarg;
+ break;
+ case 'l':
+ if (ndev + nlink >= MAXPORT)
+ die("too many ports specified");
- nport++;
+ links[nlink++] = optarg;
break;
case 't':
- t_arg = B_TRUE;
+ flags &= ~DLADM_OPT_PERSIST;
break;
case 'R':
altroot = optarg;
@@ -506,17 +659,36 @@ do_remove_aggr(int argc, char *argv[])
}
}
- if (nport == 0)
+ if (ndev + nlink == 0)
usage();
- /* get key value (required last argument) */
+ /* get key value or the aggregation name (required last argument) */
if (optind != (argc-1))
usage();
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ for (n = 0; n < ndev; n++) {
+ if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) !=
+ DLADM_STATUS_OK) {
+ die("invalid <dev> '%s'", devs[n]);
+ }
+ }
+
+ for (n = 0; n < nlink; n++) {
+ if (dladm_name2info(links[n], &port[n + ndev].lp_linkid,
+ NULL, NULL, NULL) != DLADM_STATUS_OK) {
+ die("invalid <link> '%s'", links[n]);
+ }
+ }
- status = dladm_aggr_remove(key, nport, port, t_arg, altroot);
+ status = dladm_aggr_remove(linkid, ndev + nlink, port, flags);
+done:
if (status != DLADM_STATUS_OK)
die_dlerr(status, "remove operation failed");
}
@@ -525,19 +697,19 @@ static void
do_modify_aggr(int argc, char *argv[])
{
char option;
- int key;
uint32_t policy = AGGR_POLICY_L4;
aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF;
aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT;
uint8_t mac_addr[ETHERADDRL];
boolean_t mac_addr_fixed = B_FALSE;
uint8_t modify_mask = 0;
- boolean_t t_arg = B_FALSE;
char *altroot = NULL;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ datalink_id_t linkid;
dladm_status_t status;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts,
+ while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
NULL)) != -1) {
switch (option) {
case 'P':
@@ -560,6 +732,7 @@ do_modify_aggr(int argc, char *argv[])
die("invalid MAC address '%s'", optarg);
break;
case 'l':
+ case 'L':
if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
die_optdup(option);
@@ -578,7 +751,7 @@ do_modify_aggr(int argc, char *argv[])
die("invalid LACP timer value '%s'", optarg);
break;
case 't':
- t_arg = B_TRUE;
+ flags &= ~DLADM_OPT_PERSIST;
break;
case 'R':
altroot = optarg;
@@ -592,15 +765,21 @@ do_modify_aggr(int argc, char *argv[])
if (modify_mask == 0)
die("at least one of the -PulT options must be specified");
- /* get key value (required last argument) */
+ /* get key value or the aggregation name (required last argument) */
if (optind != (argc-1))
usage();
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
- status = dladm_aggr_modify(key, modify_mask, policy, mac_addr_fixed,
- mac_addr, lacp_mode, lacp_timer, t_arg, altroot);
+ status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed,
+ (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags);
+
+done:
if (status != DLADM_STATUS_OK)
die_dlerr(status, "modify operation failed");
}
@@ -608,21 +787,27 @@ do_modify_aggr(int argc, char *argv[])
static void
do_up_aggr(int argc, char *argv[])
{
- int key = 0;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
dladm_status_t status;
- /* get aggregation key (optional last argument) */
+ /*
+ * get the key or the name of the aggregation (optional last argument)
+ */
if (argc == 2) {
- if (!str2int(argv[1], &key) || key < 1)
- die("invalid key value '%s'", argv[1]);
+ if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
+ DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) {
+ goto done;
+ }
} else if (argc > 2) {
usage();
}
- if ((status = dladm_aggr_up(key, NULL)) != DLADM_STATUS_OK) {
- if (key != 0) {
- die_dlerr(status, "could not bring up aggregation '%u'",
- key);
+ status = dladm_aggr_up(linkid);
+done:
+ if (status != DLADM_STATUS_OK) {
+ if (argc == 2) {
+ die_dlerr(status,
+ "could not bring up aggregation '%s'", argv[1]);
} else {
die_dlerr(status, "could not bring aggregations up");
}
@@ -630,174 +815,554 @@ do_up_aggr(int argc, char *argv[])
}
static void
-do_down_aggr(int argc, char *argv[])
+do_create_vlan(int argc, char *argv[])
{
+ char *link = NULL;
+ char drv[DLPI_LINKNAME_MAX];
+ uint_t ppa;
+ datalink_id_t linkid;
+ int vid = 0;
+ char option;
+ uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
+ char *altroot = NULL;
+ char vlan[MAXLINKNAMELEN];
dladm_status_t status;
- int key = 0;
- /* get aggregation key (optional last argument) */
- if (argc == 2) {
- if (!str2int(argv[1], &key) || key < 1)
- die("invalid key value '%s'", argv[1]);
- } else if (argc > 2) {
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":tfl:v:",
+ lopts, NULL)) != -1) {
+ switch (option) {
+ case 'v':
+ if (vid != 0)
+ die_optdup(option);
+
+ if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
+ die("invalid VLAN identifier '%s'", optarg);
+
+ break;
+ case 'l':
+ if (link != NULL)
+ die_optdup(option);
+
+ link = optarg;
+ break;
+ case 'f':
+ flags |= DLADM_OPT_FORCE;
+ break;
+ case 't':
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'R':
+ altroot = optarg;
+ break;
+ default:
+ die_opterr(optopt, option);
+ break;
+ }
+ }
+
+ /* get vlan name if there is any */
+ if ((vid == 0) || (link == NULL) || (argc - optind > 1))
usage();
+
+ if (optind == (argc - 1)) {
+ if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
+ MAXLINKNAMELEN) {
+ die("vlan name too long '%s'", argv[optind]);
+ }
+ } else {
+ if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
+ (ppa >= 1000) ||
+ (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
+ DLPI_SUCCESS)) {
+ die("invalid link name '%s'", link);
+ }
}
- if ((status = dladm_aggr_down(key)) != DLADM_STATUS_OK) {
- if (key != 0) {
- die_dlerr(status,
- "could not bring down aggregation '%u'", key);
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
+ DLADM_STATUS_OK) {
+ die("invalid link name '%s'", link);
+ }
+
+ if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) !=
+ DLADM_STATUS_OK) {
+ if (status == DLADM_STATUS_NOTSUP) {
+ die_dlerr(status, "VLAN over '%s' may require lowered "
+ "MTU; must use -f (see dladm(1M))\n", link);
} else {
- die_dlerr(status, "could not bring down aggregations");
+ die_dlerr(status, "create operation failed");
}
}
}
-#define TYPE_WIDTH 10
+static void
+do_delete_vlan(int argc, char *argv[])
+{
+ char option;
+ uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
+ char *altroot = NULL;
+ datalink_id_t linkid;
+ dladm_status_t status;
+
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
+ switch (option) {
+ case 't':
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'R':
+ altroot = optarg;
+ break;
+ default:
+ die_opterr(optopt, option);
+ break;
+ }
+ }
+
+ /* get VLAN link name (required last argument) */
+ if (optind != (argc - 1))
+ usage();
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ status = dladm_vlan_delete(linkid, flags);
+done:
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "delete operation failed");
+}
static void
-print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy)
+do_up_vlan(int argc, char *argv[])
{
- char type[TYPE_WIDTH];
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
- if (!legacy) {
- char drv[DLPI_LINKNAME_MAX];
- uint_t instance;
+ /*
+ * get the name of the VLAN (optional last argument)
+ */
+ if (argc > 2)
+ usage();
+
+ if (argc == 2) {
+ status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ }
- if (dap->da_vid != 0) {
- (void) snprintf(type, TYPE_WIDTH, "vlan %u",
- dap->da_vid);
+ status = dladm_vlan_up(linkid);
+done:
+ if (status != DLADM_STATUS_OK) {
+ if (argc == 2) {
+ die_dlerr(status,
+ "could not bring up VLAN '%s'", argv[1]);
} else {
- (void) snprintf(type, TYPE_WIDTH, "non-vlan");
+ die_dlerr(status, "could not bring VLANs up");
}
+ }
+}
- if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS)
- return;
+static void
+do_rename_link(int argc, char *argv[])
+{
+ char option;
+ char *link1, *link2;
+ char *altroot = NULL;
+ dladm_status_t status;
- if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
- (void) printf("%s type=%s mtu=%d key=%u\n",
- name, type, dap->da_max_sdu, instance);
- } else {
- (void) printf("%s type=%s mtu=%d device=%s\n",
- name, type, dap->da_max_sdu, dap->da_dev);
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
+ switch (option) {
+ case 'R':
+ altroot = optarg;
+ break;
+ default:
+ die_opterr(optopt, option);
+ break;
}
- } else {
- (void) printf("%s type=legacy mtu=%d device=%s\n",
- name, dap->da_max_sdu, name);
}
+
+ /* get link1 and link2 name (required the last 2 arguments) */
+ if (optind != (argc - 2))
+ usage();
+
+ if (altroot != NULL)
+ altroot_cmd(altroot, argc, argv);
+
+ link1 = argv[optind++];
+ link2 = argv[optind];
+ if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK)
+ die_dlerr(status, "rename operation failed");
}
static void
-print_link(const char *name, dladm_attr_t *dap, boolean_t legacy)
+do_delete_phys(int argc, char *argv[])
{
- char type[TYPE_WIDTH];
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
- if (!legacy) {
- char drv[DLPI_LINKNAME_MAX];
- uint_t instance;
+ /* get link name (required the last argument) */
+ if (argc > 2)
+ usage();
- if (dap->da_vid != 0) {
- (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"),
- dap->da_vid);
- } else {
- (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan"));
- }
+ if (argc == 2) {
+ status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "cannot delete '%s'", argv[1]);
+ }
- if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS)
- return;
- if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) {
- (void) printf(gettext("%-9s\ttype: %s\tmtu: %d"
- "\taggregation: key %u\n"), name, type,
- dap->da_max_sdu, instance);
- } else {
- (void) printf(gettext("%-9s\ttype: %s\tmtu: "
- "%d\tdevice: %s\n"), name, type, dap->da_max_sdu,
- dap->da_dev);
- }
- } else {
- (void) printf(gettext("%-9s\ttype: legacy\tmtu: "
- "%d\tdevice: %s\n"), name, dap->da_max_sdu, name);
+ if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) {
+ if (argc == 2)
+ die_dlerr(status, "cannot delete '%s'", argv[1]);
+ else
+ die_dlerr(status, "delete operation failed");
}
}
+/*ARGSUSED*/
static int
-get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy)
+i_dladm_walk_linkmap(datalink_id_t linkid, void *arg)
{
- int err;
+ char name[MAXLINKNAMELEN];
+ char mediabuf[DLADM_STRSIZE];
+ char classbuf[DLADM_STRSIZE];
+ datalink_class_t class;
+ uint32_t media;
+ uint32_t flags;
+
+ if (dladm_datalink_id2info(linkid, &flags, &class, &media, name,
+ MAXLINKNAMELEN) == DLADM_STATUS_OK) {
+ (void) dladm_class2str(class, classbuf);
+ (void) dladm_media2str(media, mediabuf);
+ (void) printf("%-12s%8d %-12s%-20s %6d\n", name,
+ linkid, classbuf, mediabuf, flags);
+ }
+ return (DLADM_WALK_CONTINUE);
+}
- if ((err = dladm_info(name, dlattrp)) == 0) {
- *legacy = B_FALSE;
- } else if (err < 0 && errno == ENODEV) {
- dlpi_handle_t dh;
- dlpi_info_t dlinfo;
+/*ARGSUSED*/
+static void
+do_show_linkmap(int argc, char *argv[])
+{
+ if (argc != 1)
+ die("invalid arguments");
+
+ (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID",
+ "CLASS", "MEDIA", "FLAGS");
+ (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
+}
- /*
- * A return value of ENODEV means that the specified
- * device is not gldv3.
- */
- if (dlpi_open(name, &dh, 0) != DLPI_SUCCESS) {
- errno = ENOENT;
- return (-1);
+/*
+ * Delete inactive physical links.
+ */
+/*ARGSUSED*/
+static int
+purge_phys(datalink_id_t linkid, void *arg)
+{
+ datalink_class_t class;
+ uint32_t flags;
+
+ if (dladm_datalink_id2info(linkid, &flags, &class, NULL,
+ NULL, 0) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
+ (void) dladm_phys_delete(linkid);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+/*ARGSUSED*/
+static void
+do_init_phys(int argc, char *argv[])
+{
+ di_node_t devtree;
+
+ if (argc > 1)
+ usage();
+
+ /*
+ * Force all the devices to attach, therefore all the network physical
+ * devices can be known to the dlmgmtd daemon.
+ */
+ if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
+ di_fini(devtree);
+
+ (void) dladm_walk_datalink_id(purge_phys, NULL,
+ DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
+}
+
+static void
+print_link_head(show_state_t *state)
+{
+ if (state->ls_donefirst)
+ return;
+ state->ls_donefirst = B_TRUE;
+
+ if (state->ls_parseable)
+ return;
+
+ if (state->ls_flags & DLADM_OPT_ACTIVE) {
+ (void) printf("%-12s%-8s%6s %-9s%s\n", "LINK", "CLASS", "MTU",
+ "STATE", "OVER");
+ } else {
+ (void) printf("%-12s%-8s%s\n", "LINK", "CLASS", "OVER");
+ }
+}
+
+/*
+ * Print the active topology information.
+ */
+static dladm_status_t
+print_link_topology(show_state_t *state, datalink_id_t linkid,
+ datalink_class_t class, char **pptr, char *lim)
+{
+ char *fmt;
+ char over[MAXLINKNAMELEN];
+ uint32_t flags = state->ls_flags;
+ dladm_status_t status = DLADM_STATUS_OK;
+
+ if (state->ls_parseable)
+ fmt = "OVER=\"%s";
+ else
+ fmt = "%s";
+
+ if (class == DATALINK_CLASS_VLAN) {
+ dladm_vlan_attr_t vinfo;
+
+ status = dladm_vlan_info(linkid, &vinfo, flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL,
+ NULL, over, sizeof (over));
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over);
+ } else if (class == DATALINK_CLASS_AGGR) {
+ dladm_aggr_grp_attr_t ginfo;
+ int i;
+
+ status = dladm_aggr_info(linkid, &ginfo, flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ if (ginfo.lg_nports == 0) {
+ status = DLADM_STATUS_BADVAL;
+ goto done;
}
- if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
- dlpi_close(dh);
- errno = EINVAL;
- return (-1);
+ for (i = 0; i < ginfo.lg_nports; i++) {
+ status = dladm_datalink_id2info(
+ ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, over,
+ sizeof (over));
+ if (status != DLADM_STATUS_OK) {
+ free(ginfo.lg_ports);
+ goto done;
+ }
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over);
+ fmt = " %s";
+ }
+ free(ginfo.lg_ports);
+ } else if (class == DATALINK_CLASS_VNIC) {
+ dladm_vnic_attr_sys_t vinfo;
+
+ if ((status = dladm_vnic_info(linkid, &vinfo, flags)) !=
+ DLADM_STATUS_OK || (status = dladm_datalink_id2info(
+ vinfo.va_link_id, NULL, NULL, NULL, over,
+ sizeof (over))) != DLADM_STATUS_OK) {
+ goto done;
}
- dlpi_close(dh);
- *legacy = B_TRUE;
- bzero(dlattrp, sizeof (*dlattrp));
- dlattrp->da_max_sdu = dlinfo.di_max_sdu;
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over);
} else {
- /*
- * If the return value is not ENODEV, this means that
- * user is either passing in a bogus interface name
- * or a vlan interface name that doesn't exist yet.
- */
- errno = ENOENT;
- return (-1);
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt,
+ state->ls_parseable ? "" : "--");
}
- return (0);
+ if (state->ls_parseable)
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\"\n");
+ else
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\n");
+
+done:
+ return (status);
}
-/* ARGSUSED */
-static void
-show_link(void *arg, const char *name)
+static dladm_status_t
+print_link(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim)
{
- dladm_attr_t dlattr;
- boolean_t legacy = B_TRUE;
- show_link_state_t *state = (show_link_state_t *)arg;
+ char link[MAXLINKNAMELEN];
+ char buf[DLADM_STRSIZE];
+ datalink_class_t class;
+ uint_t mtu;
+ char *fmt;
+ uint32_t flags;
+ dladm_status_t status;
+
+ if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL,
+ link, sizeof (link))) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (!(state->ls_flags & flags)) {
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ dladm_attr_t dlattr;
+
+ if (class == DATALINK_CLASS_PHYS) {
+ dladm_phys_attr_t dpa;
+ dlpi_handle_t dh;
+ dlpi_info_t dlinfo;
+
+ if ((status = dladm_phys_info(linkid, &dpa,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (!dpa.dp_novanity)
+ goto link_mtu;
+
+ /*
+ * This is a physical link that does not have
+ * vanity naming support.
+ */
+ if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
+ DLPI_SUCCESS) {
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
+ dlpi_close(dh);
+ status = DLADM_STATUS_BADARG;
+ goto done;
+ }
+
+ dlpi_close(dh);
+ mtu = dlinfo.di_max_sdu;
+ } else {
+link_mtu:
+ status = dladm_info(linkid, &dlattr);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ mtu = dlattr.da_max_sdu;
+ }
+ }
- if (get_if_info(name, &dlattr, &legacy) < 0)
- die("invalid link '%s'", name);
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ if (state->ls_parseable)
+ fmt = "LINK=\"%s\" CLASS=\"%s\" MTU=\"%d\" ";
+ else
+ fmt = "%-12s%-8s%6d ";
+ } else {
+ if (state->ls_parseable)
+ fmt = "LINK=\"%s\" CLASS=\"%s\" ";
+ else
+ fmt = "%-12s%-8s";
+ }
- if (state->ls_parseable) {
- print_link_parseable(name, &dlattr, legacy);
+ (void) dladm_class2str(class, buf);
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link,
+ buf, mtu);
} else {
- print_link(name, &dlattr, legacy);
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, buf);
}
+
+ (void) get_linkstate(link, B_TRUE, buf);
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ if (state->ls_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "STATE=\"%s\" ", buf);
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-9s", buf);
+ }
+ }
+
+ status = print_link_topology(state, linkid, class, pptr, lim);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+done:
+ return (status);
}
-static void
-show_link_stats(void *arg, const char *name)
+static int
+show_link(datalink_id_t linkid, void *arg)
+{
+ show_state_t *state = arg;
+ dladm_status_t status;
+ char buf[MAXLINELEN];
+ char *ptr = buf, *lim = buf + MAXLINELEN;
+
+ status = print_link(state, linkid, &ptr, lim);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ print_link_head(state);
+ (void) printf("%s", buf);
+
+done:
+ state->ls_status = status;
+ return (DLADM_WALK_CONTINUE);
+}
+
+static int
+show_link_stats(datalink_id_t linkid, void *arg)
{
- show_link_state_t *state = (show_link_state_t *)arg;
+ char link[MAXLINKNAMELEN];
+ datalink_class_t class;
+ show_state_t *state = arg;
pktsum_t stats, diff_stats;
+ dladm_phys_attr_t dpa;
if (state->ls_firstonly) {
if (state->ls_donefirst)
- return;
+ return (DLADM_WALK_CONTINUE);
state->ls_donefirst = B_TRUE;
} else {
bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
}
- get_link_stats(name, &stats);
+ if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link,
+ sizeof (link)) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (class == DATALINK_CLASS_PHYS) {
+ if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
+ DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
+ if (dpa.dp_novanity)
+ get_mac_stats(dpa.dp_dev, &stats);
+ else
+ get_link_stats(link, &stats);
+ } else {
+ get_link_stats(link, &stats);
+ }
stats_diff(&diff_stats, &stats, &state->ls_prevstats);
- (void) printf("%s", name);
- (void) printf("\t\t%-10llu", diff_stats.ipackets);
+ (void) printf("%-12s", link);
+ (void) printf("%-10llu", diff_stats.ipackets);
(void) printf("%-12llu", diff_stats.rbytes);
(void) printf("%-8u", diff_stats.ierrors);
(void) printf("%-10llu", diff_stats.opackets);
@@ -805,218 +1370,358 @@ show_link_stats(void *arg, const char *name)
(void) printf("%-8u\n", diff_stats.oerrors);
state->ls_prevstats = stats;
+ return (DLADM_WALK_CONTINUE);
}
static void
-dump_grp(dladm_aggr_grp_attr_t *grp, boolean_t parseable)
+print_port_stat(const char *port, pktsum_t *old_stats, pktsum_t *port_stats,
+ pktsum_t *tot_stats, char **pptr, char *lim)
{
- char buf[DLADM_STRSIZE];
- char addr_str[ETHERADDRL * 3];
+ pktsum_t diff_stats;
- if (!parseable) {
- (void) printf(gettext("key: %d (0x%04x)"),
- grp->lg_key, grp->lg_key);
+ stats_diff(&diff_stats, port_stats, old_stats);
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-12s%-10s%8llu %8llu %8llu %8llu ", "", port,
+ diff_stats.ipackets, diff_stats.rbytes, diff_stats.opackets,
+ diff_stats.obytes);
- (void) printf(gettext("\tpolicy: %s"),
- dladm_aggr_policy2str(grp->lg_policy, buf));
+ if (tot_stats->ipackets == 0) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s ", "--");
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%% ",
+ (double)diff_stats.ipackets/
+ (double)tot_stats->ipackets * 100);
+ }
- (void) printf(gettext("\taddress: %s (%s)\n"),
- dladm_aggr_macaddr2str(grp->lg_mac, addr_str),
- (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto"));
+ if (tot_stats->opackets == 0) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s\n", "--");
} else {
- (void) printf("aggr key=%d", grp->lg_key);
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%%\n",
+ (double)diff_stats.opackets/
+ (double)tot_stats->opackets * 100);
+ }
- (void) printf(" policy=%s",
- dladm_aggr_policy2str(grp->lg_policy, buf));
+ *old_stats = *port_stats;
+}
- (void) printf(" address=%s",
- dladm_aggr_macaddr2str(grp->lg_mac, addr_str));
+static void
+print_aggr_head(show_grp_state_t *state)
+{
+ if (state->gs_donefirst)
+ return;
+ state->gs_donefirst = B_TRUE;
- (void) printf(" address-type=%s\n",
- (grp->lg_mac_fixed) ? "fixed" : "auto");
+ if (state->gs_parseable)
+ return;
+
+ if (state->gs_lacp) {
+ (void) printf("%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n", "LINK",
+ "PORT", "AGGREGATABLE", "SYNC", "COLL", "DIST",
+ "DEFAULTED", "EXPIRED");
+ } else if (state->gs_extended) {
+ (void) printf("%-12s%-14s%6s %-9s%-9s%-18s%s\n", "LINK",
+ "PORT", "SPEED", "DUPLEX", "STATE", "ADDRESS", "PORTSTATE");
+ } else if (!state->gs_stats) {
+ (void) printf("%-12s%-8s%-24s%-13s%-11s%s\n", "LINK", "POLICY",
+ "ADDRPOLICY", "LACPACTIVITY", "LACPTIMER", "FLAGS");
}
}
-static void
-dump_grp_lacp(dladm_aggr_grp_attr_t *grp, boolean_t parseable)
+static dladm_status_t
+print_aggr_info(show_grp_state_t *state, const char *link,
+ dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim)
{
- char lacp_mode_str[DLADM_STRSIZE];
- char lacp_timer_str[DLADM_STRSIZE];
+ char buf[DLADM_STRSIZE];
+ char *fmt;
+ char addr_str[ETHERADDRL * 3];
+ char str[ETHERADDRL * 3 + 2];
- (void) dladm_aggr_lacpmode2str(grp->lg_lacp_mode, lacp_mode_str);
- (void) dladm_aggr_lacptimer2str(grp->lg_lacp_timer, lacp_timer_str);
+ if (state->gs_parseable)
+ fmt = "LINK=\"%s\" POLICY=\"%s\" ADDRPOLICY=\"%s%s\" ";
+ else
+ fmt = "%-12s%-8s%-6s%-18s";
- if (!parseable) {
- (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str);
- (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str);
+ if (ginfop->lg_mac_fixed) {
+ (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
+ (void) snprintf(str, ETHERADDRL * 3 + 3, " (%s)", addr_str);
} else {
- (void) printf(" lacp-mode=%s", lacp_mode_str);
- (void) printf(" lacp-timer=%s\n", lacp_timer_str);
+ str[0] = '\0';
}
-}
-static void
-dump_grp_stats(dladm_aggr_grp_attr_t *grp)
-{
- (void) printf("key: %d", grp->lg_key);
- (void) printf("\tipackets rbytes opackets obytes ");
- (void) printf("%%ipkts %%opkts\n");
-}
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link,
+ dladm_aggr_policy2str(ginfop->lg_policy, buf),
+ ginfop->lg_mac_fixed ? "fixed" : "auto", str);
-static void
-dump_ports_lacp_head(void)
-{
- (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"),
- gettext("timeout"), gettext("aggregatable"), gettext("sync"),
- gettext("coll"), gettext("dist"), gettext("defaulted"),
- gettext("expired"));
-}
+ (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, buf);
+ if (state->gs_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "LACPACTIVITY=\"%s\" ", buf);
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-13s", buf);
+ }
-static void
-dump_ports_head(void)
-{
- (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t"
- "state\n"));
+ (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, buf);
+ if (state->gs_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "LACPTIMER=\"%s\" FLAGS=\"%c----\"\n", buf,
+ ginfop->lg_force ? 'f' : '-');
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-11s%c----\n", buf, ginfop->lg_force ? 'f' : '-');
+ }
+
+ return (DLADM_STATUS_OK);
}
-static void
-dump_port(dladm_aggr_port_attr_t *port, boolean_t parseable)
+static dladm_status_t
+print_aggr_extended(show_grp_state_t *state, const char *link,
+ dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim)
{
- char *dev = port->lp_devname;
- char mac_addr[ETHERADDRL * 3];
- char buf[DLADM_STRSIZE];
+ char addr_str[ETHERADDRL * 3];
+ char port[MAXLINKNAMELEN];
+ dladm_phys_attr_t dpa;
+ char buf[DLADM_STRSIZE];
+ char *fmt;
+ int i;
+ dladm_status_t status;
- if (!parseable) {
- (void) printf(" %-9s\t%s", dev, dladm_aggr_macaddr2str(
- port->lp_mac, mac_addr));
- (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) /
- 1000000ull));
- (void) printf("\t%s", mac_link_duplex(dev, buf));
- (void) printf("\t%s", mac_link_state(dev, buf));
- (void) printf("\t%s\n",
- dladm_aggr_portstate2str(port->lp_state, buf));
+ if (state->gs_parseable)
+ fmt = "LINK=\"%s\" PORT=\"%s\" SPEED=\"%uMb\" DUPLEX=\"%s\" ";
+ else
+ fmt = "%-12s%-14s%4uMb %-9s";
+ (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
+
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link,
+ state->gs_parseable ? "" : "--",
+ (uint_t)((get_ifspeed(link, B_TRUE)) / 1000000ull),
+ get_linkduplex(link, B_TRUE, buf));
+
+ (void) get_linkstate(link, B_TRUE, buf);
+ if (state->gs_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "STATE=\"%s\" ADDRESS=\"%s\" PORTSTATE=\"%s\"\n", buf,
+ addr_str, "");
} else {
- (void) printf(" device=%s address=%s", dev,
- dladm_aggr_macaddr2str(port->lp_mac, mac_addr));
- (void) printf(" speed=%u", (int)(mac_ifspeed(dev) /
- 1000000ull));
- (void) printf(" duplex=%s", mac_link_duplex(dev, buf));
- (void) printf(" link=%s", mac_link_state(dev, buf));
- (void) printf(" port=%s",
- dladm_aggr_portstate2str(port->lp_state, buf));
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-9s%-18s%s\n",
+ buf, addr_str, "--");
}
-}
-static void
-dump_port_lacp(dladm_aggr_port_attr_t *port)
-{
- aggr_lacp_state_t *state = &port->lp_lacp_state;
+ for (i = 0; i < ginfop->lg_nports; i++) {
+ dladm_aggr_port_attr_t *portp = &(ginfop->lg_ports[i]);
+ const char *tmp;
+
+ if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL,
+ NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ (void) dladm_aggr_macaddr2str(portp->lp_mac, addr_str);
+
+ if (state->gs_parseable)
+ tmp = link;
+ else
+ tmp = "";
+
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, tmp, port,
+ (uint_t)((get_ifspeed(dpa.dp_dev, B_FALSE)) / 1000000ull),
+ get_linkduplex(dpa.dp_dev, B_FALSE, buf));
+
+ (void) get_linkstate(dpa.dp_dev, B_FALSE, buf);
+ if (state->gs_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "STATE=\"%s\" ADDRESS=\"%s\" ", buf, addr_str);
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-9s%-18s", buf, addr_str);
+ }
+
+ (void) dladm_aggr_portstate2str(
+ ginfop->lg_ports[i].lp_state, buf);
+ if (state->gs_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "PORTSTATE=\"%s\"\n", buf);
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%s\n", buf);
+ }
+ }
- (void) printf(DUMP_LACP_FORMAT,
- port->lp_devname, state->bit.activity ? "active" : "passive",
- state->bit.timeout ? "short" : "long",
- state->bit.aggregation ? "yes" : "no",
- state->bit.sync ? "yes" : "no",
- state->bit.collecting ? "yes" : "no",
- state->bit.distributing ? "yes" : "no",
- state->bit.defaulted ? "yes" : "no",
- state->bit.expired ? "yes" : "no");
+ status = DLADM_STATUS_OK;
+done:
+ return (status);
}
-static void
-dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats,
- pktsum_t *tot_stats)
+static dladm_status_t
+print_aggr_lacp(show_grp_state_t *state, const char *link,
+ dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim)
{
- pktsum_t diff_stats;
- pktsum_t *old_stats = &state->gs_prevstats[index];
-
- stats_diff(&diff_stats, port_stats, old_stats);
+ char port[MAXLINKNAMELEN];
+ char *fmt;
+ const char *dlink = link;
+ int i;
+ dladm_status_t status;
- (void) printf("\t%-10llu", diff_stats.ipackets);
- (void) printf("%-12llu", diff_stats.rbytes);
- (void) printf("%-10llu", diff_stats.opackets);
- (void) printf("%-12llu", diff_stats.obytes);
+ if (state->gs_parseable) {
+ fmt = "LINK=\"%s\" PORT=\"%s\" AGGREGATABLE=\"%s\" SYNC=\"%s\" "
+ "COLL=\"%s\" DIST=\"%s\" DEFAULTED=\"%s\" EXPITED=\"%s\"\n";
+ } else {
+ fmt = "%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n";
+ }
- if (tot_stats->ipackets == 0)
- (void) printf("\t-");
- else
- (void) printf("\t%-6.1f", (double)diff_stats.ipackets/
- (double)tot_stats->ipackets * 100);
+ for (i = 0; i < ginfop->lg_nports; i++) {
+ aggr_lacp_state_t *lstate;
- if (tot_stats->opackets == 0)
- (void) printf("\t-");
- else
- (void) printf("\t%-6.1f", (double)diff_stats.opackets/
- (double)tot_stats->opackets * 100);
+ status = dladm_datalink_id2info(ginfop->lg_ports[i].lp_linkid,
+ NULL, NULL, NULL, port, sizeof (port));
+ if (status != DLADM_STATUS_OK)
+ goto done;
- (void) printf("\n");
+ /*
+ * Only display link for the first port.
+ */
+ if ((i > 0) && !(state->gs_parseable))
+ dlink = "";
+ lstate = &(ginfop->lg_ports[i].lp_lacp_state);
+
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, dlink, port,
+ lstate->bit.aggregation ? "yes" : "no",
+ lstate->bit.sync ? "yes" : "no",
+ lstate->bit.collecting ? "yes" : "no",
+ lstate->bit.distributing ? "yes" : "no",
+ lstate->bit.defaulted ? "yes" : "no",
+ lstate->bit.expired ? "yes" : "no");
+ }
- *old_stats = *port_stats;
+ status = DLADM_STATUS_OK;
+done:
+ return (status);
}
-static int
-show_key(void *arg, dladm_aggr_grp_attr_t *grp)
+static dladm_status_t
+print_aggr_stats(show_grp_state_t *state, const char *link,
+ dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim)
{
- show_grp_state_t *state = (show_grp_state_t *)arg;
- int i;
+ char port[MAXLINKNAMELEN];
+ dladm_phys_attr_t dpa;
+ dladm_aggr_port_attr_t *portp;
pktsum_t pktsumtot, port_stat;
+ dladm_status_t status;
+ int i;
- if (state->gs_key != 0 && state->gs_key != grp->lg_key)
- return (0);
if (state->gs_firstonly) {
- if (state->gs_found)
- return (0);
+ if (state->gs_donefirst)
+ return (DLADM_WALK_CONTINUE);
+ state->gs_donefirst = B_TRUE;
} else {
bzero(&state->gs_prevstats, sizeof (state->gs_prevstats));
}
- state->gs_found = B_TRUE;
+ /* sum the ports statistics */
+ bzero(&pktsumtot, sizeof (pktsumtot));
- if (state->gs_stats) {
- /* show statistics */
- dump_grp_stats(grp);
+ for (i = 0; i < ginfop->lg_nports; i++) {
- /* sum the ports statistics */
- bzero(&pktsumtot, sizeof (pktsumtot));
- for (i = 0; i < grp->lg_nports; i++) {
- get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
- stats_total(&pktsumtot, &port_stat,
- &state->gs_prevstats[i]);
+ portp = &(ginfop->lg_ports[i]);
+ if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ goto done;
}
- (void) printf(" Total");
- (void) printf("\t%-10llu", pktsumtot.ipackets);
- (void) printf("%-12llu", pktsumtot.rbytes);
- (void) printf("%-10llu", pktsumtot.opackets);
- (void) printf("%-12llu\n", pktsumtot.obytes);
+ get_mac_stats(dpa.dp_dev, &port_stat);
+ stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]);
+ }
+
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-12s%-10s%8llu %8llu %8llu %8llu %8s %8s\n", link, "--",
+ pktsumtot.ipackets, pktsumtot.rbytes, pktsumtot.opackets,
+ pktsumtot.obytes, "--", "--");
+
+ for (i = 0; i < ginfop->lg_nports; i++) {
+ portp = &(ginfop->lg_ports[i]);
- for (i = 0; i < grp->lg_nports; i++) {
- get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat);
- (void) printf(" %s", grp->lg_ports[i].lp_devname);
- dump_port_stat(i, state, &port_stat, &pktsumtot);
+ if ((status = dladm_phys_info(portp->lp_linkid, &dpa,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ goto done;
}
- } else if (state->gs_lacp) {
- /* show LACP info */
- dump_grp(grp, state->gs_parseable);
- dump_grp_lacp(grp, state->gs_parseable);
- dump_ports_lacp_head();
- for (i = 0; i < grp->lg_nports; i++)
- dump_port_lacp(&grp->lg_ports[i]);
- } else {
- dump_grp(grp, state->gs_parseable);
- if (!state->gs_parseable)
- dump_ports_head();
- for (i = 0; i < grp->lg_nports; i++) {
- if (state->gs_parseable)
- (void) printf("dev key=%d", grp->lg_key);
- dump_port(&grp->lg_ports[i], state->gs_parseable);
- if (state->gs_parseable)
- (void) printf("\n");
+
+ get_mac_stats(dpa.dp_dev, &port_stat);
+
+ if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL,
+ NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) {
+ goto done;
}
+
+ print_port_stat(port, &state->gs_prevstats[i], &port_stat,
+ &pktsumtot, pptr, lim);
}
- return (0);
+ status = DLADM_STATUS_OK;
+done:
+ return (status);
+}
+
+static dladm_status_t
+print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr,
+ char *lim)
+{
+ char link[MAXLINKNAMELEN];
+ dladm_aggr_grp_attr_t ginfo;
+ uint32_t flags;
+ dladm_status_t status;
+
+ if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link,
+ sizeof (link))) != DLADM_STATUS_OK) {
+ return (status);
+ }
+
+ if (!(state->gs_flags & flags))
+ return (DLADM_STATUS_NOTFOUND);
+
+ status = dladm_aggr_info(linkid, &ginfo, state->gs_flags);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ if (state->gs_lacp)
+ status = print_aggr_lacp(state, link, &ginfo, pptr, lim);
+ else if (state->gs_extended)
+ status = print_aggr_extended(state, link, &ginfo, pptr, lim);
+ else if (state->gs_stats)
+ status = print_aggr_stats(state, link, &ginfo, pptr, lim);
+ else
+ status = print_aggr_info(state, link, &ginfo, pptr, lim);
+
+done:
+ free(ginfo.lg_ports);
+ return (status);
+}
+
+static int
+show_aggr(datalink_id_t linkid, void *arg)
+{
+ show_grp_state_t *state = arg;
+ dladm_status_t status;
+ char buf[MAXLINELEN];
+ char *ptr = buf, *lim = buf + MAXLINELEN;
+
+ status = print_aggr(state, linkid, &ptr, lim);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ print_aggr_head(state);
+ (void) printf("%s", buf);
+
+done:
+ state->gs_status = status;
+ return (DLADM_WALK_CONTINUE);
}
static int
@@ -1044,77 +1749,90 @@ kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
return (0);
}
-static void
-show_dev(void *arg, const char *dev)
+static int
+show_dev(const char *dev, void *arg)
{
- show_mac_state_t *state = (show_mac_state_t *)arg;
- char buf[DLADM_STRSIZE];
+ show_state_t *state = arg;
+ char buf[DLADM_STRSIZE];
+ char *fmt;
- (void) printf("%s", dev);
+ if (state->ls_parseable)
+ fmt = "DEV=\"%s\" STATE=\"%s\" SPEED=\"%u\" ";
+ else
+ fmt = "%-12s%-10s%4uMb ";
- if (!state->ms_parseable) {
- (void) printf(gettext("\t\tlink: %s"),
- mac_link_state(dev, buf));
- (void) printf(gettext("\tspeed: %5uMb"),
- (unsigned int)(mac_ifspeed(dev) / 1000000ull));
- (void) printf(gettext("\tduplex: %s\n"),
- mac_link_duplex(dev, buf));
- } else {
- (void) printf(" link=%s", mac_link_state(dev, buf));
- (void) printf(" speed=%u",
- (unsigned int)(mac_ifspeed(dev) / 1000000ull));
- (void) printf(" duplex=%s\n", mac_link_duplex(dev, buf));
+ if (!state->ls_donefirst) {
+ if (!state->ls_parseable) {
+ (void) printf("%-12s%-10s%6s %s\n", "DEV", "STATE",
+ "SPEED", "DUPLEX");
+ }
+ state->ls_donefirst = B_TRUE;
}
+
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ (void) printf(fmt, dev, get_linkstate(dev, B_FALSE, buf),
+ (uint_t)(get_ifspeed(dev, B_FALSE) / 1000000ull));
+
+ (void) get_linkduplex(dev, B_FALSE, buf);
+ if (state->ls_parseable)
+ (void) printf("DUPLEX=\"%s\"\n", buf);
+ else
+ (void) printf("%s\n", buf);
+
+ return (DLADM_WALK_CONTINUE);
}
-/*ARGSUSED*/
-static void
-show_dev_stats(void *arg, const char *dev)
+static int
+show_dev_stats(const char *dev, void *arg)
{
- show_mac_state_t *state = (show_mac_state_t *)arg;
+ show_state_t *state = arg;
pktsum_t stats, diff_stats;
- if (state->ms_firstonly) {
- if (state->ms_donefirst)
- return;
- state->ms_donefirst = B_TRUE;
+ if (state->ls_firstonly) {
+ if (state->ls_donefirst)
+ return (DLADM_WALK_CONTINUE);
+ state->ls_donefirst = B_TRUE;
} else {
- bzero(&state->ms_prevstats, sizeof (state->ms_prevstats));
+ bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
}
get_mac_stats(dev, &stats);
- stats_diff(&diff_stats, &stats, &state->ms_prevstats);
+ stats_diff(&diff_stats, &stats, &state->ls_prevstats);
- (void) printf("%s", dev);
- (void) printf("\t\t%-10llu", diff_stats.ipackets);
+ (void) printf("%-12s", dev);
+ (void) printf("%-10llu", diff_stats.ipackets);
(void) printf("%-12llu", diff_stats.rbytes);
(void) printf("%-8u", diff_stats.ierrors);
(void) printf("%-10llu", diff_stats.opackets);
(void) printf("%-12llu", diff_stats.obytes);
(void) printf("%-8u\n", diff_stats.oerrors);
- state->ms_prevstats = stats;
+ state->ls_prevstats = stats;
+ return (DLADM_WALK_CONTINUE);
}
static void
do_show_link(int argc, char *argv[])
{
- char *name = NULL;
int option;
boolean_t s_arg = B_FALSE;
boolean_t i_arg = B_FALSE;
+ uint32_t flags = DLADM_OPT_ACTIVE;
+ boolean_t p_arg = B_FALSE;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
int interval = 0;
- show_link_state_t state;
-
- state.ls_stats = B_FALSE;
- state.ls_parseable = B_FALSE;
+ show_state_t state;
+ dladm_status_t status;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":psi:",
- longopts, NULL)) != -1) {
+ while ((option = getopt_long(argc, argv, ":pPsi:",
+ show_lopts, NULL)) != -1) {
switch (option) {
case 'p':
- state.ls_parseable = B_TRUE;
+ if (p_arg)
+ die_optdup(option);
+
+ p_arg = B_TRUE;
break;
case 's':
if (s_arg)
@@ -1122,6 +1840,12 @@ do_show_link(int argc, char *argv[])
s_arg = B_TRUE;
break;
+ case 'P':
+ if (flags != DLADM_OPT_ACTIVE)
+ die_optdup(option);
+
+ flags = DLADM_OPT_PERSIST;
+ break;
case 'i':
if (i_arg)
die_optdup(option);
@@ -1139,74 +1863,101 @@ do_show_link(int argc, char *argv[])
if (i_arg && !s_arg)
die("the option -i can be used only with -s");
+ if (s_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
+ die("the option -%c cannot be used with -s", p_arg ? 'p' : 'P');
+
/* get link name (optional last argument) */
- if (optind == (argc-1))
- name = argv[optind];
- else if (optind != argc)
+ if (optind == (argc-1)) {
+ uint32_t f;
+
+ if ((status = dladm_name2info(argv[optind], &linkid, &f,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+
+ if (!(f & flags)) {
+ die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
+ argv[optind], flags == DLADM_OPT_PERSIST ?
+ "a temporary link" : "temporarily removed");
+ }
+ } else if (optind != argc) {
usage();
+ }
if (s_arg) {
- link_stats(name, interval);
+ link_stats(linkid, interval);
return;
}
- if (name == NULL) {
- (void) dladm_walk(show_link, &state);
+ state.ls_parseable = p_arg;
+ state.ls_flags = flags;
+ state.ls_donefirst = B_FALSE;
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_link, &state,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
} else {
- show_link(&state, name);
+ (void) show_link(linkid, &state);
+ if (state.ls_status != DLADM_STATUS_OK) {
+ die_dlerr(state.ls_status, "failed to show link %s",
+ argv[optind]);
+ }
}
}
static void
do_show_aggr(int argc, char *argv[])
{
- int option;
- int key = 0;
boolean_t L_arg = B_FALSE;
boolean_t s_arg = B_FALSE;
boolean_t i_arg = B_FALSE;
+ boolean_t p_arg = B_FALSE;
+ boolean_t x_arg = B_FALSE;
show_grp_state_t state;
+ uint32_t flags = DLADM_OPT_ACTIVE;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ int option;
int interval = 0;
-
- state.gs_stats = B_FALSE;
- state.gs_lacp = B_FALSE;
- state.gs_parseable = B_FALSE;
+ int key;
+ dladm_status_t status;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":Lpsi:",
- longopts, NULL)) != -1) {
+ while ((option = getopt_long(argc, argv, ":LpPxsi:",
+ show_lopts, NULL)) != -1) {
switch (option) {
case 'L':
if (L_arg)
die_optdup(option);
- if (s_arg || i_arg) {
- die("the option -L cannot be used with -i "
- "or -s");
- }
-
L_arg = B_TRUE;
- state.gs_lacp = B_TRUE;
break;
case 'p':
- state.gs_parseable = B_TRUE;
+ if (p_arg)
+ die_optdup(option);
+
+ p_arg = B_TRUE;
+ break;
+ case 'x':
+ if (x_arg)
+ die_optdup(option);
+
+ x_arg = B_TRUE;
+ break;
+ case 'P':
+ if (flags != DLADM_OPT_ACTIVE)
+ die_optdup(option);
+
+ flags = DLADM_OPT_PERSIST;
break;
case 's':
if (s_arg)
die_optdup(option);
- if (L_arg)
- die("the option -s cannot be used with -L");
-
s_arg = B_TRUE;
break;
case 'i':
if (i_arg)
die_optdup(option);
- if (L_arg)
- die("the option -i cannot be used with -L");
-
i_arg = B_TRUE;
if (!str2int(optarg, &interval) || interval == 0)
die("invalid interval value '%s'", optarg);
@@ -1220,26 +1971,56 @@ do_show_aggr(int argc, char *argv[])
if (i_arg && !s_arg)
die("the option -i can be used only with -s");
- /* get aggregation key (optional last argument) */
+ if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
+ die("the option -%c cannot be used with -s",
+ L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
+ }
+
+ if (L_arg && flags != DLADM_OPT_ACTIVE)
+ die("the option -P cannot be used with -L");
+
+ if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
+ die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
+
+ /* get aggregation key or aggrname (optional last argument) */
if (optind == (argc-1)) {
- if (!str2int(argv[optind], &key) || key < 1)
- die("invalid key value '%s'", argv[optind]);
+ if (!str2int(argv[optind], &key)) {
+ status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL);
+ } else {
+ status = dladm_key2linkid((uint16_t)key,
+ &linkid, DLADM_OPT_ACTIVE);
+ }
+
+ if (status != DLADM_STATUS_OK)
+ die("non-existent aggregation '%s'", argv[optind]);
+
} else if (optind != argc) {
usage();
}
+ bzero(&state, sizeof (state));
+ state.gs_lacp = L_arg;
+ state.gs_stats = s_arg;
+ state.gs_flags = flags;
+ state.gs_parseable = p_arg;
+ state.gs_extended = x_arg;
+
if (s_arg) {
- aggr_stats(key, interval);
+ aggr_stats(linkid, &state, interval);
return;
}
- state.gs_key = key;
- state.gs_found = B_FALSE;
-
- (void) dladm_aggr_walk(show_key, &state);
-
- if (key != 0 && !state.gs_found)
- die("non-existent aggregation key '%u'", key);
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_aggr, &state,
+ DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
+ } else {
+ (void) show_aggr(linkid, &state);
+ if (state.gs_status != DLADM_STATUS_OK) {
+ die_dlerr(state.gs_status, "failed to show aggr %s",
+ argv[optind]);
+ }
+ }
}
static void
@@ -1249,17 +2030,20 @@ do_show_dev(int argc, char *argv[])
char *dev = NULL;
boolean_t s_arg = B_FALSE;
boolean_t i_arg = B_FALSE;
+ boolean_t p_arg = B_FALSE;
+ datalink_id_t linkid;
int interval = 0;
- show_mac_state_t state;
-
- state.ms_parseable = B_FALSE;
+ show_state_t state;
opterr = 0;
while ((option = getopt_long(argc, argv, ":psi:",
- longopts, NULL)) != -1) {
+ show_lopts, NULL)) != -1) {
switch (option) {
case 'p':
- state.ms_parseable = B_TRUE;
+ if (p_arg)
+ die_optdup(option);
+
+ p_arg = B_TRUE;
break;
case 's':
if (s_arg)
@@ -1284,26 +2068,25 @@ do_show_dev(int argc, char *argv[])
if (i_arg && !s_arg)
die("the option -i can be used only with -s");
+ if (s_arg && p_arg)
+ die("the option -s cannot be used with -p");
+
/* get dev name (optional last argument) */
- if (optind == (argc-1))
+ if (optind == (argc-1)) {
+ uint32_t flags;
+
dev = argv[optind];
- else if (optind != argc)
- usage();
- if (dev != NULL) {
- uint_t ppa;
- char drv[DLPI_LINKNAME_MAX];
- dladm_attr_t dlattr;
- boolean_t legacy;
+ if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK)
+ die("invalid device %s", dev);
- /*
- * Check for invalid devices.
- * aggregations and vlans are not considered devices.
- */
- if (dlpi_parselink(dev, drv, &ppa) != DLPI_SUCCESS ||
- strcmp(drv, "aggr") == 0 || ppa >= 1000 ||
- get_if_info(dev, &dlattr, &legacy) < 0)
- die("invalid device '%s'", dev);
+ if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL,
+ NULL, 0) != DLADM_STATUS_OK) ||
+ !(flags & DLADM_OPT_ACTIVE)) {
+ die("device %s has been removed", dev);
+ }
+ } else if (optind != argc) {
+ usage();
}
if (s_arg) {
@@ -1311,22 +2094,336 @@ do_show_dev(int argc, char *argv[])
return;
}
- if (dev == NULL)
+ state.ls_donefirst = B_FALSE;
+ state.ls_parseable = p_arg;
+ if (dev == NULL) {
(void) dladm_mac_walk(show_dev, &state);
+ } else {
+ (void) show_dev(dev, &state);
+ }
+}
+
+static void
+print_phys_head(show_state_t *state)
+{
+ if (state->ls_donefirst)
+ return;
+ state->ls_donefirst = B_TRUE;
+
+ if (state->ls_parseable)
+ return;
+
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ (void) printf("%-12s%-20s%-10s%6s %-9s%s\n", "LINK",
+ "MEDIA", "STATE", "SPEED", "DUPLEX", "DEVICE");
+ } else {
+ (void) printf("%-12s%-12s%-20s%s\n", "LINK", "DEVICE",
+ "MEDIA", "FLAGS");
+ }
+}
+
+static dladm_status_t
+print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim)
+{
+ char link[MAXLINKNAMELEN];
+ dladm_phys_attr_t dpa;
+ char buf[DLADM_STRSIZE];
+ uint32_t flags;
+ datalink_class_t class;
+ uint32_t media;
+ dladm_status_t status;
+
+ if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media,
+ link, sizeof (link))) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (class != DATALINK_CLASS_PHYS) {
+ status = DLADM_STATUS_BADARG;
+ goto done;
+ }
+
+ if (!(state->ls_flags & flags)) {
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ status = dladm_phys_info(linkid, &dpa, state->ls_flags);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ if (state->ls_flags == DLADM_OPT_ACTIVE) {
+ char name[MAXLINKNAMELEN];
+ boolean_t islink;
+
+ if (!dpa.dp_novanity) {
+ (void) strlcpy(name, link, sizeof (name));
+ islink = B_TRUE;
+ } else {
+ /*
+ * This is a physical link that does not have
+ * vanity naming support.
+ */
+ (void) strlcpy(name, dpa.dp_dev, sizeof (name));
+ islink = B_FALSE;
+ }
+
+ if (state->ls_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "LINK=\"%s\" MEDIA=\"%s\" ", link,
+ dladm_media2str(media, buf));
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "STATE=\"%s\" SPEED=\"%uMb\" ",
+ get_linkstate(name, islink, buf),
+ (uint_t)((get_ifspeed(name, islink)) / 1000000ull));
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "DUPLEX=\"%s\" DEVICE=\"%s\"\n",
+ get_linkduplex(name, islink, buf), dpa.dp_dev);
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-12s%-20s", link,
+ dladm_media2str(media, buf));
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-10s%4uMb ",
+ get_linkstate(name, islink, buf),
+ (uint_t)((get_ifspeed(name, islink)) / 1000000ull));
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-9s%s\n", get_linkduplex(name, islink, buf),
+ dpa.dp_dev);
+ }
+ } else {
+ if (state->ls_parseable) {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "LINK=\"%s\" DEVICE=\"%s\" MEDIA=\"%s\" "
+ "FLAGS=\"%c----\"\n", link, dpa.dp_dev,
+ dladm_media2str(media, buf),
+ flags & DLADM_OPT_ACTIVE ? '-' : 'r');
+ } else {
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr),
+ "%-12s%-12s%-20s%c----\n", link,
+ dpa.dp_dev, dladm_media2str(media, buf),
+ flags & DLADM_OPT_ACTIVE ? '-' : 'r');
+ }
+ }
+
+done:
+ return (status);
+}
+
+static int
+show_phys(datalink_id_t linkid, void *arg)
+{
+ show_state_t *state = arg;
+ dladm_status_t status;
+ char buf[MAXLINELEN];
+ char *ptr = buf, *lim = buf + MAXLINELEN;
+
+ status = print_phys(state, linkid, &ptr, lim);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ print_phys_head(state);
+ (void) printf("%s", buf);
+
+done:
+ state->ls_status = status;
+ return (DLADM_WALK_CONTINUE);
+}
+
+static void
+print_vlan_head(show_state_t *state)
+{
+ if (state->ls_donefirst)
+ return;
+ state->ls_donefirst = B_TRUE;
+
+ if (state->ls_parseable)
+ return;
+
+ (void) printf("%-12s%5s %-12s%s\n", "LINK", "VID", "OVER", "FLAGS");
+}
+
+/*
+ * Print the active topology information.
+ */
+static dladm_status_t
+print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim)
+{
+ char link[MAXLINKNAMELEN];
+ char over[MAXLINKNAMELEN];
+ char *fmt;
+ dladm_vlan_attr_t vinfo;
+ uint32_t flags;
+ dladm_status_t status;
+
+ if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link,
+ sizeof (link))) != DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (!(state->ls_flags & flags)) {
+ status = DLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) !=
+ DLADM_STATUS_OK || (status = dladm_datalink_id2info(
+ vinfo.dv_linkid, NULL, NULL, NULL, over, sizeof (over))) !=
+ DLADM_STATUS_OK) {
+ goto done;
+ }
+
+ if (state->ls_parseable)
+ fmt = "LINK=\"%s\" VID=\"%d\" OVER=\"%s\" FLAGS=\"%c%c---\"\n";
else
- show_dev(&state, dev);
+ fmt = "%-12s%5d %-12s%c%c---\n";
+ /*LINTED: E_SEC_PRINTF_VAR_FMT*/
+ *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link,
+ vinfo.dv_vid, over, vinfo.dv_force ? 'f' : '-',
+ vinfo.dv_implicit ? 'i' : '-');
+
+done:
+ return (status);
+}
+
+static int
+show_vlan(datalink_id_t linkid, void *arg)
+{
+ show_state_t *state = arg;
+ dladm_status_t status;
+ char buf[MAXLINELEN];
+ char *ptr = buf, *lim = buf + MAXLINELEN;
+
+ status = print_vlan(state, linkid, &ptr, lim);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ print_vlan_head(state);
+ (void) printf("%s", buf);
+
+done:
+ state->ls_status = status;
+ return (DLADM_WALK_CONTINUE);
+}
+
+static void
+do_show_phys(int argc, char *argv[])
+{
+ int option;
+ uint32_t flags = DLADM_OPT_ACTIVE;
+ boolean_t p_arg = B_FALSE;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ show_state_t state;
+ dladm_status_t status;
+
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":pP",
+ show_lopts, NULL)) != -1) {
+ switch (option) {
+ case 'p':
+ if (p_arg)
+ die_optdup(option);
+
+ p_arg = B_TRUE;
+ break;
+ case 'P':
+ if (flags != DLADM_OPT_ACTIVE)
+ die_optdup(option);
+
+ flags = DLADM_OPT_PERSIST;
+ break;
+ default:
+ die_opterr(optopt, option);
+ break;
+ }
+ }
+
+ /* get link name (optional last argument) */
+ if (optind == (argc-1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
+ usage();
+ }
+
+ state.ls_parseable = p_arg;
+ state.ls_flags = flags;
+ state.ls_donefirst = B_FALSE;
+
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_phys, &state,
+ DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
+ } else {
+ (void) show_phys(linkid, &state);
+ if (state.ls_status != DLADM_STATUS_OK) {
+ die_dlerr(state.ls_status,
+ "failed to show physical link %s", argv[optind]);
+ }
+ }
}
-/* ARGSUSED */
static void
-link_stats(const char *link, uint_t interval)
+do_show_vlan(int argc, char *argv[])
{
- dladm_attr_t dlattr;
- boolean_t legacy;
- show_link_state_t state;
+ int option;
+ uint32_t flags = DLADM_OPT_ACTIVE;
+ boolean_t p_arg = B_FALSE;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ show_state_t state;
+ dladm_status_t status;
- if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0)
- die("invalid link '%s'", link);
+ opterr = 0;
+ while ((option = getopt_long(argc, argv, ":pP",
+ show_lopts, NULL)) != -1) {
+ switch (option) {
+ case 'p':
+ if (p_arg)
+ die_optdup(option);
+
+ p_arg = B_TRUE;
+ break;
+ case 'P':
+ if (flags != DLADM_OPT_ACTIVE)
+ die_optdup(option);
+
+ flags = DLADM_OPT_PERSIST;
+ break;
+ default:
+ die_opterr(optopt, option);
+ break;
+ }
+ }
+
+ /* get link name (optional last argument) */
+ if (optind == (argc-1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
+ usage();
+ }
+
+ state.ls_parseable = p_arg;
+ state.ls_flags = flags;
+ state.ls_donefirst = B_FALSE;
+
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_vlan, &state,
+ DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
+ } else {
+ (void) show_vlan(linkid, &state);
+ if (state.ls_status != DLADM_STATUS_OK) {
+ die_dlerr(state.ls_status, "failed to show vlan %s",
+ argv[optind]);
+ }
+ }
+}
+
+static void
+link_stats(datalink_id_t linkid, uint_t interval)
+{
+ show_state_t state;
bzero(&state, sizeof (state));
@@ -1337,14 +2434,18 @@ link_stats(const char *link, uint_t interval)
state.ls_firstonly = (interval != 0);
for (;;) {
- (void) printf("\t\tipackets rbytes ierrors ");
- (void) printf("opackets obytes oerrors\n");
+ (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n",
+ "LINK", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS",
+ "OBYTES", "OERRORS");
state.ls_donefirst = B_FALSE;
- if (link == NULL)
- (void) dladm_walk(show_link_stats, &state);
- else
- show_link_stats(&state, link);
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_link_stats, &state,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE);
+ } else {
+ (void) show_link_stats(linkid, &state);
+ }
if (interval == 0)
break;
@@ -1353,27 +2454,28 @@ link_stats(const char *link, uint_t interval)
}
}
-/* ARGSUSED */
static void
-aggr_stats(uint32_t key, uint_t interval)
+aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
{
- show_grp_state_t state;
-
- bzero(&state, sizeof (state));
- state.gs_stats = B_TRUE;
- state.gs_key = key;
-
/*
* If an interval is specified, continuously show the stats
* only for the first group.
*/
- state.gs_firstonly = (interval != 0);
+ state->gs_firstonly = (interval != 0);
for (;;) {
- state.gs_found = B_FALSE;
- (void) dladm_aggr_walk(show_key, &state);
- if (state.gs_key != 0 && !state.gs_found)
- die("non-existent aggregation key '%u'", key);
+
+ (void) printf("%-12s%-10s%8s %8s %8s %8s %-9s%s\n",
+ "LINK", "PORT", "IPACKETS", "RBYTES", "OPACKETS",
+ "OBYTES", "IPKTDIST", "OPKTDIST");
+
+ state->gs_donefirst = B_FALSE;
+ if (linkid == DATALINK_ALL_LINKID)
+ (void) dladm_walk_datalink_id(show_aggr, state,
+ DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE);
+ else
+ (void) show_aggr(linkid, state);
if (interval == 0)
break;
@@ -1382,11 +2484,10 @@ aggr_stats(uint32_t key, uint_t interval)
}
}
-/* ARGSUSED */
static void
dev_stats(const char *dev, uint32_t interval)
{
- show_mac_state_t state;
+ show_state_t state;
bzero(&state, sizeof (state));
@@ -1394,24 +2495,28 @@ dev_stats(const char *dev, uint32_t interval)
* If an interval is specified, continuously show the stats
* only for the first MAC port.
*/
- state.ms_firstonly = (interval != 0);
+ state.ls_firstonly = (interval != 0);
for (;;) {
- (void) printf("\t\tipackets rbytes ierrors ");
- (void) printf("opackets obytes oerrors\n");
+ (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n",
+ "DEV", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS",
+ "OBYTES", "OERRORS");
- state.ms_donefirst = B_FALSE;
+ state.ls_donefirst = B_FALSE;
if (dev == NULL)
(void) dladm_mac_walk(show_dev_stats, &state);
else
- show_dev_stats(&state, dev);
+ (void) show_dev_stats(dev, &state);
if (interval == 0)
break;
(void) sleep(interval);
}
+
+ if (dev != NULL && state.ls_status != DLADM_STATUS_OK)
+ die_dlerr(state.ls_status, "cannot show device '%s'", dev);
}
/* accumulate stats (s1 += (s2 - s3)) */
@@ -1438,16 +2543,8 @@ stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
s1->oerrors = s2->oerrors - s3->oerrors;
}
-/*
- * In the following routines, we do the first kstat_lookup() assuming that
- * the device is gldv3-based and that the kstat name is the one passed in
- * as the "name" argument. If the lookup fails, we redo the kstat_lookup()
- * omitting the kstat name. This second lookup is needed for getting kstats
- * from legacy devices. This can fail too if the device is not attached or
- * the device is legacy and doesn't export the kstats we need.
- */
static void
-get_stats(char *module, int instance, char *name, pktsum_t *stats)
+get_stats(char *module, int instance, const char *name, pktsum_t *stats)
{
kstat_ctl_t *kcp;
kstat_t *ksp;
@@ -1457,8 +2554,7 @@ get_stats(char *module, int instance, char *name, pktsum_t *stats)
return;
}
- if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL &&
- (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
+ if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
/*
* The kstat query could fail if the underlying MAC
* driver was already detached.
@@ -1494,56 +2590,45 @@ get_stats(char *module, int instance, char *name, pktsum_t *stats)
&stats->oerrors) < 0)
goto bail;
+bail:
(void) kstat_close(kcp);
return;
-bail:
- (void) kstat_close(kcp);
}
static void
get_mac_stats(const char *dev, pktsum_t *stats)
{
- char module[DLPI_LINKNAME_MAX];
- uint_t instance;
+ char module[DLPI_LINKNAME_MAX];
+ uint_t instance;
+ bzero(stats, sizeof (*stats));
if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
return;
- bzero(stats, sizeof (*stats));
+
get_stats(module, instance, "mac", stats);
}
static void
get_link_stats(const char *link, pktsum_t *stats)
{
- char module[DLPI_LINKNAME_MAX];
- uint_t instance;
-
- if (dlpi_parselink(link, module, &instance) != DLPI_SUCCESS)
- return;
bzero(stats, sizeof (*stats));
- get_stats(module, instance, (char *)link, stats);
+ get_stats("link", 0, link, stats);
}
static int
-get_single_mac_stat(const char *dev, const char *name, uint8_t type,
- void *val)
+query_kstat(char *module, int instance, const char *name, const char *stat,
+ uint8_t type, void *val)
{
- char module[DLPI_LINKNAME_MAX];
- uint_t instance;
kstat_ctl_t *kcp;
kstat_t *ksp;
- if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
- return (-1);
-
if ((kcp = kstat_open()) == NULL) {
warn("kstat open operation failed");
return (-1);
}
- if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
- (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) {
+ if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
/*
* The kstat query could fail if the underlying MAC
* driver was already detached.
@@ -1556,7 +2641,7 @@ get_single_mac_stat(const char *dev, const char *name, uint8_t type,
goto bail;
}
- if (kstat_value(ksp, name, type, val) < 0)
+ if (kstat_value(ksp, stat, type, val) < 0)
goto bail;
(void) kstat_close(kcp);
@@ -1567,41 +2652,59 @@ bail:
return (-1);
}
+static int
+get_one_kstat(const char *name, const char *stat, uint8_t type,
+ void *val, boolean_t islink)
+{
+ char module[DLPI_LINKNAME_MAX];
+ uint_t instance;
+
+ if (islink) {
+ return (query_kstat("link", 0, name, stat, type, val));
+ } else {
+ if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
+ return (-1);
+
+ return (query_kstat(module, instance, "mac", stat, type, val));
+ }
+}
+
static uint64_t
-mac_ifspeed(const char *dev)
+get_ifspeed(const char *name, boolean_t islink)
{
uint64_t ifspeed = 0;
- (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed);
+ (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
+ &ifspeed, islink);
+
return (ifspeed);
}
static const char *
-mac_link_state(const char *dev, char *buf)
+get_linkstate(const char *name, boolean_t islink, char *buf)
{
- link_state_t link_state;
+ link_state_t linkstate;
- if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32,
- &link_state) != 0) {
+ if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32,
+ &linkstate, islink) != 0) {
(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
return (buf);
}
-
- return (dladm_linkstate2str(link_state, buf));
+ return (dladm_linkstate2str(linkstate, buf));
}
static const char *
-mac_link_duplex(const char *dev, char *buf)
+get_linkduplex(const char *name, boolean_t islink, char *buf)
{
- link_duplex_t link_duplex;
+ link_duplex_t linkduplex;
- if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32,
- &link_duplex) != 0) {
+ if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32,
+ &linkduplex, islink) != 0) {
(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
return (buf);
}
- return (dladm_linkduplex2str(link_duplex, buf));
+ return (dladm_linkduplex2str(linkduplex, buf));
}
#define WIFI_CMD_SCAN 0x00000001
@@ -1616,17 +2719,17 @@ typedef struct wifi_field {
} wifi_field_t;
static wifi_field_t wifi_fields[] = {
-{ "link", "LINK", 10, 0, WIFI_CMD_ALL},
+{ "link", "LINK", 10, 0, WIFI_CMD_ALL},
{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL},
{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL},
{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL},
{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL},
{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL},
{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW},
-{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
-{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
-{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
-{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
+{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL},
+{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL},
+{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW},
+{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}}
;
static char *all_scan_wifi_fields =
@@ -1751,7 +2854,7 @@ fail:
}
typedef struct print_wifi_state {
- const char *ws_link;
+ char *ws_link;
boolean_t ws_parseable;
boolean_t ws_header;
wifi_field_t **ws_fields;
@@ -1877,18 +2980,24 @@ print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
return (B_TRUE);
}
-static boolean_t
-scan_wifi(void *arg, const char *link)
+static int
+scan_wifi(datalink_id_t linkid, void *arg)
{
print_wifi_state_t *statep = arg;
dladm_status_t status;
+ char link[MAXLINKNAMELEN];
+
+ if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
+ sizeof (link)) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
statep->ws_link = link;
- status = dladm_wlan_scan(link, statep, print_scan_results);
+ status = dladm_wlan_scan(linkid, statep, print_scan_results);
if (status != DLADM_STATUS_OK)
- die_dlerr(status, "cannot scan link '%s'", link);
+ die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
}
static void
@@ -1907,17 +3016,25 @@ print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp,
print_wlan_attr(statep, wfp, &attrp->la_wlan_attr);
}
-static boolean_t
-show_wifi(void *arg, const char *link)
+static int
+show_wifi(datalink_id_t linkid, void *arg)
{
int i;
print_wifi_state_t *statep = arg;
dladm_wlan_linkattr_t attr;
dladm_status_t status;
+ char link[MAXLINKNAMELEN];
+
+ if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
+ sizeof (link)) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
- status = dladm_wlan_get_linkattr(link, &attr);
+ status = dladm_wlan_get_linkattr(linkid, &attr);
if (status != DLADM_STATUS_OK)
- die_dlerr(status, "cannot get link attributes for '%s'", link);
+ die_dlerr(status, "cannot get link attributes for %s", link);
+
+ statep->ws_link = link;
if (statep->ws_header) {
statep->ws_header = B_FALSE;
@@ -1925,14 +3042,13 @@ show_wifi(void *arg, const char *link)
print_wifi_head(statep);
}
- statep->ws_link = link;
statep->ws_overflow = 0;
for (i = 0; i < statep->ws_nfields; i++) {
statep->ws_lastfield = (i + 1 == statep->ws_nfields);
print_link_attr(statep, statep->ws_fields[i], &attr);
}
(void) putchar('\n');
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
}
static void
@@ -1941,9 +3057,10 @@ do_display_wifi(int argc, char **argv, int cmd)
int option;
char *fields_str = NULL;
wifi_field_t **fields;
- boolean_t (*callback)(void *, const char *);
+ int (*callback)(datalink_id_t, void *);
uint_t nfields;
print_wifi_state_t state;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
dladm_status_t status;
if (cmd == WIFI_CMD_SCAN)
@@ -1953,7 +3070,6 @@ do_display_wifi(int argc, char **argv, int cmd)
else
return;
- state.ws_link = NULL;
state.ws_parseable = B_FALSE;
state.ws_header = B_TRUE;
opterr = 0;
@@ -1974,10 +3090,14 @@ do_display_wifi(int argc, char **argv, int cmd)
}
}
- if (optind == (argc - 1))
- state.ws_link = argv[optind];
- else if (optind != argc)
+ if (optind == (argc - 1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
usage();
+ }
if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0)
die("invalid field(s) specified");
@@ -1985,12 +3105,11 @@ do_display_wifi(int argc, char **argv, int cmd)
state.ws_fields = fields;
state.ws_nfields = nfields;
- if (state.ws_link == NULL) {
- status = dladm_wlan_walk(&state, callback);
- if (status != DLADM_STATUS_OK)
- die_dlerr(status, "cannot walk wifi links");
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(callback, &state,
+ DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
} else {
- (void) (*callback)(&state, state.ws_link);
+ (void) (*callback)(linkid, &state);
}
free(fields);
}
@@ -2009,18 +3128,18 @@ do_show_wifi(int argc, char **argv)
typedef struct wlan_count_attr {
uint_t wc_count;
- const char *wc_link;
+ datalink_id_t wc_linkid;
} wlan_count_attr_t;
-static boolean_t
-do_count_wlan(void *arg, const char *link)
+static int
+do_count_wlan(datalink_id_t linkid, void *arg)
{
wlan_count_attr_t *cp = arg;
if (cp->wc_count == 0)
- cp->wc_link = strdup(link);
+ cp->wc_linkid = linkid;
cp->wc_count++;
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
}
static int
@@ -2086,7 +3205,7 @@ do_connect_wifi(int argc, char **argv)
dladm_wlan_attr_t attr, *attrp;
dladm_status_t status = DLADM_STATUS_OK;
int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
- const char *link = NULL;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
dladm_wlan_key_t *keys = NULL;
uint_t key_count = 0;
uint_t flags = 0;
@@ -2186,28 +3305,33 @@ do_connect_wifi(int argc, char **argv)
attr.wa_secmode = keysecmode;
}
- if (optind == (argc - 1))
- link = argv[optind];
- else if (optind != argc)
+ if (optind == (argc - 1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
usage();
+ }
- if (link == NULL) {
+ if (linkid == DATALINK_ALL_LINKID) {
wlan_count_attr_t wcattr;
- wcattr.wc_link = NULL;
+ wcattr.wc_linkid = DATALINK_INVALID_LINKID;
wcattr.wc_count = 0;
- (void) dladm_wlan_walk(&wcattr, do_count_wlan);
+ (void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
+ DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
if (wcattr.wc_count == 0) {
die("no wifi links are available");
} else if (wcattr.wc_count > 1) {
die("link name is required when more than one wifi "
"link is available");
}
- link = wcattr.wc_link;
+ linkid = wcattr.wc_linkid;
}
attrp = (attr.wa_valid == 0) ? NULL : &attr;
again:
- if ((status = dladm_wlan_connect(link, attrp, timeout, keys,
+ if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys,
key_count, flags)) != DLADM_STATUS_OK) {
if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
/*
@@ -2225,29 +3349,29 @@ again:
"criteria are available");
}
}
- die_dlerr(status, "cannot connect link '%s'", link);
+ die_dlerr(status, "cannot connect");
}
free(keys);
}
/* ARGSUSED */
-static boolean_t
-do_all_disconnect_wifi(void *arg, const char *link)
+static int
+do_all_disconnect_wifi(datalink_id_t linkid, void *arg)
{
dladm_status_t status;
- status = dladm_wlan_disconnect(link);
+ status = dladm_wlan_disconnect(linkid);
if (status != DLADM_STATUS_OK)
- warn_dlerr(status, "cannot disconnect link '%s'", link);
+ warn_dlerr(status, "cannot disconnect link");
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
}
static void
do_disconnect_wifi(int argc, char **argv)
{
int option;
- const char *link = NULL;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
boolean_t all_links = B_FALSE;
dladm_status_t status;
wlan_count_attr_t wcattr;
@@ -2265,41 +3389,46 @@ do_disconnect_wifi(int argc, char **argv)
}
}
- if (optind == (argc - 1))
- link = argv[optind];
- else if (optind != argc)
+ if (optind == (argc - 1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
usage();
+ }
- if (link == NULL) {
+ if (linkid == DATALINK_ALL_LINKID) {
if (!all_links) {
- wcattr.wc_link = NULL;
+ wcattr.wc_linkid = linkid;
wcattr.wc_count = 0;
- (void) dladm_wlan_walk(&wcattr, do_count_wlan);
+ (void) dladm_walk_datalink_id(do_count_wlan, &wcattr,
+ DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE);
if (wcattr.wc_count == 0) {
die("no wifi links are available");
} else if (wcattr.wc_count > 1) {
die("link name is required when more than "
"one wifi link is available");
}
- link = wcattr.wc_link;
+ linkid = wcattr.wc_linkid;
} else {
- (void) dladm_wlan_walk(&all_links,
- do_all_disconnect_wifi);
+ (void) dladm_walk_datalink_id(do_all_disconnect_wifi,
+ NULL, DATALINK_CLASS_PHYS, DL_WIFI,
+ DLADM_OPT_ACTIVE);
return;
}
}
- status = dladm_wlan_disconnect(link);
+ status = dladm_wlan_disconnect(linkid);
if (status != DLADM_STATUS_OK)
- die_dlerr(status, "cannot disconnect link '%s'", link);
+ die_dlerr(status, "cannot disconnect");
}
#define MAX_PROPS 32
-#define MAX_PROP_VALS 32
#define MAX_PROP_LINE 512
typedef struct prop_info {
char *pi_name;
- char *pi_val[MAX_PROP_VALS];
+ char *pi_val[DLADM_MAX_PROP_VALCNT];
uint_t pi_count;
} prop_info_t;
@@ -2310,7 +3439,7 @@ typedef struct prop_list {
} prop_list_t;
typedef struct show_linkprop_state {
- const char *ls_link;
+ char ls_link[MAXLINKNAMELEN];
char *ls_line;
char **ls_propvals;
prop_list_t *ls_proplist;
@@ -2364,7 +3493,7 @@ parse_props(char *str, prop_list_t **listp, boolean_t novalues)
}
if (pip != NULL && c != '=') {
- if (pip->pi_count > MAX_PROP_VALS)
+ if (pip->pi_count > DLADM_MAX_PROP_VALCNT)
goto fail;
if (novalues)
@@ -2401,24 +3530,29 @@ print_linkprop_head(void)
}
static void
-print_linkprop(show_linkprop_state_t *statep, const char *propname,
- dladm_prop_type_t type, const char *typename, const char *format,
- char **pptr)
+print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep,
+ const char *propname, dladm_prop_type_t type, const char *typename,
+ const char *format, char **pptr)
{
int i;
char *ptr, *lim;
char buf[DLADM_STRSIZE];
char *unknown = "?", *notsup = "";
char **propvals = statep->ls_propvals;
- uint_t valcnt = MAX_PROP_VALS;
+ uint_t valcnt = DLADM_MAX_PROP_VALCNT;
dladm_status_t status;
- status = dladm_get_prop(statep->ls_link, type, propname,
- propvals, &valcnt);
+ status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt);
if (status != DLADM_STATUS_OK) {
if (status == DLADM_STATUS_TEMPONLY) {
- statep->ls_status = status;
- return;
+ if (type == DLADM_PROP_VAL_MODIFIABLE &&
+ statep->ls_persist) {
+ valcnt = 1;
+ propvals = &unknown;
+ } else {
+ statep->ls_status = status;
+ return;
+ }
} else if (status == DLADM_STATUS_NOTSUP ||
statep->ls_persist) {
valcnt = 1;
@@ -2428,9 +3562,11 @@ print_linkprop(show_linkprop_state_t *statep, const char *propname,
propvals = &notsup;
} else {
statep->ls_status = status;
- warn_dlerr(status,
- "cannot get link property '%s' for %s",
- propname, statep->ls_link);
+ if (statep->ls_proplist) {
+ warn_dlerr(status,
+ "cannot get link property '%s' for %s",
+ propname, statep->ls_link);
+ }
return;
}
}
@@ -2457,8 +3593,8 @@ print_linkprop(show_linkprop_state_t *statep, const char *propname,
}
}
-static boolean_t
-show_linkprop(void *arg, const char *propname)
+static int
+show_linkprop(datalink_id_t linkid, const char *propname, void *arg)
{
show_linkprop_state_t *statep = arg;
char *ptr = statep->ls_line;
@@ -2475,7 +3611,7 @@ show_linkprop(void *arg, const char *propname)
else
ptr += snprintf(ptr, lim - ptr, "%-15s ", propname);
- print_linkprop(statep, propname,
+ print_linkprop(linkid, statep, propname,
statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT :
DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr);
@@ -2485,17 +3621,17 @@ show_linkprop(void *arg, const char *propname)
* skip the output.
*/
if (statep->ls_status != DLADM_STATUS_OK)
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
- print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT,
+ print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_DEFAULT,
"DEFAULT", "%-14s ", &ptr);
if (statep->ls_status != DLADM_STATUS_OK)
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
- print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE,
+ print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_MODIFIABLE,
"POSSIBLE", "%-20s ", &ptr);
if (statep->ls_status != DLADM_STATUS_OK)
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
if (statep->ls_header) {
statep->ls_header = B_FALSE;
@@ -2503,7 +3639,7 @@ show_linkprop(void *arg, const char *propname)
print_linkprop_head();
}
(void) printf("%s\n", statep->ls_line);
- return (B_TRUE);
+ return (DLADM_WALK_CONTINUE);
}
static void
@@ -2511,10 +3647,12 @@ do_show_linkprop(int argc, char **argv)
{
int option;
prop_list_t *proplist = NULL;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
show_linkprop_state_t state;
+ uint32_t flags = DLADM_OPT_ACTIVE;
+ dladm_status_t status;
opterr = 0;
- state.ls_link = NULL;
state.ls_propvals = NULL;
state.ls_line = NULL;
state.ls_parseable = B_FALSE;
@@ -2532,6 +3670,7 @@ do_show_linkprop(int argc, char **argv)
break;
case 'P':
state.ls_persist = B_TRUE;
+ flags = DLADM_OPT_PERSIST;
break;
default:
die_opterr(optopt, option);
@@ -2539,40 +3678,59 @@ do_show_linkprop(int argc, char **argv)
}
}
- if (optind == (argc - 1))
- state.ls_link = argv[optind];
- else if (optind != argc)
+ if (optind == (argc - 1)) {
+ if ((status = dladm_name2info(argv[optind], &linkid, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK) {
+ die_dlerr(status, "link %s is not valid", argv[optind]);
+ }
+ } else if (optind != argc) {
usage();
+ }
state.ls_proplist = proplist;
state.ls_status = DLADM_STATUS_OK;
- if (state.ls_link == NULL) {
- (void) dladm_walk(show_linkprop_onelink, &state);
+ if (linkid == DATALINK_ALL_LINKID) {
+ (void) dladm_walk_datalink_id(show_linkprop_onelink, &state,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
} else {
- show_linkprop_onelink(&state, state.ls_link);
+ (void) show_linkprop_onelink(linkid, &state);
}
free_props(proplist);
- if (state.ls_status != DLADM_STATUS_OK)
+ if (state.ls_status != DLADM_STATUS_OK) {
+ if (optind == (argc - 1)) {
+ warn_dlerr(state.ls_status,
+ "show-linkprop failed for %s", argv[optind]);
+ }
exit(EXIT_FAILURE);
+ }
}
-static void
-show_linkprop_onelink(void *arg, const char *link)
+static int
+show_linkprop_onelink(datalink_id_t linkid, void *arg)
{
int i;
- int retval;
char *buf;
- dladm_status_t status;
+ uint32_t flags;
prop_list_t *proplist = NULL;
- show_linkprop_state_t *statep;
- const char *savep;
- dlpi_handle_t dh;
+ show_linkprop_state_t *statep = arg;
+ dlpi_handle_t dh = NULL;
+
+ statep->ls_status = DLADM_STATUS_OK;
+
+ if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link,
+ MAXLINKNAMELEN) != DLADM_STATUS_OK) {
+ statep->ls_status = DLADM_STATUS_NOTFOUND;
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
+ (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
+ statep->ls_status = DLADM_STATUS_BADARG;
+ return (DLADM_WALK_CONTINUE);
+ }
- statep = (show_linkprop_state_t *)arg;
- savep = statep->ls_link;
- statep->ls_link = link;
proplist = statep->ls_proplist;
/*
@@ -2580,58 +3738,55 @@ show_linkprop_onelink(void *arg, const char *link)
* automatically scans for APs and does other slow operations. Thus,
* if there are no open links, the retrieval of link properties
* (below) will proceed slowly unless we hold the link open.
+ *
+ * Note that failure of dlpi_open() does not necessarily mean invalid
+ * link properties, because dlpi_open() may fail because of incorrect
+ * autopush configuration. Therefore, we ingore the return value of
+ * dlpi_open().
*/
- if ((retval = dlpi_open(link, &dh, 0)) != DLPI_SUCCESS) {
- warn("cannot open %s: %s", link, dlpi_strerror(retval));
- statep->ls_status = DLADM_STATUS_NOTFOUND;
- return;
- }
+ if (!statep->ls_persist)
+ (void) dlpi_open(statep->ls_link, &dh, 0);
- buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
- MAX_PROP_LINE);
+ buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
+ DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
if (buf == NULL)
die("insufficient memory");
statep->ls_propvals = (char **)(void *)buf;
- for (i = 0; i < MAX_PROP_VALS; i++) {
- statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
+ for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
+ statep->ls_propvals[i] = buf +
+ sizeof (char *) * DLADM_MAX_PROP_VALCNT +
i * DLADM_PROP_VAL_MAX;
}
statep->ls_line = buf +
- (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS;
+ (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
if (proplist != NULL) {
- for (i = 0; i < proplist->pl_count; i++)
- (void) show_linkprop(statep,
- proplist->pl_info[i].pi_name);
+ for (i = 0; i < proplist->pl_count; i++) {
+ (void) show_linkprop(linkid,
+ proplist->pl_info[i].pi_name, statep);
+ }
} else {
- status = dladm_walk_prop(link, statep, show_linkprop);
- if (status != DLADM_STATUS_OK)
- warn_dlerr(status, "show-linkprop failed for %s", link);
+ (void) dladm_walk_linkprop(linkid, statep, show_linkprop);
}
- dlpi_close(dh);
+ if (dh != NULL)
+ dlpi_close(dh);
free(buf);
- statep->ls_link = savep;
+ return (DLADM_WALK_CONTINUE);
}
static dladm_status_t
-set_linkprop_persist(const char *link, const char *prop_name, char **prop_val,
- uint_t val_cnt, boolean_t reset)
+set_linkprop_persist(datalink_id_t linkid, const char *prop_name,
+ char **prop_val, uint_t val_cnt, boolean_t reset)
{
dladm_status_t status;
- char *errprop;
- status = dladm_set_prop(link, prop_name, prop_val, val_cnt,
- DLADM_OPT_PERSIST, &errprop);
+ status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt,
+ DLADM_OPT_PERSIST);
if (status != DLADM_STATUS_OK) {
- if (reset) {
- warn_dlerr(status, "cannot persistently reset link "
- "property '%s' on '%s'", errprop, link);
- } else {
- warn_dlerr(status, "cannot persistently set link "
- "property '%s' on '%s'", errprop, link);
- }
+ warn_dlerr(status, "cannot persistently %s link property",
+ reset ? "reset" : "set");
}
return (status);
}
@@ -2641,7 +3796,8 @@ set_linkprop(int argc, char **argv, boolean_t reset)
{
int i, option;
char errmsg[DLADM_STRSIZE];
- const char *link = NULL;
+ char *altroot = NULL;
+ datalink_id_t linkid;
prop_list_t *proplist = NULL;
boolean_t temp = B_FALSE;
dladm_status_t status = DLADM_STATUS_OK;
@@ -2658,11 +3814,7 @@ set_linkprop(int argc, char **argv, boolean_t reset)
temp = B_TRUE;
break;
case 'R':
- status = dladm_set_rootdir(optarg);
- if (status != DLADM_STATUS_OK) {
- die_dlerr(status, "invalid directory "
- "specified");
- }
+ altroot = optarg;
break;
default:
die_opterr(optopt, option);
@@ -2670,30 +3822,32 @@ set_linkprop(int argc, char **argv, boolean_t reset)
}
}
- if (optind == (argc - 1))
- link = argv[optind];
- else if (optind != argc)
+ /* get link name (required last argument) */
+ if (optind != (argc - 1))
usage();
- if (link == NULL)
- die("link name must be specified");
+ if (proplist == NULL && !reset)
+ die("link property must be specified");
- if (proplist == NULL) {
- char *errprop;
+ if (altroot != NULL) {
+ free_props(proplist);
+ altroot_cmd(altroot, argc, argv);
+ }
- if (!reset)
- die("link property must be specified");
+ status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "link %s is not valid", argv[optind]);
- status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP,
- &errprop);
- if (status != DLADM_STATUS_OK) {
- warn_dlerr(status, "cannot reset link property '%s' "
- "on '%s'", errprop, link);
+ if (proplist == NULL) {
+ if ((status = dladm_set_linkprop(linkid, NULL, NULL, 0,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ warn_dlerr(status, "cannot reset link property "
+ "on '%s'", argv[optind]);
}
if (!temp) {
dladm_status_t s;
- s = set_linkprop_persist(link, NULL, NULL, 0, reset);
+ s = set_linkprop_persist(linkid, NULL, NULL, 0, reset);
if (s != DLADM_STATUS_OK)
status = s;
}
@@ -2719,11 +3873,11 @@ set_linkprop(int argc, char **argv, boolean_t reset)
continue;
}
}
- s = dladm_set_prop(link, pip->pi_name, val, count,
- DLADM_OPT_TEMP, NULL);
+ s = dladm_set_linkprop(linkid, pip->pi_name, val, count,
+ DLADM_OPT_ACTIVE);
if (s == DLADM_STATUS_OK) {
if (!temp) {
- s = set_linkprop_persist(link,
+ s = set_linkprop_persist(linkid,
pip->pi_name, val, count, reset);
if (s != DLADM_STATUS_OK)
status = s;
@@ -2739,28 +3893,36 @@ set_linkprop(int argc, char **argv, boolean_t reset)
int j;
char *ptr, *lim;
char **propvals = NULL;
- uint_t valcnt = MAX_PROP_VALS;
+ uint_t valcnt = DLADM_MAX_PROP_VALCNT;
ptr = malloc((sizeof (char *) +
- DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
+ DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
MAX_PROP_LINE);
propvals = (char **)(void *)ptr;
if (propvals == NULL)
die("insufficient memory");
- for (j = 0; j < MAX_PROP_VALS; j++) {
+ for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
propvals[j] = ptr + sizeof (char *) *
- MAX_PROP_VALS +
+ DLADM_MAX_PROP_VALCNT +
j * DLADM_PROP_VAL_MAX;
}
- s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE,
- pip->pi_name, propvals, &valcnt);
+ s = dladm_get_linkprop(linkid,
+ DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals,
+ &valcnt);
+
+ if (s != DLADM_STATUS_OK) {
+ warn_dlerr(status, "cannot set link property "
+ "'%s' on '%s'", pip->pi_name, argv[optind]);
+ free(propvals);
+ break;
+ }
ptr = errmsg;
lim = ptr + DLADM_STRSIZE;
*ptr = '\0';
- for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
+ for (j = 0; j < valcnt; j++) {
ptr += snprintf(ptr, lim - ptr, "%s,",
propvals[j]);
if (ptr >= lim)
@@ -2778,10 +3940,10 @@ set_linkprop(int argc, char **argv, boolean_t reset)
default:
if (reset) {
warn_dlerr(status, "cannot reset link property "
- "'%s' on '%s'", pip->pi_name, link);
+ "'%s' on '%s'", pip->pi_name, argv[optind]);
} else {
warn_dlerr(status, "cannot set link property "
- "'%s' on '%s'", pip->pi_name, link);
+ "'%s' on '%s'", pip->pi_name, argv[optind]);
}
break;
}
@@ -3097,7 +4259,7 @@ do_create_secobj(int argc, char **argv)
}
status = dladm_set_secobj(obj_name, class, obj_val, obj_len,
- DLADM_OPT_CREATE | DLADM_OPT_TEMP);
+ DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK) {
die_dlerr(status, "could not create secure object '%s'",
obj_name);
@@ -3161,7 +4323,7 @@ do_delete_secobj(int argc, char **argv)
die("authorization '%s' is required", LINK_SEC_AUTH);
for (i = 0; i < sp->s_nfields; i++) {
- status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP);
+ status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE);
if (!temp) {
pstatus = dladm_unset_secobj(sp->s_fields[i],
DLADM_OPT_PERSIST);
@@ -3301,15 +4463,24 @@ do_show_secobj(int argc, char **argv)
die_dlerr(status, "show-secobj");
}
+/*ARGSUSED*/
+static int
+i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
+{
+ (void) dladm_init_linkprop(linkid);
+ return (DLADM_WALK_CONTINUE);
+}
+
/* ARGSUSED */
static void
do_init_linkprop(int argc, char **argv)
{
- dladm_status_t status;
-
- status = dladm_init_linkprop();
- if (status != DLADM_STATUS_OK)
- die_dlerr(status, "link property initialization failed");
+ /*
+ * linkprops of links of other classes have been initialized as a
+ * part of the dladm up-xxx operation.
+ */
+ (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
+ DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
}
/* ARGSUSED */
@@ -3323,6 +4494,68 @@ do_init_secobj(int argc, char **argv)
die_dlerr(status, "secure object initialization failed");
}
+/*
+ * "-R" option support. It is used for live upgrading. Append dladm commands
+ * to a upgrade script which will be run when the alternative root boots up:
+ *
+ * - If the dlmgmtd door file exists on the alternative root, append dladm
+ * commands to the <altroot>/var/svc/profile/upgrade_datalink script. This
+ * script will be run as part of the network/physical service. We cannot defer
+ * this to /var/svc/profile/upgrade because then the configuration will not
+ * be able to take effect before network/physical plumbs various interfaces.
+ *
+ * - If the dlmgmtd door file does not exist on the alternative root, append
+ * dladm commands to the <altroot>/var/svc/profile/upgrade script, which will
+ * be run in the manifest-import service.
+ *
+ * Note that the SMF team is considering to move the manifest-import service
+ * to be run at the very begining of boot. Once that is done, the need for
+ * the /var/svc/profile/upgrade_datalink script will not exist any more.
+ */
+static void
+altroot_cmd(char *altroot, int argc, char *argv[])
+{
+ char path[MAXPATHLEN];
+ struct stat stbuf;
+ FILE *fp;
+ int i;
+
+ /*
+ * Check for the existence of the dlmgmtd door file, and determine
+ * the name of script file.
+ */
+ (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, DLMGMT_DOOR);
+ if (stat(path, &stbuf) < 0) {
+ (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
+ SMF_UPGRADE_FILE);
+ } else {
+ (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot,
+ SMF_UPGRADEDATALINK_FILE);
+ }
+
+ if ((fp = fopen(path, "a+")) == NULL)
+ die("operation not supported on %s", altroot);
+
+ (void) fprintf(fp, "/sbin/dladm ");
+ for (i = 0; i < argc; i++) {
+ /*
+ * Directly write to the file if it is not the "-R <altroot>"
+ * option. In which case, skip it.
+ */
+ if (strcmp(argv[i], "-R") != 0)
+ (void) fprintf(fp, "%s ", argv[i]);
+ else
+ i ++;
+ }
+ (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG);
+ (void) fclose(fp);
+ exit(0);
+}
+
+/*
+ * Convert the string to an integer. Note that the string must not have any
+ * trailing non-integer characters.
+ */
static boolean_t
str2int(const char *str, int *valp)
{
diff --git a/usr/src/cmd/dladm/dladm.xcl b/usr/src/cmd/dladm/dladm.xcl
index 1f47d2c1ac..c48e5d4bbb 100644
--- a/usr/src/cmd/dladm/dladm.xcl
+++ b/usr/src/cmd/dladm/dladm.xcl
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -131,8 +131,11 @@ msgid "connect-wifi"
msgid "create-aggr"
msgid "create-ibss"
msgid "create-secobj"
+msgid "create-vlan"
msgid "delete-aggr"
+msgid "delete-phys"
msgid "delete-secobj"
+msgid "delete-vlan"
msgid "dev key=%d"
msgid "dev"
msgid "disconnect-wifi"
@@ -180,6 +183,7 @@ msgid "prop"
msgid "r"
msgid "rbytes64"
msgid "remove-aggr"
+msgid "rename-link"
msgid "reset-linkprop"
msgid "root-dir"
msgid "scan-wifi"
@@ -190,8 +194,10 @@ msgid "show-aggr"
msgid "show-dev"
msgid "show-link"
msgid "show-linkprop"
+msgid "show-phys"
msgid "show-secobj"
msgid "show-wifi"
+msgid "show-vlan"
msgid "solaris.network.link.security"
msgid "speed"
msgid "standby"
@@ -204,6 +210,7 @@ msgid "unicast"
msgid "unknown"
msgid "up"
msgid "up-aggr"
+msgid "up-vlan"
msgid "vlan-id"
msgid "wep"
msgid "yes"
diff --git a/usr/src/cmd/dlmgmtd/Makefile b/usr/src/cmd/dlmgmtd/Makefile
new file mode 100644
index 0000000000..0c78f21e5e
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/Makefile
@@ -0,0 +1,77 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= dlmgmtd
+OBJS= dlmgmt_main.o dlmgmt_door.o dlmgmt_util.o dlmgmt_db.o
+SRCS= $(OBJS:.o=.c)
+SVCMETHOD= svc-dlmgmtd
+MANIFEST= dlmgmt.xml
+DOOR= .dlmgmt_door
+CFGFILES= datalink.conf
+
+include ../Makefile.cmd
+
+ROOTMANIFESTDIR= $(ROOTSVCNETWORK)
+ROOTETCDOOR= $(DOOR:%=$(ROOTETC)/%)
+$(ROOTETCDOOR) := FILEMODE = 444
+ROOTCFGDIR= $(ROOTETC)/dladm
+ROOTCFGFILES= $(CFGFILES:%=$(ROOTCFGDIR)/%)
+
+$(ROOTCFGFILES) := OWNER= dladm
+$(ROOTCFGFILES) := GROUP= sys
+$(ROOTCFGDIR)/datalink.conf := FILEMODE= 644
+
+LDLIBS += -ldladm -ldlpi -lavl
+
+.KEEP_STATE:
+
+all: $(PROG) $(DOOR)
+
+$(DOOR):
+ $(TOUCH) $(DOOR)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTSBINPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTETCDOOR) \
+ $(ROOTCFGDIR) $(ROOTCFGFILES)
+
+check: $(CHKMANIFEST)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+$(ROOTCFGDIR):
+ $(INS.dir)
+
+$(ROOTCFGDIR)/%: $(ROOTCFGDIR) %
+ $(INS.file)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/dladm/linkprop.conf b/usr/src/cmd/dlmgmtd/datalink.conf
index dd196c1273..91c9931ff3 100644
--- a/usr/src/cmd/dladm/linkprop.conf
+++ b/usr/src/cmd/dlmgmtd/datalink.conf
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt.xml b/usr/src/cmd/dlmgmtd/dlmgmt.xml
new file mode 100644
index 0000000000..e0781a8d8b
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ 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
+ or http://www.opensolaris.org/os/licensing.
+ 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 2008 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:dlmgmtd'>
+
+<service
+ name='network/datalink-management'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance/>
+
+ <dependent name='dlmgmt-install-discovery'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/install-discovery' />
+ </dependent>
+
+ <dependent name='dlmgmt-device-system'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/device/local' />
+ </dependent>
+
+ <dependent name='dlmgmt-network-physical'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/physical' />
+ </dependent>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/svc-dlmgmtd'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='3' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'> data-link management daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='dlmgmtd' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_db.c b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
new file mode 100644
index 0000000000..e65fda35d2
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
@@ -0,0 +1,949 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "dlmgmt_impl.h"
+
+typedef enum dlmgmt_db_op {
+ DLMGMT_DB_OP_WRITE,
+ DLMGMT_DB_OP_DELETE,
+ DLMGMT_DB_OP_READ
+} dlmgmt_db_op_t;
+
+typedef struct dlmgmt_db_req_s {
+ struct dlmgmt_db_req_s *ls_next;
+ dlmgmt_db_op_t ls_op;
+ datalink_id_t ls_linkid;
+ uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */
+ /* DLMGMT_PERSIST, not both. */
+} dlmgmt_db_req_t;
+
+/*
+ * List of pending db updates (e.g., because of a read-only filesystem).
+ */
+static dlmgmt_db_req_t *dlmgmt_db_req_head = NULL;
+static dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL;
+
+static int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t,
+ uint32_t);
+static int dlmgmt_process_db_req(dlmgmt_db_req_t *);
+static int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t);
+static void *dlmgmt_db_update_thread(void *);
+static boolean_t process_link_line(char *, dlmgmt_link_t **);
+static int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *);
+static int process_db_read(dlmgmt_db_req_t *, FILE *, FILE *);
+static void generate_link_line(dlmgmt_link_t *, boolean_t, char *);
+
+#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
+#define MAXLINELEN 1024
+
+/*
+ * Translator functions to go from dladm_datatype_t to character strings.
+ * Each function takes a pointer to a buffer, the size of the buffer,
+ * the name of the attribute, and the value to be written. The functions
+ * return the number of bytes written to the buffer. If the buffer is not big
+ * enough to hold the string representing the value, then nothing is written
+ * and 0 is returned.
+ */
+typedef size_t write_func_t(char *, size_t, char *, void *);
+
+/*
+ * Translator functions to read from a NULL terminated string buffer into
+ * something of the given DLADM_TYPE_*. The functions each return the number
+ * of bytes read from the string buffer. If there is an error reading data
+ * from the buffer, then 0 is returned. It is the caller's responsibility
+ * to free the data allocated by these functions.
+ */
+typedef size_t read_func_t(char *, void **);
+
+typedef struct translator_s {
+ const char *type_name;
+ write_func_t *write_func;
+ read_func_t *read_func;
+} translator_t;
+
+/*
+ * Translator functions, defined later but declared here so that
+ * the translator table can be defined.
+ */
+static write_func_t write_str, write_boolean, write_uint64;
+static read_func_t read_str, read_boolean, read_int64;
+
+/*
+ * Translator table, indexed by dladm_datatype_t.
+ */
+static translator_t translators[] = {
+ { "string", write_str, read_str },
+ { "boolean", write_boolean, read_boolean },
+ { "int", write_uint64, read_int64 }
+};
+
+static size_t ntranslators = sizeof (translators) / sizeof (translator_t);
+
+#define LINK_PROPERTY_DELIMINATOR ";"
+#define LINK_PROPERTY_TYPE_VALUE_SEP ","
+#define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\
+ strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\
+ strlen(LINK_PROPERTY_DELIMINATOR) +\
+ strlen((n)))
+#define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \
+ (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \
+ translators[(type)].type_name, \
+ LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR))
+
+#define DLMGMT_DB_OWNER 15
+#define DLMGMT_DB_GROUP 3
+
+/*
+ * Name of the cache file to keep the active <link name, linkid> mapping
+ */
+static char cachefile[MAXPATHLEN];
+
+#define DLMGMT_TEMP_DB_DIR "/etc/svc/volatile"
+#define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
+#define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \
+ (void) snprintf((buffer), MAXPATHLEN, "%s", \
+ (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile);
+
+static size_t
+write_str(char *buffer, size_t buffer_length, char *name, void *value)
+{
+ char *ptr = value;
+ size_t data_length = strnlen(ptr, buffer_length);
+
+ /*
+ * Strings are assumed to be NULL terminated. In order to fit in
+ * the buffer, the string's length must be less then buffer_length.
+ * If the value is empty, there's no point in writing it, in fact,
+ * we shouldn't even see that case.
+ */
+ if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) ==
+ buffer_length || data_length == 0)
+ return (0);
+
+ /*
+ * Since we know the string will fit in the buffer, snprintf will
+ * always return less than buffer_length, so we can just return
+ * whatever snprintf returns.
+ */
+ return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s",
+ name, DLADM_TYPE_STR, ptr));
+}
+
+static size_t
+write_boolean(char *buffer, size_t buffer_length, char *name, void *value)
+{
+ boolean_t *ptr = value;
+
+ /*
+ * Booleans are either zero or one, so we only need room for two
+ * characters in the buffer.
+ */
+ if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name))
+ return (0);
+
+ return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d",
+ name, DLADM_TYPE_BOOLEAN, *ptr));
+}
+
+static size_t
+write_uint64(char *buffer, size_t buffer_length, char *name, void *value)
+{
+ uint64_t *ptr = value;
+
+ /*
+ * Limit checking for uint64_t is a little trickier.
+ */
+ if (snprintf(NULL, 0, "%lld", *ptr) +
+ BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length)
+ return (0);
+
+ return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld",
+ name, DLADM_TYPE_UINT64, *ptr));
+}
+
+static size_t
+read_str(char *buffer, void **value)
+{
+ char *ptr = calloc(MAXLINKATTRLEN, sizeof (char));
+ ssize_t len;
+
+ if (ptr == NULL || (len = snprintf(ptr, MAXLINKATTRLEN, "%s", buffer))
+ >= MAXLINKATTRLEN) {
+ free(ptr);
+ return (0);
+ }
+
+ *(char **)value = ptr;
+
+ /* Account for NULL terminator */
+ return (len + 1);
+}
+
+static size_t
+read_boolean(char *buffer, void **value)
+{
+ boolean_t *ptr = calloc(1, sizeof (boolean_t));
+
+ if (ptr == NULL)
+ return (0);
+
+ *ptr = atoi(buffer);
+ *(boolean_t **)value = ptr;
+
+ return (sizeof (boolean_t));
+}
+
+static size_t
+read_int64(char *buffer, void **value)
+{
+ int64_t *ptr = calloc(1, sizeof (int64_t));
+
+ if (ptr == NULL)
+ return (0);
+
+ *ptr = (int64_t)atoll(buffer);
+ *(int64_t **)value = ptr;
+
+ return (sizeof (int64_t));
+}
+
+static int
+dlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags)
+{
+ dlmgmt_db_req_t *req;
+ int err;
+
+ /*
+ * It is either a persistent request or an active request, not both.
+ */
+ assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
+
+ if ((req = malloc(sizeof (dlmgmt_db_req_t))) == NULL)
+ return (ENOMEM);
+
+ req->ls_next = NULL;
+ req->ls_op = op;
+ req->ls_linkid = linkid;
+ req->ls_flags = flags;
+
+ /*
+ * If the return error is EINPROGRESS, this request is handled
+ * asynchronously; return success.
+ */
+ err = dlmgmt_process_db_req(req);
+ if (err != EINPROGRESS)
+ free(req);
+ else
+ err = 0;
+ return (err);
+}
+
+#define DLMGMT_DB_OP_STR(op) \
+ (((op) == DLMGMT_DB_OP_READ) ? "read" : \
+ (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete"))
+
+#define DLMGMT_DB_CONF_STR(flag) \
+ (((flag) == DLMGMT_ACTIVE) ? "active" : \
+ (((flag) == DLMGMT_PERSIST) ? "persistent" : ""))
+
+static int
+dlmgmt_process_db_req(dlmgmt_db_req_t *req)
+{
+ pthread_t tid;
+ boolean_t writeop;
+ int err;
+
+ /*
+ * If there are already pending "write" requests, queue this request in
+ * the pending list. Note that this function is called while the
+ * dlmgmt_rw_lock is held, so it is safe to access the global variables.
+ */
+ writeop = (req->ls_op != DLMGMT_DB_OP_READ);
+ if (writeop && (req->ls_flags == DLMGMT_PERSIST) &&
+ (dlmgmt_db_req_head != NULL)) {
+ dlmgmt_db_req_tail->ls_next = req;
+ dlmgmt_db_req_tail = req;
+ return (EINPROGRESS);
+ }
+
+ err = dlmgmt_process_db_onereq(req, writeop);
+ if (err != EINPROGRESS && err != 0 &&
+ (req->ls_flags != DLMGMT_ACTIVE || errno != ENOENT)) {
+
+ /*
+ * Log the error unless the request processing:
+ * - is successful;
+ * - is still in progress;
+ * - has failed with ENOENT because the active configuration
+ * file is not created yet;
+ */
+ dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s "
+ "operation on %s configuration failed: %s",
+ DLMGMT_DB_OP_STR(req->ls_op),
+ DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err));
+ }
+
+ if (err == EINPROGRESS) {
+ assert(req->ls_flags == DLMGMT_PERSIST);
+ assert(writeop && dlmgmt_db_req_head == NULL);
+ dlmgmt_db_req_tail = dlmgmt_db_req_head = req;
+ err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL);
+ if (err == 0)
+ return (EINPROGRESS);
+ }
+ return (err);
+}
+
+static int
+dlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
+{
+ int err = 0;
+ FILE *fp, *nfp = NULL;
+ char file[MAXPATHLEN];
+ char newfile[MAXPATHLEN];
+ int nfd;
+
+ DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
+ if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
+ if (writeop && errno == EROFS) {
+ /*
+ * This can happen at boot when the file system is
+ * read-only. So add this request to the pending
+ * request list and start a retry thread.
+ */
+ return (EINPROGRESS);
+ } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) {
+ /*
+ * It is fine if the file keeping active configuration
+ * does not exist. This happens during a new reboot.
+ */
+ if (!writeop)
+ return (ENOENT);
+ /*
+ * If this is an update request for the active
+ * configuration, create the file.
+ */
+ if ((fp = fopen(file, "w")) == NULL)
+ return (errno == EROFS ? EINPROGRESS : errno);
+ } else {
+ return (errno);
+ }
+ }
+
+ if (writeop) {
+ (void) snprintf(newfile, MAXPATHLEN, "%s.new", file);
+ if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ (void) fclose(fp);
+ return (errno);
+ }
+
+ if ((nfp = fdopen(nfd, "w")) == NULL) {
+ (void) close(nfd);
+ (void) fclose(fp);
+ (void) unlink(newfile);
+ return (errno);
+ }
+ }
+ if (writeop)
+ err = process_db_write(req, fp, nfp);
+ else
+ err = process_db_read(req, fp, nfp);
+ if (!writeop || err != 0)
+ goto done;
+
+ /*
+ * Configuration files need to be owned by the 'dladm' user.
+ * If we are invoked by root, the file ownership needs to be fixed.
+ */
+ if (getuid() == 0 || geteuid() == 0) {
+ if (fchown(nfd, DLMGMT_DB_OWNER, DLMGMT_DB_GROUP) < 0) {
+ err = errno;
+ goto done;
+ }
+ }
+
+ if (fflush(nfp) == EOF) {
+ err = errno;
+ goto done;
+ }
+ (void) fclose(fp);
+ (void) fclose(nfp);
+
+ if (rename(newfile, file) < 0) {
+ (void) unlink(newfile);
+ return (errno);
+ }
+
+ return (0);
+
+done:
+ if (nfp != NULL) {
+ (void) fclose(nfp);
+ if (err != 0)
+ (void) unlink(newfile);
+ }
+ (void) fclose(fp);
+ return (err);
+}
+
+/*ARGSUSED*/
+static void *
+dlmgmt_db_update_thread(void *arg)
+{
+ dlmgmt_db_req_t *req;
+ int err = 0;
+
+ dlmgmt_table_lock(B_TRUE);
+
+ assert(dlmgmt_db_req_head != NULL);
+ while ((req = dlmgmt_db_req_head) != NULL) {
+ assert(req->ls_flags == DLMGMT_PERSIST);
+ err = dlmgmt_process_db_onereq(req, B_TRUE);
+ if (err == EINPROGRESS) {
+ /*
+ * The filesystem is still read only. Go to sleep and
+ * try again.
+ */
+ dlmgmt_table_unlock();
+ (void) sleep(5);
+ dlmgmt_table_lock(B_TRUE);
+ continue;
+ }
+
+ /*
+ * The filesystem is no longer read only. Continue processing
+ * and remove the request from the pending list.
+ */
+ dlmgmt_db_req_head = req->ls_next;
+ if (dlmgmt_db_req_tail == req) {
+ assert(dlmgmt_db_req_head == NULL);
+ dlmgmt_db_req_tail = NULL;
+ }
+ free(req);
+ }
+
+ dlmgmt_table_unlock();
+ return (NULL);
+}
+
+static int
+parse_linkprops(char *buf, dlmgmt_link_t *linkp)
+{
+ boolean_t found_type = B_FALSE;
+ dladm_datatype_t type = DLADM_TYPE_STR;
+ int i, len;
+ int err = 0;
+ char *curr;
+ char attr_name[MAXLINKATTRLEN];
+ size_t attr_buf_len = 0;
+ void *attr_buf = NULL;
+
+ curr = buf;
+ len = strlen(buf);
+ attr_name[0] = '\0';
+ for (i = 0; i < len && err == 0; i++) {
+ char c = buf[i];
+ boolean_t match = (c == '=' ||
+ (c == ',' && !found_type) || c == ';');
+
+ /*
+ * Move to the next character if there is no match and
+ * if we have not reached the last character.
+ */
+ if (!match && i != len - 1)
+ continue;
+
+ if (match) {
+ /*
+ * NUL-terminate the string pointed to by 'curr'.
+ */
+ buf[i] = '\0';
+ if (*curr == '\0')
+ goto parse_fail;
+ }
+
+ if (attr_name[0] != '\0' && found_type) {
+ /*
+ * We get here after we have processed the "<prop>="
+ * pattern. The pattern we are now interested in is
+ * "<val>;".
+ */
+ if (c == '=')
+ goto parse_fail;
+
+ if (strcmp(attr_name, "name") == 0) {
+ (void) read_str(curr, &attr_buf);
+ (void) snprintf(linkp->ll_link,
+ MAXLINKNAMELEN, "%s", attr_buf);
+ } else if (strcmp(attr_name, "class") == 0) {
+ (void) read_int64(curr, &attr_buf);
+ linkp->ll_class =
+ (datalink_class_t)*(int64_t *)attr_buf;
+ } else if (strcmp(attr_name, "media") == 0) {
+ (void) read_int64(curr, &attr_buf);
+ linkp->ll_media =
+ (uint32_t)*(int64_t *)attr_buf;
+ } else {
+ attr_buf_len = translators[type].read_func(curr,
+ &attr_buf);
+ err = linkattr_set(&(linkp->ll_head), attr_name,
+ attr_buf, attr_buf_len, type);
+ }
+
+ free(attr_buf);
+ attr_name[0] = '\0';
+ found_type = B_FALSE;
+ } else if (attr_name[0] != '\0') {
+ /*
+ * Non-zero length attr_name and found_type of false
+ * indicates that we have not found the type for this
+ * attribute. The pattern now is "<type>,<val>;", we
+ * want the <type> part of the pattern.
+ */
+ for (type = 0; type < ntranslators; type++) {
+ if (strcmp(curr,
+ translators[type].type_name) == 0) {
+ found_type = B_TRUE;
+ break;
+ }
+ }
+
+ if (!found_type)
+ goto parse_fail;
+ } else {
+ /*
+ * A zero length attr_name indicates we are looking
+ * at the beginning of a link attribute.
+ */
+ if (c != '=')
+ goto parse_fail;
+
+ (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
+ }
+ curr = buf + i + 1;
+ }
+
+ return (err);
+
+parse_fail:
+ return (-1);
+}
+
+static boolean_t
+process_link_line(char *buf, dlmgmt_link_t **linkpp)
+{
+ dlmgmt_link_t *linkp;
+ int i, len, llen;
+ char *str, *lasts;
+ char tmpbuf[MAXLINELEN];
+
+ /*
+ * Use a copy of buf for parsing so that we can do whatever we want.
+ */
+ (void) strlcpy(tmpbuf, buf, MAXLINELEN);
+
+ /*
+ * Skip leading spaces, blank lines, and comments.
+ */
+ len = strlen(tmpbuf);
+ for (i = 0; i < len; i++) {
+ if (!isspace(tmpbuf[i]))
+ break;
+ }
+ if (i == len || tmpbuf[i] == '#') {
+ *linkpp = NULL;
+ return (B_TRUE);
+ }
+
+ linkp = calloc(1, sizeof (dlmgmt_link_t));
+ if (linkp == NULL)
+ goto fail;
+
+ str = tmpbuf + i;
+ /*
+ * Find the link id and assign it to the link structure.
+ */
+ if (strtok_r(str, " \n\t", &lasts) == NULL)
+ goto fail;
+
+ llen = strlen(str);
+ linkp->ll_linkid = atoi(str);
+
+ str += llen + 1;
+ if (str >= tmpbuf + len)
+ goto fail;
+
+ /*
+ * Now find the list of link properties.
+ */
+ if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
+ goto fail;
+
+ if (parse_linkprops(str, linkp) < 0)
+ goto fail;
+
+ *linkpp = linkp;
+ return (B_TRUE);
+
+fail:
+ link_destroy(linkp);
+
+ /*
+ * Delete corrupted line.
+ */
+ buf[0] = '\0';
+ return (B_FALSE);
+}
+
+static int
+process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
+{
+ boolean_t done = B_FALSE;
+ int err = 0;
+ dlmgmt_link_t *linkp, *link_in_file, link;
+ char buf[MAXLINELEN];
+
+ if (req->ls_op == DLMGMT_DB_OP_WRITE) {
+ /*
+ * find the link in the avl tree with the given linkid.
+ */
+ link.ll_linkid = req->ls_linkid;
+ linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
+ if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) {
+ /*
+ * This link has already been changed. This could
+ * happen if the request is pending because of
+ * read-only file-system. If so, we are done.
+ */
+ return (0);
+ }
+ }
+
+ while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
+ process_link_line(buf, &link_in_file)) {
+ if (link_in_file == NULL || done) {
+ /*
+ * this is a comment line, write it out.
+ */
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
+ continue;
+ }
+
+ switch (req->ls_op) {
+ case DLMGMT_DB_OP_WRITE:
+ /*
+ * For write operations, if the linkid of the link
+ * read from the file does not match the id of what
+ * req->ll_linkid points to, write out the buffer.
+ * Otherwise, generate a new line. If we get to the
+ * end and have not seen what req->ll_linkid points
+ * to, write it out then.
+ */
+ if (linkp == NULL ||
+ linkp->ll_linkid != link_in_file->ll_linkid) {
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
+ } else {
+ generate_link_line(linkp,
+ req->ls_flags == DLMGMT_PERSIST, buf);
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
+ done = B_TRUE;
+ }
+ break;
+ case DLMGMT_DB_OP_DELETE:
+ /*
+ * Delete is simple. If buf does not represent the
+ * link we're deleting, write it out.
+ */
+ if (req->ls_linkid != link_in_file->ll_linkid) {
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
+ } else {
+ done = B_TRUE;
+ }
+ break;
+ case DLMGMT_DB_OP_READ:
+ default:
+ err = EINVAL;
+ break;
+ }
+ link_destroy(link_in_file);
+ }
+
+ /*
+ * If we get to the end of the file and have not seen what
+ * req->ll_linkid points to, write it out then.
+ */
+ if (req->ls_op == DLMGMT_DB_OP_WRITE && !done) {
+ generate_link_line(linkp, req->ls_flags == DLMGMT_PERSIST, buf);
+ done = B_TRUE;
+ if (fputs(buf, nfp) == EOF)
+ err = errno;
+ }
+
+ if (!done)
+ err = ENOENT;
+
+ return (err);
+}
+
+/* ARGSUSED1 */
+static int
+process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
+{
+ avl_index_t name_where, id_where;
+ dlmgmt_link_t *link_in_file;
+ dlmgmt_link_t *linkp1, *linkp2;
+ char buf[MAXLINELEN];
+ int err = 0;
+
+ /*
+ * This loop processes each line of the configuration file.
+ */
+ while (fgets(buf, MAXLINELEN, fp) != NULL) {
+ if (!process_link_line(buf, &link_in_file)) {
+ err = EINVAL;
+ break;
+ }
+
+ /*
+ * Skip the comment line.
+ */
+ if (link_in_file == NULL)
+ continue;
+
+ linkp1 = avl_find(&dlmgmt_name_avl, link_in_file, &name_where);
+ linkp2 = avl_find(&dlmgmt_id_avl, link_in_file, &id_where);
+ if ((linkp1 != NULL) || (linkp2 != NULL)) {
+ /*
+ * If any of the following conditions are met, this is
+ * a duplicate entry:
+ *
+ * 1. link2 (with the given name) and link2 (with the
+ * given id) are not the same link;
+ * 2. This is a persistent req and find the link with
+ * the given name and id. Note that persistent db
+ * is read before the active one.
+ * 3. Found the link with the given name and id but
+ * the link is already active.
+ */
+ if ((linkp1 != linkp2) ||
+ (req->ls_flags == DLMGMT_PERSIST) ||
+ ((linkp1->ll_flags & DLMGMT_ACTIVE) != 0)) {
+ dlmgmt_log(LOG_WARNING, "Duplicate link "
+ "entries in repository: link name %s "
+ "link id %i", link_in_file->ll_link,
+ link_in_file->ll_linkid);
+ } else {
+ linkp1->ll_flags |= DLMGMT_ACTIVE;
+ }
+ link_destroy(link_in_file);
+ } else {
+ avl_insert(&dlmgmt_name_avl, link_in_file, name_where);
+ avl_insert(&dlmgmt_id_avl, link_in_file, id_where);
+ dlmgmt_advance(link_in_file);
+ link_in_file->ll_flags |= req->ls_flags;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Generate an entry in the link database.
+ * Each entry has this format:
+ * <link id> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
+ */
+static void
+generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
+{
+ char tmpbuf[MAXLINELEN];
+ char *ptr;
+ char *lim = tmpbuf + MAXLINELEN;
+ char *name_to_write = NULL;
+ datalink_id_t id_to_write;
+ dlmgmt_linkattr_t *cur_p = NULL;
+ uint64_t u64;
+
+ ptr = tmpbuf;
+ id_to_write = linkp->ll_linkid;
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "%d\t", id_to_write);
+ name_to_write = linkp->ll_link;
+ ptr += write_str(ptr, BUFLEN(lim, ptr), "name", name_to_write);
+ u64 = linkp->ll_class;
+ ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
+ u64 = linkp->ll_media;
+ ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
+
+ /*
+ * The daemon does not keep any active link attribute. If this request
+ * is for active configuration, we are done.
+ */
+ if (!persist)
+ goto done;
+
+ for (cur_p = linkp->ll_head; cur_p != NULL; cur_p = cur_p->lp_next) {
+ ptr += translators[cur_p->lp_type].write_func(ptr,
+ BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
+ }
+done:
+ if (ptr > lim)
+ return;
+ (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
+}
+
+int
+dlmgmt_delete_db_entry(datalink_id_t linkid, uint32_t flags)
+{
+ return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkid, flags));
+}
+
+int
+dlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags)
+{
+ int err;
+
+ if (flags & DLMGMT_PERSIST) {
+ if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
+ linkid, DLMGMT_PERSIST)) != 0) {
+ return (err);
+ }
+ }
+
+ if (flags & DLMGMT_ACTIVE) {
+ if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
+ linkid, DLMGMT_ACTIVE)) != 0) &&
+ (flags & DLMGMT_PERSIST)) {
+ (void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE,
+ linkid, DLMGMT_PERSIST);
+ return (err);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Initialize the datalink <link name, linkid> mapping and the link's
+ * attributes list based on the configuration file /etc/dladm/datalink.conf
+ * and the active configuration cache file
+ * /etc/svc/volatile/datalink-management:default.cache.
+ *
+ * This function is called when the datalink-management service is started
+ * during reboot, and when the dlmgmtd daemon is restarted.
+ */
+int
+dlmgmt_db_init()
+{
+ char filename[MAXPATHLEN];
+ dlmgmt_db_req_t req;
+ int err;
+ dlmgmt_link_t *linkp;
+ char *fmri, *c;
+
+ /*
+ * First derive the name of the cache file from the FMRI name. This
+ * cache name is used to keep active datalink configuration.
+ */
+ if (debug) {
+ (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
+ DLMGMT_TEMP_DB_DIR, progname, ".debug.cache");
+ } else {
+ if ((fmri = getenv("SMF_FMRI")) == NULL) {
+ dlmgmt_log(LOG_WARNING, "dlmgmtd is an smf(5) managed "
+ "service and should not be run from the command "
+ "line.");
+ return (EINVAL);
+ }
+
+ /*
+ * The FMRI name is in the form of
+ * svc:/service/service:instance. We need to remove the
+ * prefix "svc:/" and replace '/' with '-'. The cache file
+ * name is in the form of "service:instance.cache".
+ */
+ if ((c = strchr(fmri, '/')) != NULL)
+ c++;
+ else
+ c = fmri;
+ (void) snprintf(filename, MAXPATHLEN, "%s.cache", c);
+ for (c = filename; *c != '\0'; c++) {
+ if (*c == '/')
+ *c = '-';
+ }
+
+ (void) snprintf(cachefile, MAXPATHLEN, "%s/%s",
+ DLMGMT_TEMP_DB_DIR, filename);
+ }
+
+ dlmgmt_table_lock(B_TRUE);
+
+ req.ls_next = NULL;
+ req.ls_op = DLMGMT_DB_OP_READ;
+ req.ls_linkid = DATALINK_INVALID_LINKID;
+ req.ls_flags = DLMGMT_PERSIST;
+
+ if ((err = dlmgmt_process_db_req(&req)) != 0)
+ goto done;
+
+ req.ls_flags = DLMGMT_ACTIVE;
+ err = dlmgmt_process_db_req(&req);
+ if (err == ENOENT) {
+ /*
+ * The temporary datalink.conf does not exist. This is
+ * the first boot. Mark all the physical links active.
+ */
+ for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
+ linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
+ if (linkp->ll_class == DATALINK_CLASS_PHYS) {
+ linkp->ll_flags |= DLMGMT_ACTIVE;
+ (void) dlmgmt_write_db_entry(
+ linkp->ll_linkid, DLMGMT_ACTIVE);
+ }
+ }
+ err = 0;
+ }
+
+done:
+ dlmgmt_table_unlock();
+ return (err);
+}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_door.c b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
new file mode 100644
index 0000000000..a4c0de808e
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
@@ -0,0 +1,1075 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Main door handler functions used by dlmgmtd to process the different door
+ * call requests. Door call requests can come from the user-land applications,
+ * which will be handled by dlmgmt_call_handler(); or they can come from the
+ * kernel, which will be handled by dlmgmt_upcall_handler().
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <strings.h>
+#include <libdlmgmt.h>
+#include "dlmgmt_impl.h"
+
+static dlmgmt_link_t *
+dlmgmt_getlink_by_dev(char *devname)
+{
+ dlmgmt_link_t *linkp = avl_first(&dlmgmt_id_avl);
+
+ for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
+ if ((linkp->ll_class == DATALINK_CLASS_PHYS) &&
+ linkattr_equal(&(linkp->ll_head), FDEVNAME, devname,
+ strlen(devname) + 1)) {
+ return (linkp);
+ }
+ }
+ return (NULL);
+}
+
+static void
+dlmgmt_upcall_create(dlmgmt_upcall_arg_create_t *create,
+ dlmgmt_create_retval_t *retvalp)
+{
+ datalink_class_t class;
+ uint32_t media;
+ dlmgmt_link_t *linkp;
+ char link[MAXLINKNAMELEN];
+ uint32_t flags;
+ int err;
+ boolean_t created = B_FALSE;
+
+ /*
+ * Determine whether this link is persistent. Note that this request
+ * is coming from kernel so this link must be active.
+ */
+ flags = DLMGMT_ACTIVE | (create->ld_persist ? DLMGMT_PERSIST : 0);
+
+ class = create->ld_class;
+ media = create->ld_media;
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+
+ /*
+ * Check to see whether this is the reattachment of an existing
+ * physical link. If so, return its linkid.
+ */
+ if ((class == DATALINK_CLASS_PHYS) &&
+ (linkp = dlmgmt_getlink_by_dev(create->ld_devname)) != NULL) {
+ err = linkattr_set(&(linkp->ll_head), FPHYMAJ,
+ &create->ld_phymaj, sizeof (uint64_t), DLADM_TYPE_UINT64);
+ if (err != 0)
+ goto done;
+
+ err = linkattr_set(&(linkp->ll_head), FPHYINST,
+ &create->ld_phyinst, sizeof (uint64_t), DLADM_TYPE_UINT64);
+ if (err != 0)
+ goto done;
+
+ linkp->ll_flags |= flags;
+ linkp->ll_gen++;
+ goto done;
+ }
+
+ if ((err = dlmgmt_create_common(create->ld_devname, class, media,
+ flags, &linkp)) == EEXIST) {
+ /*
+ * The link name already exists. Return error if this is a
+ * non-physical link (in that case, the link name must be
+ * the same as the given name).
+ */
+ if (class != DATALINK_CLASS_PHYS)
+ goto done;
+
+ /*
+ * The physical link's name already exists, request
+ * a suggested link name: net<nextppa>
+ */
+ err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN);
+ if (err != 0)
+ goto done;
+
+ err = dlmgmt_create_common(link, class, media, flags, &linkp);
+ }
+
+ if (err != 0)
+ goto done;
+
+ created = B_TRUE;
+
+ /*
+ * This is a new link. Only need to persist link attributes for
+ * physical links.
+ */
+ if (class == DATALINK_CLASS_PHYS &&
+ (((err = linkattr_set(&linkp->ll_head, FDEVNAME, create->ld_devname,
+ strlen(create->ld_devname) + 1, DLADM_TYPE_STR)) != 0) ||
+ ((err = linkattr_set(&linkp->ll_head, FPHYMAJ, &create->ld_phymaj,
+ sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0) ||
+ ((err = linkattr_set(&linkp->ll_head, FPHYINST, &create->ld_phyinst,
+ sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0))) {
+ (void) dlmgmt_destroy_common(linkp, flags);
+ goto done;
+ }
+
+done:
+ if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_linkid,
+ linkp->ll_flags)) != 0) && created) {
+ (void) dlmgmt_destroy_common(linkp, flags);
+ }
+
+ if (err == 0)
+ retvalp->lr_linkid = linkp->ll_linkid;
+
+ retvalp->lr_err = err;
+ dlmgmt_table_unlock();
+}
+
+static void
+dlmgmt_upcall_update(dlmgmt_upcall_arg_update_t *update,
+ dlmgmt_update_retval_t *retvalp)
+{
+ uint32_t media = update->ld_media;
+ dlmgmt_link_t *linkp;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+
+ /*
+ * Check to see whether this is the reattachment of an existing
+ * physical link. If so, return its linkid.
+ */
+ if ((linkp = dlmgmt_getlink_by_dev(update->ld_devname)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ retvalp->lr_linkid = linkp->ll_linkid;
+ retvalp->lr_media = media;
+ if (linkp->ll_media != media && linkp->ll_media != DL_OTHER) {
+ /*
+ * Assume a DL_ETHER link ce0, a DL_WIFI link ath0
+ * 1. # dladm rename-link ce0 net0
+ * 2. DR out ce0. net0 is down.
+ * 3. use rename-link to have the ath0 device inherit
+ * the configuration from net0
+ * # dladm rename-link ath0 net0
+ * 4. DR in ath0.
+ * As ath0 and ce0 do not have the same media type, ath0
+ * cannot inherit the configuration of net0.
+ */
+ err = EEXIST;
+
+ /*
+ * Return the media type of the existing link to indicate the
+ * reason for the name conflict.
+ */
+ retvalp->lr_media = linkp->ll_media;
+ goto done;
+ }
+
+ if (update->ld_novanity &&
+ (strcmp(update->ld_devname, linkp->ll_link) != 0)) {
+ /*
+ * Return an error if this is a physical link that does not
+ * support vanity naming, but the link name is not the same
+ * as the given device name.
+ */
+ err = EEXIST;
+ goto done;
+ }
+
+ linkp->ll_media = media;
+ linkp->ll_gen++;
+
+ (void) dlmgmt_write_db_entry(linkp->ll_linkid, linkp->ll_flags);
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_upcall_destroy(dlmgmt_upcall_arg_destroy_t *destroy,
+ dlmgmt_destroy_retval_t *retvalp)
+{
+ datalink_id_t linkid = destroy->ld_linkid;
+ dlmgmt_link_t *linkp = NULL;
+ uint32_t flags, dflags = 0;
+ int err = 0;
+
+ flags = DLMGMT_ACTIVE | (destroy->ld_persist ? DLMGMT_PERSIST : 0);
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+
+ if ((linkp = link_by_id(linkid)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) &&
+ ((err = dlmgmt_delete_db_entry(linkid, DLMGMT_ACTIVE)) != 0)) {
+ dflags = DLMGMT_ACTIVE;
+ goto done;
+ }
+
+ if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) &&
+ ((err = dlmgmt_delete_db_entry(linkid, DLMGMT_PERSIST)) != 0)) {
+ if (dflags != 0)
+ (void) dlmgmt_write_db_entry(linkp->ll_linkid, dflags);
+ dflags |= DLMGMT_PERSIST;
+ goto done;
+ }
+
+ if ((err = dlmgmt_destroy_common(linkp, flags)) != 0 && dflags != 0)
+ (void) dlmgmt_write_db_entry(linkp->ll_linkid, dflags);
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_getname(dlmgmt_door_getname_t *getname, dlmgmt_getname_retval_t *retvalp)
+{
+ dlmgmt_link_t *linkp;
+ int err = 0;
+
+ /*
+ * Hold the reader lock to access the link
+ */
+ dlmgmt_table_lock(B_FALSE);
+ if ((linkp = link_by_id(getname->ld_linkid)) == NULL) {
+ /*
+ * The link does not exists.
+ */
+ err = ENOENT;
+ goto done;
+ }
+
+ if (strlcpy(retvalp->lr_link, linkp->ll_link, MAXLINKNAMELEN) >=
+ MAXLINKNAMELEN) {
+ err = ENOSPC;
+ goto done;
+ }
+ retvalp->lr_flags = linkp->ll_flags;
+ retvalp->lr_class = linkp->ll_class;
+ retvalp->lr_media = linkp->ll_media;
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_getlinkid(dlmgmt_door_getlinkid_t *getlinkid,
+ dlmgmt_getlinkid_retval_t *retvalp)
+{
+ dlmgmt_link_t *linkp;
+ int err = 0;
+
+ /*
+ * Hold the reader lock to access the link
+ */
+ dlmgmt_table_lock(B_FALSE);
+ if ((linkp = link_by_name(getlinkid->ld_link)) == NULL) {
+ /*
+ * The link does not exists.
+ */
+ err = ENOENT;
+ goto done;
+ }
+
+ retvalp->lr_linkid = linkp->ll_linkid;
+ retvalp->lr_flags = linkp->ll_flags;
+ retvalp->lr_class = linkp->ll_class;
+ retvalp->lr_media = linkp->ll_media;
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_getnext(dlmgmt_door_getnext_t *getnext, dlmgmt_getnext_retval_t *retvalp)
+{
+ dlmgmt_link_t link, *linkp;
+ datalink_id_t linkid = getnext->ld_linkid;
+ avl_index_t where;
+ int err = 0;
+
+ /*
+ * Hold the reader lock to access the link
+ */
+ dlmgmt_table_lock(B_FALSE);
+
+ link.ll_linkid = (linkid + 1);
+ linkp = avl_find(&dlmgmt_id_avl, &link, &where);
+ if (linkp == NULL)
+ linkp = avl_nearest(&dlmgmt_id_avl, where, AVL_AFTER);
+
+ for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
+ if ((linkp->ll_class & getnext->ld_class) &&
+ (linkp->ll_flags & getnext->ld_flags) &&
+ DATALINK_MEDIA_ACCEPTED(getnext->ld_dmedia,
+ linkp->ll_media))
+ break;
+ }
+
+ if (linkp == NULL) {
+ err = ENOENT;
+ } else {
+ retvalp->lr_linkid = linkp->ll_linkid;
+ retvalp->lr_class = linkp->ll_class;
+ retvalp->lr_media = linkp->ll_media;
+ retvalp->lr_flags = linkp->ll_flags;
+ }
+
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+/*
+ * Note that the caller needs to free the memory of *retvalp, when it returns
+ * success.
+ */
+static int
+dlmgmt_upcall_getattr(dlmgmt_upcall_arg_getattr_t *getattr,
+ dlmgmt_getattr_retval_t **retvalpp, size_t *retszp)
+{
+ dlmgmt_link_t *linkp;
+ int err = 0;
+
+ /*
+ * Hold the reader lock to access the link
+ */
+ dlmgmt_table_lock(B_FALSE);
+ if ((linkp = link_by_id(getattr->ld_linkid)) == NULL) {
+ /*
+ * The link does not exist.
+ */
+ err = ENOENT;
+ goto done;
+ }
+
+ err = dlmgmt_getattr_common(&linkp->ll_head, getattr->ld_attr,
+ retvalpp, retszp);
+
+done:
+ dlmgmt_table_unlock();
+ return (err);
+}
+
+static void
+dlmgmt_upcall_handler(void *arg, int cmd)
+{
+ switch (cmd) {
+ case DLMGMT_CMD_DLS_CREATE: {
+ dlmgmt_create_retval_t retval;
+
+ dlmgmt_upcall_create(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_DLS_UPDATE: {
+ dlmgmt_update_retval_t retval;
+
+ dlmgmt_upcall_update(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_DLS_GETATTR: {
+ dlmgmt_getattr_retval_t retval;
+ dlmgmt_getattr_retval_t *retvalp = NULL;
+ dlmgmt_getattr_retval_t *tmp;
+ size_t retsz = 0;
+ int err;
+
+ if ((err = dlmgmt_upcall_getattr(arg, &retvalp, &retsz)) != 0) {
+ retval.lr_err = err;
+ retvalp = &retval;
+ retsz = sizeof (retval);
+ } else {
+ /*
+ * For the successful case, retvalp points to
+ * memory that was allocated with malloc. But, since
+ * door_return never returns, that memory gets leaked.
+ * Use alloca and free retvalp.
+ */
+ tmp = alloca(retsz);
+ bcopy(retvalp, tmp, retsz);
+ free(retvalp);
+ retvalp = tmp;
+ }
+ (void) door_return((char *)retvalp, retsz, NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_DLS_DESTROY: {
+ dlmgmt_destroy_retval_t retval;
+
+ dlmgmt_upcall_destroy(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_GETNAME: {
+ dlmgmt_getname_retval_t retval;
+
+ dlmgmt_getname(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_GETLINKID: {
+ dlmgmt_getlinkid_retval_t retval;
+
+ dlmgmt_getlinkid(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_GETNEXT: {
+ dlmgmt_getnext_retval_t retval;
+
+ dlmgmt_getnext(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ default: {
+ struct dlmgmt_null_retval_s retval;
+
+ retval.lr_err = EINVAL;
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ }
+}
+
+static void
+dlmgmt_createid(dlmgmt_door_createid_t *createid,
+ dlmgmt_createid_retval_t *retvalp)
+{
+ dlmgmt_link_t *linkp;
+ datalink_id_t linkid = DATALINK_INVALID_LINKID;
+ char link[MAXLINKNAMELEN];
+ int err;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+
+ if (createid->ld_prefix) {
+ err = dlmgmt_generate_name(createid->ld_link, link,
+ MAXLINKNAMELEN);
+ if (err != 0)
+ goto done;
+
+ err = dlmgmt_create_common(link, createid->ld_class,
+ createid->ld_media, createid->ld_flags, &linkp);
+ } else {
+ err = dlmgmt_create_common(createid->ld_link,
+ createid->ld_class, createid->ld_media, createid->ld_flags,
+ &linkp);
+ }
+
+ if (err == 0) {
+ /*
+ * Keep the active mapping.
+ */
+ linkid = linkp->ll_linkid;
+ if (createid->ld_flags & DLMGMT_ACTIVE)
+ (void) dlmgmt_write_db_entry(linkid, DLMGMT_ACTIVE);
+ }
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_linkid = linkid;
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_destroyid(dlmgmt_door_destroyid_t *destroyid,
+ dlmgmt_destroyid_retval_t *retvalp)
+{
+ datalink_id_t linkid = destroyid->ld_linkid;
+ uint32_t flags = destroyid->ld_flags;
+ dlmgmt_link_t *linkp = NULL;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+ if ((linkp = link_by_id(linkid)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ if ((err = dlmgmt_destroy_common(linkp, flags)) != 0)
+ goto done;
+
+ /*
+ * Delete the active mapping.
+ */
+ if (flags & DLMGMT_ACTIVE)
+ (void) dlmgmt_delete_db_entry(linkid, DLMGMT_ACTIVE);
+
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+/*
+ * Remap a linkid to a given link name, i.e., rename an existing link1
+ * (ld_linkid) to a non-existent link2 (ld_link): rename link1's name to
+ * the given link name.
+ */
+static void
+dlmgmt_remapid(dlmgmt_door_remapid_t *remapid,
+ dlmgmt_remapid_retval_t *retvalp)
+{
+ datalink_id_t linkid1 = remapid->ld_linkid;
+ dlmgmt_link_t link, *linkp1, *tmp;
+ avl_index_t where;
+ int err = 0;
+
+ if (!dladm_valid_linkname(remapid->ld_link)) {
+ retvalp->lr_err = EINVAL;
+ return;
+ }
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+ if ((linkp1 = link_by_id(linkid1)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ if (link_by_name(remapid->ld_link) != NULL) {
+ err = EEXIST;
+ goto done;
+ }
+
+ avl_remove(&dlmgmt_name_avl, linkp1);
+ (void) strlcpy(link.ll_link, remapid->ld_link, MAXLINKNAMELEN);
+ tmp = avl_find(&dlmgmt_name_avl, &link, &where);
+ assert(tmp == NULL);
+ (void) strlcpy(linkp1->ll_link, remapid->ld_link, MAXLINKNAMELEN);
+ avl_insert(&dlmgmt_name_avl, linkp1, where);
+ dlmgmt_advance(linkp1);
+
+ /*
+ * If we renamed a temporary link, update the temporary repository.
+ */
+ if (linkp1->ll_flags & DLMGMT_ACTIVE)
+ (void) dlmgmt_write_db_entry(linkid1, DLMGMT_ACTIVE);
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_upid(dlmgmt_door_upid_t *upid, dlmgmt_upid_retval_t *retvalp)
+{
+ dlmgmt_link_t *linkp;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+ if ((linkp = link_by_id(upid->ld_linkid)) == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ if (linkp->ll_flags & DLMGMT_ACTIVE) {
+ err = EINVAL;
+ goto done;
+ }
+
+ linkp->ll_flags |= DLMGMT_ACTIVE;
+ (void) dlmgmt_write_db_entry(linkp->ll_linkid, DLMGMT_ACTIVE);
+done:
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_createconf(dlmgmt_door_createconf_t *createconf,
+ dlmgmt_createconf_retval_t *retvalp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp, *tmp;
+ avl_index_t where;
+ int err;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ if ((err = dlconf_create(createconf->ld_link, createconf->ld_linkid,
+ createconf->ld_class, createconf->ld_media, &dlconfp)) != 0) {
+ goto done;
+ }
+
+ dlconf.ld_id = dlconfp->ld_id;
+ tmp = avl_find(&dlmgmt_dlconf_avl, &dlconf, &where);
+ assert(tmp == NULL);
+ avl_insert(&dlmgmt_dlconf_avl, dlconfp, where);
+ dlmgmt_advance_dlconfid(dlconfp);
+
+ retvalp->lr_conf = (dladm_conf_t)dlconfp->ld_id;
+done:
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_setattr(dlmgmt_door_setattr_t *setattr, size_t argsz,
+ dlmgmt_setattr_retval_t *retvalp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp;
+ int err = 0;
+
+ if (argsz < sizeof (dlmgmt_door_setattr_t) ||
+ argsz != sizeof (dlmgmt_door_setattr_t) + setattr->ld_attrsz - 1) {
+ retvalp->lr_err = EINVAL;
+ return;
+ }
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ dlconf.ld_id = (int)setattr->ld_conf;
+ dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
+ if (dlconfp == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ err = linkattr_set(&(dlconfp->ld_head), setattr->ld_attr,
+ &setattr->ld_attrval, setattr->ld_attrsz, setattr->ld_type);
+
+done:
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_unsetattr(dlmgmt_door_unsetattr_t *unsetattr,
+ dlmgmt_unsetattr_retval_t *retvalp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ dlconf.ld_id = (int)unsetattr->ld_conf;
+ dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
+ if (dlconfp == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ err = linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr);
+
+done:
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+/*
+ * Note that dlmgmt_readconf() returns a conf ID of a conf AVL tree entry,
+ * which is managed by dlmgmtd. The ID is used to find the conf entry when
+ * dlmgmt_write_conf() is called. The conf entry contains an ld_gen value
+ * (which is the generation number - ll_gen) of the dlmgmt_link_t at the time
+ * of dlmgmt_readconf(), and ll_gen changes every time the dlmgmt_link_t
+ * changes its attributes. Therefore, dlmgmt_write_conf() can compare ld_gen
+ * in the conf entry against the latest dlmgmt_link_t ll_gen value to see if
+ * anything has changed between the dlmgmt_read_conf() and dlmgmt_writeconf()
+ * calls. If so, EAGAIN is returned. This mechanism can ensures atomicity
+ * across the pair of dladm_read_conf() and dladm_write_conf() calls.
+ */
+static void
+dlmgmt_writeconf(dlmgmt_door_writeconf_t *writeconf,
+ dlmgmt_writeconf_retval_t *retvalp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp;
+ dlmgmt_link_t *linkp;
+ dlmgmt_linkattr_t *attrp, *next;
+ int err = 0;
+
+ /*
+ * Hold the read lock to access the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ dlconf.ld_id = (int)writeconf->ld_conf;
+ dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
+ if (dlconfp == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ /*
+ * Hold the writer lock to update the link table.
+ */
+ dlmgmt_table_lock(B_TRUE);
+ linkp = link_by_id(dlconfp->ld_linkid);
+ if ((linkp == NULL) || (linkp->ll_class != dlconfp->ld_class) ||
+ (linkp->ll_media != dlconfp->ld_media) ||
+ (strcmp(linkp->ll_link, dlconfp->ld_link) != 0)) {
+ /*
+ * The link does not exist.
+ */
+ dlmgmt_table_unlock();
+ err = ENOENT;
+ goto done;
+ }
+
+ if (linkp->ll_gen != dlconfp->ld_gen) {
+ /*
+ * Something has changed the link configuration; try again.
+ */
+ dlmgmt_table_unlock();
+ err = EAGAIN;
+ goto done;
+ }
+
+ /*
+ * Delete the old attribute list.
+ */
+ for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
+ next = attrp->lp_next;
+ free(attrp->lp_val);
+ free(attrp);
+ }
+ linkp->ll_head = NULL;
+
+ /*
+ * Set the new attribute.
+ */
+ for (attrp = dlconfp->ld_head; attrp != NULL; attrp = attrp->lp_next) {
+ if ((err = linkattr_set(&(linkp->ll_head), attrp->lp_name,
+ attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
+ dlmgmt_table_unlock();
+ goto done;
+ }
+ }
+
+ linkp->ll_gen++;
+ err = dlmgmt_write_db_entry(linkp->ll_linkid, DLMGMT_PERSIST);
+ dlmgmt_table_unlock();
+done:
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_removeconf(dlmgmt_door_removeconf_t *removeconf,
+ dlmgmt_removeconf_retval_t *retvalp)
+{
+ int err;
+
+ dlmgmt_table_lock(B_TRUE);
+ err = dlmgmt_delete_db_entry(removeconf->ld_linkid, DLMGMT_PERSIST);
+ dlmgmt_table_unlock();
+ retvalp->lr_err = err;
+}
+
+static void
+dlmgmt_destroyconf(dlmgmt_door_destroyconf_t *destroyconf,
+ dlmgmt_destroyconf_retval_t *retvalp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ dlconf.ld_id = (int)destroyconf->ld_conf;
+ dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
+ if (dlconfp == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ avl_remove(&dlmgmt_dlconf_avl, dlconfp);
+ dlconf_destroy(dlconfp);
+
+done:
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+/*
+ * See the comments above dladm_write_conf() to see how ld_gen is used to
+ * ensure atomicity across the {dlmgmt_readconf(), dlmgmt_writeconf()} pair.
+ */
+static void
+dlmgmt_readconf(dlmgmt_door_readconf_t *readconf,
+ dlmgmt_readconf_retval_t *retvalp)
+{
+ dlmgmt_link_t *linkp;
+ datalink_id_t linkid = readconf->ld_linkid;
+ dlmgmt_dlconf_t *dlconfp, *tmp, dlconf;
+ dlmgmt_linkattr_t *attrp;
+ avl_index_t where;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_TRUE);
+
+ /*
+ * Hold the reader lock to access the link
+ */
+ dlmgmt_table_lock(B_FALSE);
+ linkp = link_by_id(linkid);
+ if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
+ /*
+ * The persistent link configuration does not exists.
+ */
+ err = ENOENT;
+ goto done;
+ }
+
+ if ((err = dlconf_create(linkp->ll_link, linkp->ll_linkid,
+ linkp->ll_class, linkp->ll_media, &dlconfp)) != 0) {
+ goto done;
+ }
+
+ for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
+ if ((err = linkattr_set(&(dlconfp->ld_head), attrp->lp_name,
+ attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
+ dlconf_destroy(dlconfp);
+ goto done;
+ }
+ }
+ dlconfp->ld_gen = linkp->ll_gen;
+
+ dlconf.ld_id = dlconfp->ld_id;
+ tmp = avl_find(&dlmgmt_dlconf_avl, &dlconf, &where);
+ assert(tmp == NULL);
+ avl_insert(&dlmgmt_dlconf_avl, dlconfp, where);
+ dlmgmt_advance_dlconfid(dlconfp);
+
+ retvalp->lr_conf = (dladm_conf_t)dlconfp->ld_id;
+done:
+ dlmgmt_table_unlock();
+ dlmgmt_dlconf_table_unlock();
+ retvalp->lr_err = err;
+}
+
+/*
+ * Note: the caller must free *retvalpp in case of success.
+ */
+static int
+dlmgmt_getattr(dlmgmt_door_getattr_t *getattr,
+ dlmgmt_getattr_retval_t **retvalpp, size_t *retszp)
+{
+ dlmgmt_dlconf_t dlconf, *dlconfp;
+ int err = 0;
+
+ /*
+ * Hold the writer lock to update the dlconf table.
+ */
+ dlmgmt_dlconf_table_lock(B_FALSE);
+
+ dlconf.ld_id = (int)getattr->ld_conf;
+ dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
+ if (dlconfp == NULL) {
+ err = ENOENT;
+ goto done;
+ }
+
+ err = dlmgmt_getattr_common(&dlconfp->ld_head, getattr->ld_attr,
+ retvalpp, retszp);
+
+done:
+ dlmgmt_dlconf_table_unlock();
+ return (err);
+}
+
+static void
+dlmgmt_call_handler(void *arg, size_t argsz, int cmd)
+{
+ switch (cmd) {
+ case DLMGMT_CMD_CREATE_LINKID: {
+ dlmgmt_createid_retval_t retval;
+
+ dlmgmt_createid(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_DESTROY_LINKID: {
+ dlmgmt_destroyid_retval_t retval;
+
+ dlmgmt_destroyid(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_REMAP_LINKID: {
+ dlmgmt_remapid_retval_t retval;
+
+ dlmgmt_remapid(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_UP_LINKID: {
+ dlmgmt_upid_retval_t retval;
+
+ dlmgmt_upid(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_CREATECONF: {
+ dlmgmt_createconf_retval_t retval;
+
+ dlmgmt_createconf(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_SETATTR: {
+ dlmgmt_setattr_retval_t retval;
+
+ dlmgmt_setattr(arg, argsz, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_UNSETATTR: {
+ dlmgmt_unsetattr_retval_t retval;
+
+ dlmgmt_unsetattr(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_WRITECONF: {
+ dlmgmt_writeconf_retval_t retval;
+
+ dlmgmt_writeconf(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_REMOVECONF: {
+ dlmgmt_removeconf_retval_t retval;
+
+ dlmgmt_removeconf(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_DESTROYCONF: {
+ dlmgmt_destroyconf_retval_t retval;
+
+ dlmgmt_destroyconf(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_READCONF: {
+ dlmgmt_readconf_retval_t retval;
+
+ dlmgmt_readconf(arg, &retval);
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ case DLMGMT_CMD_GETATTR: {
+ dlmgmt_getattr_retval_t retval;
+ dlmgmt_getattr_retval_t *retvalp = NULL;
+ dlmgmt_getattr_retval_t *tmp;
+ int err;
+ size_t retsz = 0;
+
+ if ((err = dlmgmt_getattr(arg, &retvalp, &retsz)) != 0) {
+ retval.lr_err = err;
+ retvalp = &retval;
+ retsz = sizeof (retval);
+ } else {
+ /*
+ * For the successful case, retvalp points to memory
+ * that was allocated in dlmgmt_getattr(). Since
+ * door_return never returns, that memory would get
+ * leaked. So we use alloca instead, and free retvalp.
+ */
+ tmp = alloca(retsz);
+ bcopy(retvalp, tmp, retsz);
+ free(retvalp);
+ retvalp = tmp;
+ }
+ (void) door_return((char *)retvalp, retsz, NULL, 0);
+ break;
+ }
+ default: {
+ struct dlmgmt_null_retval_s retval;
+
+ retval.lr_err = EINVAL;
+ (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+ break;
+ }
+ }
+}
+
+/* ARGSUSED */
+void
+dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
+ uint_t n_desc)
+{
+ int cmd = ((dlmgmt_door_arg_t *)(void *)argp)->ld_cmd;
+
+ if (cmd < DLMGMT_CMD_BASE) {
+ /*
+ * Upcall request from the dls module.
+ */
+ dlmgmt_upcall_handler(argp, cmd);
+ } else {
+ /*
+ * Door call request from libdladm.
+ */
+ dlmgmt_call_handler(argp, argsz, cmd);
+ }
+}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_impl.h b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
new file mode 100644
index 0000000000..365dc60d07
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
@@ -0,0 +1,134 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Functions to maintain a table of datalink configuration information.
+ */
+
+#ifndef _DLMGMT_IMPL_H
+#define _DLMGMT_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <door.h>
+#include <libdllink.h>
+
+/*
+ * datalink attribute structure
+ */
+typedef struct dlmgmt_linkattr_s {
+ struct dlmgmt_linkattr_s *lp_next;
+ struct dlmgmt_linkattr_s *lp_prev;
+ char lp_name[MAXLINKATTRLEN];
+ void *lp_val;
+ dladm_datatype_t lp_type;
+ uint_t lp_sz;
+} dlmgmt_linkattr_t;
+
+/*
+ * datalink structure
+ */
+typedef struct dlmgmt_link_s {
+ dlmgmt_linkattr_t *ll_head;
+ char ll_link[MAXLINKNAMELEN];
+ datalink_class_t ll_class;
+ uint32_t ll_media;
+ datalink_id_t ll_linkid;
+ avl_node_t ll_node_by_name;
+ avl_node_t ll_node_by_id;
+ uint32_t ll_flags;
+ uint32_t ll_gen; /* generation number */
+} dlmgmt_link_t;
+
+/*
+ * datalink configuration request structure
+ */
+typedef struct dlmgmt_dlconf_s {
+ dlmgmt_linkattr_t *ld_head;
+ char ld_link[MAXLINKNAMELEN];
+ datalink_id_t ld_linkid;
+ datalink_class_t ld_class;
+ uint32_t ld_media;
+ int ld_id;
+ uint32_t ld_gen;
+ avl_node_t ld_node;
+} dlmgmt_dlconf_t;
+
+extern boolean_t debug;
+extern const char *progname;
+
+extern avl_tree_t dlmgmt_name_avl;
+extern avl_tree_t dlmgmt_id_avl;
+extern avl_tree_t dlmgmt_dlconf_avl;
+
+boolean_t linkattr_equal(dlmgmt_linkattr_t **, const char *, void *,
+ size_t);
+int linkattr_unset(dlmgmt_linkattr_t **, const char *);
+int linkattr_set(dlmgmt_linkattr_t **, const char *, void *,
+ size_t, dladm_datatype_t);
+int linkattr_get(dlmgmt_linkattr_t **, const char *, void **,
+ size_t *, dladm_datatype_t *);
+
+void link_destroy(dlmgmt_link_t *);
+dlmgmt_link_t *link_by_id(datalink_id_t);
+dlmgmt_link_t *link_by_name(const char *);
+int dlmgmt_create_common(const char *, datalink_class_t,
+ uint32_t, uint32_t, dlmgmt_link_t **);
+int dlmgmt_destroy_common(dlmgmt_link_t *, uint32_t);
+int dlmgmt_getattr_common(dlmgmt_linkattr_t **, const char *,
+ dlmgmt_getattr_retval_t **, size_t *);
+
+void dlmgmt_advance(dlmgmt_link_t *);
+void dlmgmt_table_lock(boolean_t);
+void dlmgmt_table_unlock();
+
+int dlconf_create(const char *, datalink_id_t, datalink_class_t,
+ uint32_t, dlmgmt_dlconf_t **);
+void dlconf_destroy(dlmgmt_dlconf_t *);
+void dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *);
+void dlmgmt_dlconf_table_lock(boolean_t);
+void dlmgmt_dlconf_table_unlock(void);
+
+int dlmgmt_generate_name(const char *, char *, size_t);
+
+int dlmgmt_linktable_init(void);
+void dlmgmt_linktable_fini(void);
+
+void dlmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t);
+void dlmgmt_log(int, const char *, ...);
+int dlmgmt_write_db_entry(datalink_id_t, uint32_t);
+int dlmgmt_delete_db_entry(datalink_id_t, uint32_t);
+int dlmgmt_db_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DLMGMT_IMPL_H */
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_main.c b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
new file mode 100644
index 0000000000..e67d95d355
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
@@ -0,0 +1,345 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The dlmgmtd daemon is started by the datalink-management SMF service.
+ * This daemon is used to manage <link name, linkid> mapping and the
+ * persistent datalink configuration.
+ *
+ * Today, the <link name, linkid> mapping and the persistent configuration
+ * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps
+ * a copy of the datalinks in the memory (see dlmgmt_id_avl and
+ * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in
+ * /etc/svc/volatile cache file, so that the mapping can be recovered when
+ * dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally killed).
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <priv.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stropts.h>
+#include <strings.h>
+#include <syslog.h>
+#include <sys/dld.h>
+#include <unistd.h>
+#include <libdlmgmt.h>
+#include "dlmgmt_impl.h"
+
+const char *progname;
+boolean_t debug;
+static int pfds[2];
+static char dlmgmt_door_file[] = DLMGMT_DOOR;
+static int dlmgmt_door_fd = -1;
+
+static int
+dlmgmt_set_doorfd(boolean_t start)
+{
+ dld_ioc_door_t did;
+ struct strioctl iocb;
+ int fd;
+ int err = 0;
+
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (EINVAL);
+
+ did.did_start_door = start;
+
+ iocb.ic_cmd = DLDIOC_DOORSERVER;
+ iocb.ic_timout = 0;
+ iocb.ic_len = sizeof (did);
+ iocb.ic_dp = (char *)&did;
+
+ if (ioctl(fd, I_STR, &iocb) == -1)
+ err = errno;
+
+ (void) close(fd);
+ return (err);
+}
+
+static int
+dlmgmt_door_init()
+{
+ int err;
+
+ if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+ err = errno;
+ dlmgmt_log(LOG_WARNING, "door_create() failed: %s",
+ strerror(err));
+ return (err);
+ }
+ if (fattach(dlmgmt_door_fd, DLMGMT_DOOR) != 0) {
+ err = errno;
+ dlmgmt_log(LOG_WARNING, "fattach(%s) failed: %s",
+ DLMGMT_DOOR, strerror(err));
+ goto fail;
+ }
+ if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) {
+ dlmgmt_log(LOG_WARNING, "cannot set kernel doorfd: %s",
+ strerror(err));
+ goto fail;
+ }
+
+ return (0);
+fail:
+ if (dlmgmt_door_fd != -1) {
+ (void) door_revoke(dlmgmt_door_fd);
+ dlmgmt_door_fd = -1;
+ }
+ (void) fdetach(DLMGMT_DOOR);
+ return (err);
+}
+
+static void
+dlmgmt_door_fini()
+{
+ (void) dlmgmt_set_doorfd(B_FALSE);
+ if ((dlmgmt_door_fd != -1) && (door_revoke(dlmgmt_door_fd) == -1)) {
+ dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
+ dlmgmt_door_file, strerror(errno));
+ }
+ (void) fdetach(DLMGMT_DOOR);
+}
+
+static int
+dlmgmt_init()
+{
+ int err;
+
+ if ((err = dlmgmt_linktable_init()) != 0)
+ return (err);
+
+ if ((err = dlmgmt_db_init()) != 0 || (err = dlmgmt_door_init()) != 0)
+ dlmgmt_linktable_fini();
+
+ return (err);
+}
+
+static void
+dlmgmt_fini()
+{
+ dlmgmt_door_fini();
+ dlmgmt_linktable_fini();
+}
+
+/*
+ * This is called by the child process to inform the parent process to
+ * exit with the given return value.
+ */
+static void
+dlmgmt_inform_parent_exit(int rv)
+{
+ if (debug)
+ return;
+
+ if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
+ dlmgmt_log(LOG_WARNING,
+ "dlmgmt_inform_parent_exit() failed: %s", strerror(errno));
+ (void) close(pfds[1]);
+ exit(EXIT_FAILURE);
+ }
+ (void) close(pfds[1]);
+}
+
+/*ARGSUSED*/
+static void
+dlmgmtd_exit(int signo)
+{
+ (void) close(pfds[1]);
+ dlmgmt_fini();
+ exit(EXIT_FAILURE);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "Usage: %s [-d]\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+static int
+dlmgmt_setup_privs()
+{
+ priv_set_t *priv_set = NULL;
+ char *p;
+
+ priv_set = priv_allocset();
+ if (priv_set == NULL || getppriv(PRIV_PERMITTED, priv_set) == -1) {
+ dlmgmt_log(LOG_WARNING, "failed to get the permitted set of "
+ "privileges %s", strerror(errno));
+ return (-1);
+ }
+
+ p = priv_set_to_str(priv_set, ',', 0);
+ dlmgmt_log(LOG_DEBUG, "start with privs %s", p != NULL ? p : "Unknown");
+ free(p);
+
+ priv_emptyset(priv_set);
+ (void) priv_addset(priv_set, "file_dac_write");
+ (void) priv_addset(priv_set, "file_chown_self");
+ (void) priv_addset(priv_set, "sys_mount");
+ (void) priv_addset(priv_set, "sys_net_config");
+
+ if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
+ dlmgmt_log(LOG_WARNING, "failed to set the inheritable set of "
+ "privileges %s", strerror(errno));
+ priv_freeset(priv_set);
+ return (-1);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, priv_set) == -1) {
+ dlmgmt_log(LOG_WARNING, "failed to set the permitted set of "
+ "privileges %s", strerror(errno));
+ priv_freeset(priv_set);
+ return (-1);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
+ dlmgmt_log(LOG_WARNING, "failed to set the effective set of "
+ "privileges %s", strerror(errno));
+ priv_freeset(priv_set);
+ return (-1);
+ }
+
+ priv_freeset(priv_set);
+ return (0);
+}
+
+/*
+ * Keep the pfds fd open, close other fds.
+ */
+/*ARGSUSED*/
+static int
+closefunc(void *arg, int fd)
+{
+ if (fd != pfds[1])
+ (void) close(fd);
+ return (0);
+}
+
+static boolean_t
+dlmgmt_daemonize(void)
+{
+ pid_t pid;
+ int rv;
+
+ if (pipe(pfds) < 0) {
+ (void) fprintf(stderr, "%s: pipe() failed: %s\n",
+ progname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if ((pid = fork()) == -1) {
+ (void) fprintf(stderr, "%s: fork() failed: %s\n",
+ progname, strerror(errno));
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) { /* Parent */
+ (void) close(pfds[1]);
+
+ /*
+ * Read the child process's return value from the pfds.
+ * If the child process exits unexpected, read() returns -1.
+ */
+ if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
+ (void) kill(pid, SIGKILL);
+ rv = EXIT_FAILURE;
+ }
+
+ (void) close(pfds[0]);
+ exit(rv);
+ }
+
+ /* Child */
+ (void) close(pfds[0]);
+ (void) setsid();
+
+ /*
+ * Close all files except pfds[1].
+ */
+ (void) fdwalk(closefunc, NULL);
+ (void) chdir("/");
+ openlog(progname, LOG_PID, LOG_DAEMON);
+ return (B_TRUE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+
+ progname = strrchr(argv[0], '/');
+ if (progname != NULL)
+ progname++;
+ else
+ progname = argv[0];
+
+ /*
+ * Process options.
+ */
+ while ((opt = getopt(argc, argv, "d")) != EOF) {
+ switch (opt) {
+ case 'd':
+ debug = B_TRUE;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (!debug && !dlmgmt_daemonize())
+ return (EXIT_FAILURE);
+
+ if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR) {
+ dlmgmt_log(LOG_WARNING, "signal() for SIGTERM failed: %s",
+ strerror(errno));
+ goto child_out;
+ }
+
+ if (dlmgmt_init() != 0)
+ goto child_out;
+
+ if (dlmgmt_setup_privs() != 0)
+ goto child_out;
+
+ /*
+ * Inform the parent process that it can successfully exit.
+ */
+ dlmgmt_inform_parent_exit(EXIT_SUCCESS);
+
+ for (;;)
+ (void) pause();
+
+child_out:
+ /* return from main() forcibly exits an MT process */
+ dlmgmt_inform_parent_exit(EXIT_FAILURE);
+ return (EXIT_FAILURE);
+}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_util.c b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
new file mode 100644
index 0000000000..06416db018
--- /dev/null
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
@@ -0,0 +1,748 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Utility functions used by the dlmgmtd daemon.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <libdlpi.h>
+#include "dlmgmt_impl.h"
+
+/*
+ * There are two datalink AVL tables. One table (dlmgmt_name_avl) is keyed by
+ * the link name, and the other (dlmgmt_id_avl) is keyed by the link id.
+ * Each link will be present in both tables.
+ */
+avl_tree_t dlmgmt_name_avl;
+avl_tree_t dlmgmt_id_avl;
+
+avl_tree_t dlmgmt_dlconf_avl;
+
+static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER;
+static pthread_mutex_t dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER;
+static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+typedef struct dlmgmt_prefix {
+ struct dlmgmt_prefix *lp_next;
+ char lp_prefix[MAXLINKNAMELEN];
+ uint_t lp_nextppa;
+} dlmgmt_prefix_t;
+static dlmgmt_prefix_t *dlmgmt_prefixlist;
+
+static datalink_id_t dlmgmt_nextlinkid;
+static datalink_id_t dlmgmt_nextconfid = 1;
+
+static int linkattr_add(dlmgmt_linkattr_t **,
+ dlmgmt_linkattr_t *);
+static int linkattr_rm(dlmgmt_linkattr_t **,
+ dlmgmt_linkattr_t *);
+static int link_create(const char *, datalink_class_t, uint32_t,
+ uint32_t, dlmgmt_link_t **);
+
+static void dlmgmt_advance_linkid(dlmgmt_link_t *);
+static void dlmgmt_advance_ppa(dlmgmt_link_t *);
+
+void
+dlmgmt_log(int pri, const char *fmt, ...)
+{
+ va_list alist;
+
+ va_start(alist, fmt);
+ if (debug) {
+ (void) vfprintf(stderr, fmt, alist);
+ (void) fputc('\n', stderr);
+ } else {
+ vsyslog(pri, fmt, alist);
+ }
+ va_end(alist);
+}
+
+static int
+cmp_link_by_name(const void *v1, const void *v2)
+{
+ const dlmgmt_link_t *link1 = v1;
+ const dlmgmt_link_t *link2 = v2;
+ int cmp;
+
+ cmp = strcmp(link1->ll_link, link2->ll_link);
+ return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1));
+}
+
+static int
+cmp_link_by_id(const void *v1, const void *v2)
+{
+ const dlmgmt_link_t *link1 = v1;
+ const dlmgmt_link_t *link2 = v2;
+
+ if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid))
+ return (0);
+ else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid))
+ return (-1);
+ else
+ return (1);
+}
+
+static int
+cmp_dlconf_by_id(const void *v1, const void *v2)
+{
+ const dlmgmt_dlconf_t *dlconfp1 = v1;
+ const dlmgmt_dlconf_t *dlconfp2 = v2;
+
+ if (dlconfp1->ld_id == dlconfp2->ld_id)
+ return (0);
+ else if (dlconfp1->ld_id < dlconfp2->ld_id)
+ return (-1);
+ else
+ return (1);
+}
+
+int
+dlmgmt_linktable_init()
+{
+ /*
+ * Initialize the prefix list. First add the "net" prefix to the list.
+ */
+ dlmgmt_prefixlist = malloc(sizeof (dlmgmt_prefix_t));
+ if (dlmgmt_prefixlist == NULL) {
+ dlmgmt_log(LOG_WARNING, "dlmgmt_linktable_init() failed: %s",
+ strerror(ENOMEM));
+ return (ENOMEM);
+ }
+
+ dlmgmt_prefixlist->lp_next = NULL;
+ dlmgmt_prefixlist->lp_nextppa = 0;
+ (void) strlcpy(dlmgmt_prefixlist->lp_prefix, "net", MAXLINKNAMELEN);
+
+ avl_create(&dlmgmt_name_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
+ offsetof(dlmgmt_link_t, ll_node_by_name));
+ avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
+ offsetof(dlmgmt_link_t, ll_node_by_id));
+ avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
+ sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
+ dlmgmt_nextlinkid = 1;
+ return (0);
+}
+
+void
+dlmgmt_linktable_fini()
+{
+ dlmgmt_prefix_t *lpp, *next;
+
+ for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = next) {
+ next = lpp->lp_next;
+ free(lpp);
+ }
+
+ avl_destroy(&dlmgmt_dlconf_avl);
+ avl_destroy(&dlmgmt_name_avl);
+ avl_destroy(&dlmgmt_id_avl);
+}
+
+static int
+linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
+{
+ if (*headp == NULL) {
+ *headp = attrp;
+ } else {
+ (*headp)->lp_prev = attrp;
+ attrp->lp_next = *headp;
+ *headp = attrp;
+ }
+ return (0);
+}
+
+static int
+linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
+{
+ dlmgmt_linkattr_t *next, *prev;
+
+ next = attrp->lp_next;
+ prev = attrp->lp_prev;
+ if (next != NULL)
+ next->lp_prev = prev;
+ if (prev != NULL)
+ prev->lp_next = next;
+ else
+ *headp = next;
+
+ return (0);
+}
+
+int
+linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
+ size_t attrsz, dladm_datatype_t type)
+{
+ dlmgmt_linkattr_t *attrp;
+ int err;
+
+ /*
+ * See whether the attr is already set.
+ */
+ for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) {
+ if (strcmp(attrp->lp_name, attr) == 0)
+ break;
+ }
+
+ if (attrp != NULL) {
+ /*
+ * It is already set. If the value changed, update it.
+ */
+ if (linkattr_equal(headp, attr, attrval, attrsz))
+ return (0);
+
+ free(attrp->lp_val);
+ } else {
+ /*
+ * It is not set yet, allocate the linkattr and prepend to the
+ * list.
+ */
+ if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL)
+ return (ENOMEM);
+
+ if ((err = linkattr_add(headp, attrp)) != 0) {
+ free(attrp);
+ return (err);
+ }
+ (void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN);
+ }
+ if ((attrp->lp_val = calloc(1, attrsz)) == NULL) {
+ (void) linkattr_rm(headp, attrp);
+ free(attrp);
+ return (ENOMEM);
+ }
+
+ bcopy(attrval, attrp->lp_val, attrsz);
+ attrp->lp_sz = attrsz;
+ attrp->lp_type = type;
+ return (0);
+}
+
+int
+linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr)
+{
+ dlmgmt_linkattr_t *attrp, *prev;
+
+ /*
+ * See whether the attr exists.
+ */
+ for (prev = NULL, attrp = *headp; attrp != NULL;
+ prev = attrp, attrp = attrp->lp_next) {
+ if (strcmp(attrp->lp_name, attr) == 0)
+ break;
+ }
+
+ /*
+ * This attribute is not set in the first place. Return success.
+ */
+ if (attrp == NULL)
+ return (0);
+
+ /*
+ * Remove this attr from the list.
+ */
+ if (prev == NULL)
+ *headp = attrp->lp_next;
+ else
+ prev->lp_next = attrp->lp_next;
+
+ free(attrp->lp_val);
+ free(attrp);
+ return (0);
+}
+
+int
+linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp,
+ size_t *attrszp, dladm_datatype_t *typep)
+{
+ dlmgmt_linkattr_t *attrp = *headp;
+
+ /*
+ * find the specific attr.
+ */
+ for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) {
+ if (strcmp(attrp->lp_name, attr) == 0)
+ break;
+ }
+
+ if (attrp == NULL)
+ return (ENOENT);
+
+ *attrvalp = attrp->lp_val;
+ *attrszp = attrp->lp_sz;
+ if (typep != NULL)
+ *typep = attrp->lp_type;
+ return (0);
+}
+
+boolean_t
+linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
+ size_t attrsz)
+{
+ void *saved_attrval;
+ size_t saved_attrsz;
+
+ if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0)
+ return (B_FALSE);
+
+ return ((saved_attrsz == attrsz) &&
+ (memcmp(saved_attrval, attrval, attrsz) == 0));
+}
+
+static int
+dlmgmt_table_readwritelock(boolean_t write)
+{
+ if (write)
+ return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock));
+ else
+ return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock));
+}
+
+void
+dlmgmt_table_lock(boolean_t write)
+{
+ (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
+ while (dlmgmt_table_readwritelock(write) == EBUSY)
+ (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex);
+
+ (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
+}
+
+void
+dlmgmt_table_unlock()
+{
+ (void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
+ (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
+ (void) pthread_cond_broadcast(&dlmgmt_avl_cv);
+ (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
+}
+
+static int
+link_create(const char *name, datalink_class_t class, uint32_t media,
+ uint32_t flags, dlmgmt_link_t **linkpp)
+{
+ dlmgmt_link_t *linkp = NULL;
+ int err = 0;
+
+ if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) {
+ err = ENOSPC;
+ goto done;
+ }
+
+ if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
+ linkp->ll_class = class;
+ linkp->ll_media = media;
+ linkp->ll_linkid = dlmgmt_nextlinkid;
+ linkp->ll_flags = flags;
+ linkp->ll_gen = 0;
+done:
+ *linkpp = linkp;
+ return (err);
+}
+
+void
+link_destroy(dlmgmt_link_t *linkp)
+{
+ dlmgmt_linkattr_t *next, *attrp;
+
+ for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
+ next = attrp->lp_next;
+ free(attrp->lp_val);
+ free(attrp);
+ }
+ free(linkp);
+}
+
+dlmgmt_link_t *
+link_by_id(datalink_id_t linkid)
+{
+ dlmgmt_link_t link;
+
+ link.ll_linkid = linkid;
+ return (avl_find(&dlmgmt_id_avl, &link, NULL));
+}
+
+dlmgmt_link_t *
+link_by_name(const char *name)
+{
+ dlmgmt_link_t link;
+
+ (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
+ return (avl_find(&dlmgmt_name_avl, &link, NULL));
+}
+
+int
+dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
+ uint32_t flags, dlmgmt_link_t **linkpp)
+{
+ dlmgmt_link_t link, *linkp, *tmp;
+ avl_index_t name_where, id_where;
+ int err;
+
+ /*
+ * Validate the link.
+ */
+ if (!dladm_valid_linkname(name))
+ return (EINVAL);
+
+ /*
+ * Check to see whether this is an existing link name.
+ */
+ (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
+ if ((linkp = avl_find(&dlmgmt_name_avl, &link, &name_where)) != NULL)
+ return (EEXIST);
+
+ if ((err = link_create(name, class, media, flags, &linkp)) != 0)
+ return (err);
+
+ link.ll_linkid = linkp->ll_linkid;
+ tmp = avl_find(&dlmgmt_id_avl, &link, &id_where);
+ assert(tmp == NULL);
+ avl_insert(&dlmgmt_name_avl, linkp, name_where);
+ avl_insert(&dlmgmt_id_avl, linkp, id_where);
+ dlmgmt_advance(linkp);
+ *linkpp = linkp;
+ return (0);
+}
+
+int
+dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
+{
+ if ((linkp->ll_flags & flags) == 0) {
+ /*
+ * The link does not exist in the specified space.
+ */
+ return (ENOENT);
+ }
+ linkp->ll_flags &= ~flags;
+ if (!(linkp->ll_flags & DLMGMT_PERSIST)) {
+ dlmgmt_linkattr_t *next, *attrp;
+
+ for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
+ next = attrp->lp_next;
+ free(attrp->lp_val);
+ free(attrp);
+ }
+ linkp->ll_head = NULL;
+ }
+
+ if (linkp->ll_flags == 0) {
+ avl_remove(&dlmgmt_id_avl, linkp);
+ avl_remove(&dlmgmt_name_avl, linkp);
+ link_destroy(linkp);
+ }
+
+ return (0);
+}
+
+int
+dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
+ dlmgmt_getattr_retval_t **retvalpp, size_t *retszp)
+{
+ int err;
+ void *attrval;
+ size_t attrsz;
+ dladm_datatype_t attrtype;
+ dlmgmt_getattr_retval_t *retvalp;
+
+ err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype);
+ if (err != 0)
+ return (err);
+
+ assert(attrsz > 0);
+ *retszp = sizeof (dlmgmt_getattr_retval_t) + attrsz - 1;
+ if ((retvalp = malloc(*retszp)) == NULL)
+ return (ENOMEM);
+
+ retvalp->lr_err = 0;
+ retvalp->lr_type = attrtype;
+ bcopy(attrval, retvalp->lr_attr, attrsz);
+ *retvalpp = retvalp;
+ return (0);
+}
+
+void
+dlmgmt_dlconf_table_lock(boolean_t write)
+{
+ if (write)
+ (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock);
+ else
+ (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock);
+}
+
+void
+dlmgmt_dlconf_table_unlock()
+{
+ (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock);
+}
+
+int
+dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
+ uint32_t media, dlmgmt_dlconf_t **dlconfpp)
+{
+ dlmgmt_dlconf_t *dlconfp = NULL;
+ int err = 0;
+
+ if (dlmgmt_nextconfid == 0) {
+ err = ENOSPC;
+ goto done;
+ }
+
+ if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+
+ (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN);
+ dlconfp->ld_linkid = linkid;
+ dlconfp->ld_class = class;
+ dlconfp->ld_media = media;
+ dlconfp->ld_id = dlmgmt_nextconfid;
+
+done:
+ *dlconfpp = dlconfp;
+ return (err);
+}
+
+void
+dlconf_destroy(dlmgmt_dlconf_t *dlconfp)
+{
+ dlmgmt_linkattr_t *next, *attrp;
+
+ for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) {
+ next = attrp->lp_next;
+ free(attrp->lp_val);
+ free(attrp);
+ }
+ free(dlconfp);
+}
+
+int
+dlmgmt_generate_name(const char *prefix, char *name, size_t size)
+{
+ dlmgmt_prefix_t *lpp, *prev = NULL;
+
+ /*
+ * See whether the requested prefix is already in the list.
+ */
+ for (lpp = dlmgmt_prefixlist; lpp != NULL; prev = lpp,
+ lpp = lpp->lp_next) {
+ if (strcmp(prefix, lpp->lp_prefix) == 0)
+ break;
+ }
+
+ /*
+ * Not found.
+ */
+ if (lpp == NULL) {
+ dlmgmt_link_t *linkp, link;
+
+ assert(prev != NULL);
+
+ /*
+ * First add this new prefix into the prefix list.
+ */
+ if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL)
+ return (ENOMEM);
+
+ prev->lp_next = lpp;
+ lpp->lp_next = NULL;
+ lpp->lp_nextppa = 0;
+ (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN);
+
+ /*
+ * Now determine this prefix's nextppa.
+ */
+ (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d",
+ prefix, lpp->lp_nextppa);
+ linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
+ if (linkp != NULL)
+ dlmgmt_advance_ppa(linkp);
+ }
+
+ if (lpp->lp_nextppa == (uint_t)-1)
+ return (ENOSPC);
+
+ (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa);
+ return (0);
+}
+
+/*
+ * Advance the next available ppa value if the name prefix of the current
+ * link is in the prefix list.
+ */
+static void
+dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
+{
+ dlmgmt_prefix_t *lpp;
+ char prefix[MAXLINKNAMELEN];
+ uint_t start, ppa;
+
+ (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
+
+ /*
+ * See whether the requested prefix is already in the list.
+ */
+ for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
+ if (strcmp(prefix, lpp->lp_prefix) == 0)
+ break;
+ }
+
+ /*
+ * If the link name prefix is in the list, advance the
+ * next available ppa for the <prefix>N name.
+ */
+ if (lpp == NULL || lpp->lp_nextppa != ppa)
+ return;
+
+ start = lpp->lp_nextppa++;
+ linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
+ while (lpp->lp_nextppa != start) {
+ if (lpp->lp_nextppa == (uint_t)-1) {
+ dlmgmt_link_t link;
+
+ /*
+ * wrapped around. search from <prefix>1.
+ */
+ lpp->lp_nextppa = 0;
+ (void) snprintf(link.ll_link, MAXLINKNAMELEN,
+ "%s%d", lpp->lp_prefix, lpp->lp_nextppa);
+ linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
+ if (linkp == NULL)
+ return;
+ } else {
+ if (linkp == NULL)
+ return;
+ (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
+ if ((strcmp(prefix, lpp->lp_prefix) != 0) ||
+ (ppa != lpp->lp_nextppa)) {
+ return;
+ }
+ }
+ linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
+ lpp->lp_nextppa++;
+ }
+ lpp->lp_nextppa = (uint_t)-1;
+}
+
+/*
+ * Advance to the next available linkid value.
+ */
+static void
+dlmgmt_advance_linkid(dlmgmt_link_t *linkp)
+{
+ datalink_id_t start;
+
+ if (linkp->ll_linkid != dlmgmt_nextlinkid)
+ return;
+
+ start = dlmgmt_nextlinkid;
+ linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
+
+ do {
+ if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) {
+ dlmgmt_link_t link;
+
+ /*
+ * wrapped around. search from 1.
+ */
+ dlmgmt_nextlinkid = 1;
+ link.ll_linkid = 1;
+ linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
+ if (linkp == NULL)
+ return;
+ } else {
+ dlmgmt_nextlinkid++;
+ if (linkp == NULL)
+ return;
+ if (linkp->ll_linkid != dlmgmt_nextlinkid)
+ return;
+ }
+
+ linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
+ } while (dlmgmt_nextlinkid != start);
+
+ dlmgmt_nextlinkid = DATALINK_INVALID_LINKID;
+}
+
+/*
+ * Advance various global values, for example, next linkid value, next ppa for
+ * various prefix etc.
+ */
+void
+dlmgmt_advance(dlmgmt_link_t *linkp)
+{
+ dlmgmt_advance_linkid(linkp);
+ dlmgmt_advance_ppa(linkp);
+}
+
+/*
+ * Advance to the next available dlconf id.
+ */
+void
+dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp)
+{
+ uint_t start;
+
+ start = dlmgmt_nextconfid++;
+ dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
+ while (dlmgmt_nextconfid != start) {
+ if (dlmgmt_nextconfid == 0) {
+ dlmgmt_dlconf_t dlconf;
+
+ /*
+ * wrapped around. search from 1.
+ */
+ dlconf.ld_id = dlmgmt_nextconfid = 1;
+ dlconfp = avl_find(&dlmgmt_name_avl, &dlconf, NULL);
+ if (dlconfp == NULL)
+ return;
+ } else {
+ if ((dlconfp == NULL) ||
+ (dlconfp->ld_id != dlmgmt_nextconfid)) {
+ return;
+ }
+ }
+ dlconfp = AVL_NEXT(&dlmgmt_name_avl, dlconfp);
+ dlmgmt_nextconfid++;
+ }
+ dlmgmt_nextconfid = 0;
+}
diff --git a/usr/src/cmd/dladm/aggregation.conf b/usr/src/cmd/dlmgmtd/svc-dlmgmtd
index 5cb5189578..7559207535 100644
--- a/usr/src/cmd/dladm/aggregation.conf
+++ b/usr/src/cmd/dlmgmtd/svc-dlmgmtd
@@ -1,10 +1,10 @@
+#!/sbin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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
# or http://www.opensolaris.org/os/licensing.
@@ -19,13 +19,27 @@
#
# CDDL HEADER END
#
+
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
-#
-# DO NOT EDIT OR PARSE THIS FILE!
-#
-# Use the dladm(1m) command to change the contents of this file.
+. /lib/svc/share/smf_include.sh
+
+# The real daemon is not started in a non-global zone. But we need to
+# create a dummy background process to preserve contract lifetime.
+
+if smf_is_nonglobalzone; then
+ (while true ; do sleep 3600 ; done) &
+ exit $SMF_EXIT_OK
+fi
+
+# Start the dlmgmtd daemon.
+/sbin/dlmgmtd
+if [ $? = 0 ]; then
+ exit $SMF_EXIT_OK
+else
+ exit $SMF_EXIT_ERR_FATAL
+fi
diff --git a/usr/src/cmd/rcm_daemon/Makefile.com b/usr/src/cmd/rcm_daemon/Makefile.com
index 4b189c4b32..00a36402f8 100644
--- a/usr/src/cmd/rcm_daemon/Makefile.com
+++ b/usr/src/cmd/rcm_daemon/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -50,6 +50,8 @@ COMMON_MOD_SRC = \
$(COMMON)/dump_rcm.c \
$(COMMON)/swap_rcm.c \
$(COMMON)/network_rcm.c \
+ $(COMMON)/vlan_rcm.c \
+ $(COMMON)/aggr_rcm.c \
$(COMMON)/ip_rcm.c \
$(COMMON)/cluster_rcm.c \
$(COMMON)/pool_rcm.c \
@@ -64,6 +66,8 @@ COMMON_MOD_OBJ = \
dump_rcm.o \
swap_rcm.o \
network_rcm.o \
+ vlan_rcm.o \
+ aggr_rcm.o \
ip_rcm.o \
cluster_rcm.o \
pool_rcm.o \
@@ -80,6 +84,8 @@ COMMON_RCM_MODS = \
SUNW_dump_rcm.so \
SUNW_swap_rcm.so \
SUNW_network_rcm.so \
+ SUNW_vlan_rcm.so \
+ SUNW_aggr_rcm.so \
SUNW_ip_rcm.so \
SUNW_cluster_rcm.so \
SUNW_pool_rcm.so \
@@ -110,7 +116,9 @@ LDLIBS_MODULES =
SUNW_pool_rcm.so := LDLIBS_MODULES += -L$(ROOT)/usr/lib -lpool
SUNW_svm_rcm.so := LDLIBS_MODULES += -L$(ROOT)/usr/lib -lmeta
SUNW_network_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
-SUNW_ip_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil
+SUNW_vlan_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
+SUNW_aggr_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
+SUNW_ip_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil -ldladm
SUNW_ip_anon_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil
LDLIBS += -lgen -lelf -lrcm -lnvpair -ldevinfo -lnsl -lsocket
diff --git a/usr/src/cmd/rcm_daemon/common/aggr_rcm.c b/usr/src/cmd/rcm_daemon/common/aggr_rcm.c
new file mode 100644
index 0000000000..b3d6eeb358
--- /dev/null
+++ b/usr/src/cmd/rcm_daemon/common/aggr_rcm.c
@@ -0,0 +1,1455 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This RCM module adds support to the RCM framework for AGGR links
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <alloca.h>
+#include <sys/types.h>
+#include <sys/aggr.h>
+#include <synch.h>
+#include <assert.h>
+#include <strings.h>
+#include "rcm_module.h"
+#include <libintl.h>
+#include <libdllink.h>
+#include <libdlaggr.h>
+
+/*
+ * Definitions
+ */
+#ifndef lint
+#define _(x) gettext(x)
+#else
+#define _(x) x
+#endif
+
+/* Some generic well-knowns and defaults used in this module */
+#define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
+#define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
+
+/* AGGR link representation */
+typedef struct dl_aggr {
+ struct dl_aggr *da_next; /* next AGGR on the system */
+ struct dl_aggr *da_prev; /* prev AGGR on the system */
+ boolean_t da_stale; /* AGGR link is stale? */
+ datalink_id_t da_aggrid;
+ datalink_id_t da_lastport;
+} dl_aggr_t;
+
+/* AGGR Cache state flags */
+typedef enum {
+ CACHE_NODE_STALE = 0x01, /* stale cached data */
+ CACHE_NODE_NEW = 0x02, /* new cached nodes */
+ CACHE_NODE_OFFLINED = 0x04, /* node offlined */
+ CACHE_AGGR_PORT_OFFLINED = 0x08, /* aggr port offlined */
+ CACHE_AGGR_CONSUMER_OFFLINED = 0x10 /* consumers offlined */
+} cache_node_state_t;
+
+/* Network Cache lookup options */
+#define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
+#define CACHE_REFRESH 0x2 /* refresh cache */
+
+/*
+ * Cache element. It is used to keep a list of links on the system and
+ * their associated aggregations.
+ */
+typedef struct link_cache {
+ struct link_cache *vc_next; /* next cached resource */
+ struct link_cache *vc_prev; /* prev cached resource */
+ char *vc_resource; /* resource name */
+ datalink_id_t vc_linkid; /* linkid */
+ dl_aggr_t *vc_aggr; /* AGGR on this link */
+ cache_node_state_t vc_state; /* cache state flags */
+} link_cache_t;
+
+/*
+ * Global cache for network AGGRs
+ */
+static link_cache_t cache_head;
+static link_cache_t cache_tail;
+static mutex_t cache_lock;
+static dl_aggr_t aggr_head;
+static dl_aggr_t aggr_tail;
+static mutex_t aggr_list_lock;
+static int events_registered = 0;
+
+/*
+ * RCM module interface prototypes
+ */
+static int aggr_register(rcm_handle_t *);
+static int aggr_unregister(rcm_handle_t *);
+static int aggr_get_info(rcm_handle_t *, char *, id_t, uint_t,
+ char **, char **, nvlist_t *, rcm_info_t **);
+static int aggr_suspend(rcm_handle_t *, char *, id_t,
+ timespec_t *, uint_t, char **, rcm_info_t **);
+static int aggr_resume(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int aggr_offline(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int aggr_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int aggr_remove(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int aggr_notify_event(rcm_handle_t *, char *, id_t, uint_t,
+ char **, nvlist_t *, rcm_info_t **);
+static int aggr_configure_all(rcm_handle_t *, datalink_id_t,
+ boolean_t *);
+
+/* Module private routines */
+static int cache_update(rcm_handle_t *);
+static void cache_remove(link_cache_t *);
+static void cache_insert(link_cache_t *);
+static void node_free(link_cache_t *);
+static void aggr_list_remove(dl_aggr_t *);
+static void aggr_list_insert(dl_aggr_t *);
+static void aggr_list_free();
+static link_cache_t *cache_lookup(rcm_handle_t *, char *, char);
+static int aggr_consumer_offline(rcm_handle_t *, link_cache_t *,
+ char **, uint_t, rcm_info_t **);
+static int aggr_consumer_online(rcm_handle_t *, link_cache_t *,
+ char **, uint_t, rcm_info_t **);
+static int aggr_offline_port(link_cache_t *, cache_node_state_t);
+static int aggr_online_port(link_cache_t *, boolean_t *);
+static char *aggr_usage(link_cache_t *);
+static void aggr_log_err(datalink_id_t, char **, char *);
+static int aggr_consumer_notify(rcm_handle_t *, datalink_id_t,
+ char **, uint_t, rcm_info_t **);
+
+/* Module-Private data */
+static struct rcm_mod_ops aggr_ops =
+{
+ RCM_MOD_OPS_VERSION,
+ aggr_register,
+ aggr_unregister,
+ aggr_get_info,
+ aggr_suspend,
+ aggr_resume,
+ aggr_offline,
+ aggr_undo_offline,
+ aggr_remove,
+ NULL,
+ NULL,
+ aggr_notify_event
+};
+
+/*
+ * rcm_mod_init() - Update registrations, and return the ops structure.
+ */
+struct rcm_mod_ops *
+rcm_mod_init(void)
+{
+ rcm_log_message(RCM_TRACE1, "AGGR: mod_init\n");
+
+ cache_head.vc_next = &cache_tail;
+ cache_head.vc_prev = NULL;
+ cache_tail.vc_prev = &cache_head;
+ cache_tail.vc_next = NULL;
+ (void) mutex_init(&cache_lock, 0, NULL);
+ aggr_head.da_next = &aggr_tail;
+ aggr_head.da_prev = NULL;
+ aggr_tail.da_prev = &aggr_head;
+ aggr_tail.da_next = NULL;
+ (void) mutex_init(&aggr_list_lock, NULL, NULL);
+
+ /* Return the ops vectors */
+ return (&aggr_ops);
+}
+
+/*
+ * rcm_mod_info() - Return a string describing this module.
+ */
+const char *
+rcm_mod_info(void)
+{
+ rcm_log_message(RCM_TRACE1, "AGGR: mod_info\n");
+
+ return ("AGGR module version %I%");
+}
+
+/*
+ * rcm_mod_fini() - Destroy the network AGGR cache.
+ */
+int
+rcm_mod_fini(void)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: mod_fini\n");
+
+ /*
+ * Note that aggr_unregister() does not seem to be called anywhere,
+ * therefore we free the cache nodes here. In theory we should call
+ * rcm_register_interest() for each node before we free it, the
+ * framework does not provide the rcm_handle to allow us to do so.
+ */
+ (void) mutex_lock(&cache_lock);
+ node = cache_head.vc_next;
+ while (node != &cache_tail) {
+ cache_remove(node);
+ node_free(node);
+ node = cache_head.vc_next;
+ }
+ (void) mutex_unlock(&cache_lock);
+ (void) mutex_destroy(&cache_lock);
+
+ aggr_list_free();
+ (void) mutex_destroy(&aggr_list_lock);
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_list_insert - Insert an aggr in the global aggr list
+ */
+static void
+aggr_list_insert(dl_aggr_t *aggr)
+{
+ assert(MUTEX_HELD(&aggr_list_lock));
+
+ /* insert at the head for best performance */
+ aggr->da_next = aggr_head.da_next;
+ aggr->da_prev = &aggr_head;
+
+ aggr->da_next->da_prev = aggr;
+ aggr->da_prev->da_next = aggr;
+}
+
+/*
+ * aggr_list_remove - Remove an aggr from the global aggr list
+ */
+static void
+aggr_list_remove(dl_aggr_t *aggr)
+{
+ assert(MUTEX_HELD(&aggr_list_lock));
+ aggr->da_next->da_prev = aggr->da_prev;
+ aggr->da_prev->da_next = aggr->da_next;
+ aggr->da_next = NULL;
+ aggr->da_prev = NULL;
+}
+
+static void
+aggr_list_free()
+{
+ dl_aggr_t *aggr;
+
+ (void) mutex_lock(&aggr_list_lock);
+ aggr = aggr_head.da_next;
+ while (aggr != &aggr_tail) {
+ aggr_list_remove(aggr);
+ free(aggr);
+ aggr = aggr_head.da_next;
+ }
+ (void) mutex_unlock(&aggr_list_lock);
+}
+
+/*
+ * aggr_register() - Make sure the cache is properly sync'ed, and its
+ * registrations are in order.
+ */
+static int
+aggr_register(rcm_handle_t *hd)
+{
+ rcm_log_message(RCM_TRACE1, "AGGR: register\n");
+
+ if (cache_update(hd) < 0)
+ return (RCM_FAILURE);
+
+ /*
+ * Need to register interest in all new resources
+ * getting attached, so we get attach event notifications
+ */
+ if (!events_registered) {
+ if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to register %s\n"),
+ RCM_RESOURCE_LINK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, "AGGR: registered %s\n",
+ RCM_RESOURCE_LINK_NEW);
+ events_registered++;
+ }
+ }
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_unregister() - Walk the cache, unregistering all the networks.
+ */
+static int
+aggr_unregister(rcm_handle_t *hd)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: unregister\n");
+
+ /* Walk the cache, unregistering everything */
+ (void) mutex_lock(&cache_lock);
+ node = cache_head.vc_next;
+ while (node != &cache_tail) {
+ if (rcm_unregister_interest(hd, node->vc_resource, 0)
+ != RCM_SUCCESS) {
+ /* unregister failed for whatever reason */
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to unregister %s\n"),
+ node->vc_resource);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+ cache_remove(node);
+ node_free(node);
+ node = cache_head.vc_next;
+ }
+ (void) mutex_unlock(&cache_lock);
+
+ aggr_list_free();
+
+ /*
+ * Unregister interest in all new resources
+ */
+ if (events_registered) {
+ if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to unregister %s\n"),
+ RCM_RESOURCE_LINK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, "AGGR: unregistered %s\n",
+ RCM_RESOURCE_LINK_NEW);
+ events_registered--;
+ }
+ }
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_offline() - Offline AGGRs on a specific link.
+ */
+static int
+aggr_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **depend_info)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: offline(%s)\n", rsrc);
+
+ /* Lock the cache and lookup the resource */
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_REFRESH);
+ if (node == NULL) {
+ /* should not happen because the resource is registered. */
+ aggr_log_err(DATALINK_INVALID_LINKID, errorp,
+ "offline, unrecognized resource");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+ }
+
+ /*
+ * If this given link is the only port in the aggregation, inform
+ * VLANs and IP interfaces on associated AGGRs to be offlined
+ */
+ if (node->vc_aggr->da_lastport == node->vc_linkid) {
+ if (aggr_consumer_offline(hd, node, errorp, flags,
+ depend_info) == RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: consumers agreed on offline\n");
+ } else {
+ aggr_log_err(node->vc_linkid, errorp,
+ "consumers offline failed");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+ }
+
+ /* Check if it's a query */
+ if (flags & RCM_QUERY) {
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: offline query succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+ }
+
+ if (aggr_offline_port(node, CACHE_NODE_OFFLINED) != RCM_SUCCESS) {
+ aggr_log_err(node->vc_linkid, errorp, "offline port failed");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+
+ rcm_log_message(RCM_TRACE1, "AGGR: Offline succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_undo_offline() - Undo offline of a previously offlined link.
+ */
+/*ARGSUSED*/
+static int
+aggr_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **depend_info)
+{
+ link_cache_t *node;
+ boolean_t up;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: online(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node == NULL) {
+ aggr_log_err(DATALINK_INVALID_LINKID, errorp,
+ "undo offline, unrecognized resource");
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ /* Check if no attempt should be made to online the link here */
+ if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
+ aggr_log_err(node->vc_linkid, errorp, "resource not offlined");
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOTSUP;
+ return (RCM_SUCCESS);
+ }
+
+ if (aggr_online_port(node, &up) != RCM_SUCCESS) {
+ aggr_log_err(node->vc_linkid, errorp, "online failed");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+
+ /*
+ * Inform VLANs and IP interfaces on associated AGGRs to be online
+ */
+ if (!up)
+ goto done;
+
+ if (aggr_consumer_online(hd, node, errorp, flags, depend_info) ==
+ RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG, "AGGR: Consumers agree on online");
+ } else {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: Consumers online failed (%s)\n"), rsrc);
+ }
+
+done:
+ node->vc_state &= ~CACHE_NODE_OFFLINED;
+ rcm_log_message(RCM_TRACE1, "AGGR: online succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+}
+
+static int
+aggr_offline_port(link_cache_t *node, cache_node_state_t state)
+{
+ dl_aggr_t *aggr;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+ dladm_aggr_port_attr_db_t port;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_offline_port %s\n",
+ node->vc_resource);
+
+ aggr = node->vc_aggr;
+
+ /*
+ * Try to remove the given port from the AGGR or delete the AGGR
+ */
+ if (aggr->da_lastport == node->vc_linkid) {
+ rcm_log_message(RCM_TRACE2, "AGGR: delete aggregation %u\n",
+ aggr->da_aggrid);
+ status = dladm_aggr_delete(aggr->da_aggrid, DLADM_OPT_ACTIVE);
+ } else {
+ rcm_log_message(RCM_TRACE2,
+ "AGGR: remove port (%s) from aggregation %u\n",
+ node->vc_resource, aggr->da_aggrid);
+ port.lp_linkid = node->vc_linkid;
+ status = dladm_aggr_remove(aggr->da_aggrid, 1, &port,
+ DLADM_OPT_ACTIVE);
+ }
+ if (status != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: AGGR offline port failed (%u): %s\n"),
+ aggr->da_aggrid, dladm_status2str(status, errmsg));
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: AGGR offline port succeeded (%u)\n",
+ aggr->da_aggrid);
+ node->vc_state |= (CACHE_AGGR_PORT_OFFLINED | state);
+ return (RCM_SUCCESS);
+ }
+}
+
+static int
+aggr_online_port(link_cache_t *node, boolean_t *up)
+{
+ dl_aggr_t *aggr;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+ dladm_aggr_port_attr_db_t port;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_online_port %s\n",
+ node->vc_resource);
+
+ *up = B_FALSE;
+ if (!(node->vc_state & CACHE_AGGR_PORT_OFFLINED))
+ return (RCM_SUCCESS);
+
+ /*
+ * Either add the port into the AGGR or recreate specific AGGR
+ * depending on whether this link is the only port in the aggregation.
+ */
+ aggr = node->vc_aggr;
+ if (aggr->da_lastport == node->vc_linkid) {
+ rcm_log_message(RCM_TRACE2, "AGGR: delete aggregation %u\n",
+ aggr->da_aggrid);
+ status = dladm_aggr_up(aggr->da_aggrid);
+ *up = B_TRUE;
+ } else {
+ rcm_log_message(RCM_TRACE2,
+ "AGGR: add port (%s) to aggregation %u\n",
+ node->vc_resource, aggr->da_aggrid);
+ port.lp_linkid = node->vc_linkid;
+ status = dladm_aggr_add(aggr->da_aggrid, 1, &port,
+ DLADM_OPT_ACTIVE);
+ }
+ if (status != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: AGGR online failed (%u): %s\n"),
+ aggr->da_aggrid, dladm_status2str(status, errmsg));
+ *up = B_FALSE;
+ return (RCM_FAILURE);
+ }
+ node->vc_state &= ~CACHE_AGGR_PORT_OFFLINED;
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_get_info() - Gather usage information for this resource.
+ */
+/*ARGSUSED*/
+int
+aggr_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: get_info(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_REFRESH);
+ if (node == NULL) {
+ rcm_log_message(RCM_INFO,
+ _("AGGR: get_info(%s) unrecognized resource\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ /*
+ * *usagep will be freed by the caller.
+ */
+ *usagep = aggr_usage(node);
+ (void) mutex_unlock(&cache_lock);
+
+ if (*usagep == NULL) {
+ /* most likely malloc failure */
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: get_info(%s) malloc failure\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOMEM;
+ return (RCM_FAILURE);
+ }
+
+ /* Set client/role properties */
+ (void) nvlist_add_string(props, RCM_CLIENT_NAME, "AGGR");
+ rcm_log_message(RCM_TRACE1, "AGGR: get_info(%s) info = %s\n",
+ rsrc, *usagep);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_suspend() - Nothing to do, always okay
+ */
+/*ARGSUSED*/
+static int
+aggr_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
+ uint_t flags, char **errorp, rcm_info_t **depend_info)
+{
+ rcm_log_message(RCM_TRACE1, "AGGR: suspend(%s)\n", rsrc);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_resume() - Nothing to do, always okay
+ */
+/*ARGSUSED*/
+static int
+aggr_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **depend_info)
+{
+ rcm_log_message(RCM_TRACE1, "AGGR: resume(%s)\n", rsrc);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * aggr_remove() - remove a resource from cache
+ */
+/*ARGSUSED*/
+static int
+aggr_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **depend_info)
+{
+ link_cache_t *node;
+ char *exported;
+ dl_aggr_t *aggr;
+ int rv = RCM_SUCCESS;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: remove(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node == NULL) {
+ rcm_log_message(RCM_INFO,
+ _("AGGR: remove(%s) unrecognized resource\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ /* remove the cached entry for the resource */
+ cache_remove(node);
+ (void) mutex_unlock(&cache_lock);
+
+ /*
+ * If this link is not the only port in the associated aggregation,
+ * the CACHE_AGGR_CONSUMER_OFFLINED flags won't be set.
+ */
+ if (node->vc_state & CACHE_AGGR_CONSUMER_OFFLINED) {
+ aggr = node->vc_aggr;
+ exported = alloca(RCM_LINK_RESOURCE_MAX);
+ (void) snprintf(exported, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, aggr->da_aggrid);
+ rv = rcm_notify_remove(hd, exported, flags, depend_info);
+ if (rv != RCM_SUCCESS) {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: failed to notify remove dependent %s\n"),
+ exported);
+ }
+ }
+
+ node_free(node);
+ return (rv);
+}
+
+/*
+ * aggr_notify_event - Project private implementation to receive new resource
+ * events. It intercepts all new resource events. If the
+ * new resource is a network resource, pass up a notify
+ * for it too. The new resource need not be cached, since
+ * it is done at register again.
+ */
+/*ARGSUSED*/
+static int
+aggr_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
+{
+ nvpair_t *nvp = NULL;
+ datalink_id_t linkid;
+ uint64_t id64;
+ boolean_t up;
+ int rv = RCM_SUCCESS;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: notify_event(%s)\n", rsrc);
+
+ if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
+ aggr_log_err(DATALINK_INVALID_LINKID, errorp,
+ "unrecognized event");
+ errno = EINVAL;
+ return (RCM_FAILURE);
+ }
+
+ /* Update cache to reflect latest AGGRs */
+ if (cache_update(hd) < 0) {
+ aggr_log_err(DATALINK_INVALID_LINKID, errorp,
+ "private Cache update failed");
+ return (RCM_FAILURE);
+ }
+
+ /* Process the nvlist for the event */
+ rcm_log_message(RCM_TRACE1, "AGGR: process_nvlist\n");
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+
+ if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
+ continue;
+
+ if (nvpair_value_uint64(nvp, &id64) != 0) {
+ aggr_log_err(DATALINK_INVALID_LINKID, errorp,
+ "cannot get linkid");
+ return (RCM_FAILURE);
+ }
+
+ linkid = (datalink_id_t)id64;
+ if (aggr_configure_all(hd, linkid, &up) != 0) {
+ aggr_log_err(linkid, errorp,
+ "failed configuring AGGR links");
+ rv = RCM_FAILURE;
+ }
+
+ /* Notify all VLAN and IP AGGR consumers */
+ if (up && aggr_consumer_notify(hd, linkid, errorp, flags,
+ depend_info) != 0) {
+ aggr_log_err(linkid, errorp, "consumer notify failed");
+ rv = RCM_FAILURE;
+ }
+ }
+
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: notify_event: link configuration complete\n");
+ return (rv);
+}
+
+/*
+ * aggr_usage - Determine the usage of a link.
+ * The returned buffer is owned by caller, and the caller
+ * must free it up when done.
+ */
+static char *
+aggr_usage(link_cache_t *node)
+{
+ char *buf;
+ const char *fmt;
+ char errmsg[DLADM_STRSIZE];
+ char name[MAXLINKNAMELEN];
+ dladm_status_t status;
+ size_t bufsz;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: usage(%s)\n", node->vc_resource);
+ assert(MUTEX_HELD(&cache_lock));
+
+ if (node->vc_state & CACHE_NODE_OFFLINED)
+ fmt = _("%s offlined");
+ else
+ fmt = _("%s is part of AGGR ");
+
+ if ((status = dladm_datalink_id2info(node->vc_linkid, NULL, NULL,
+ NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: usage(%s) get port name failure(%s)\n"),
+ node->vc_resource, dladm_status2str(status, errmsg));
+ return (NULL);
+ }
+
+ /* space for resources and message */
+ bufsz = MAXLINKNAMELEN + strlen(fmt) + strlen(name) + 1;
+ if ((buf = malloc(bufsz)) == NULL) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: usage(%s) malloc failure(%s)\n"),
+ node->vc_resource, strerror(errno));
+ return (NULL);
+ }
+ (void) snprintf(buf, bufsz, fmt, name);
+
+ if (node->vc_state & CACHE_NODE_OFFLINED) {
+ /* Nothing else to do */
+ rcm_log_message(RCM_TRACE2, "AGGR: usage (%s) info = %s\n",
+ node->vc_resource, buf);
+ return (buf);
+ }
+
+ if ((status = dladm_datalink_id2info(node->vc_aggr->da_aggrid, NULL,
+ NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: usage(%s) get aggr %u name failure(%s)\n"),
+ node->vc_resource, node->vc_aggr->da_aggrid,
+ dladm_status2str(status, errmsg));
+ (void) free(buf);
+ return (NULL);
+ }
+
+ (void) strlcat(buf, name, bufsz);
+
+ rcm_log_message(RCM_TRACE2, "AGGR: usage (%s) info = %s\n",
+ node->vc_resource, buf);
+ return (buf);
+}
+
+/*
+ * Cache management routines, all cache management functions should be
+ * be called with cache_lock held.
+ */
+
+/*
+ * cache_lookup() - Get a cache node for a resource.
+ * Call with cache lock held.
+ *
+ * This ensures that the cache is consistent with the system state and
+ * returns a pointer to the cache element corresponding to the resource.
+ */
+static link_cache_t *
+cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: cache lookup(%s)\n", rsrc);
+ assert(MUTEX_HELD(&cache_lock));
+
+ if (options & CACHE_REFRESH) {
+ /* drop lock since update locks cache again */
+ (void) mutex_unlock(&cache_lock);
+ (void) cache_update(hd);
+ (void) mutex_lock(&cache_lock);
+ }
+
+ node = cache_head.vc_next;
+ for (; node != &cache_tail; node = node->vc_next) {
+ if (strcmp(rsrc, node->vc_resource) == 0) {
+ rcm_log_message(RCM_TRACE2,
+ "AGGR: cache lookup succeeded(%s)\n", rsrc);
+ return (node);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * node_free - Free a node from the cache
+ */
+static void
+node_free(link_cache_t *node)
+{
+ free(node->vc_resource);
+ free(node);
+}
+
+/*
+ * cache_insert - Insert a resource node in cache
+ */
+static void
+cache_insert(link_cache_t *node)
+{
+ assert(MUTEX_HELD(&cache_lock));
+
+ /* insert at the head for best performance */
+ node->vc_next = cache_head.vc_next;
+ node->vc_prev = &cache_head;
+
+ node->vc_next->vc_prev = node;
+ node->vc_prev->vc_next = node;
+}
+
+/*
+ * cache_remove() - Remove a resource node from cache.
+ * Call with the cache_lock held.
+ */
+static void
+cache_remove(link_cache_t *node)
+{
+ assert(MUTEX_HELD(&cache_lock));
+ node->vc_next->vc_prev = node->vc_prev;
+ node->vc_prev->vc_next = node->vc_next;
+ node->vc_next = NULL;
+ node->vc_prev = NULL;
+}
+
+static int
+aggr_port_update(rcm_handle_t *hd, dl_aggr_t *aggr, datalink_id_t portid)
+{
+ link_cache_t *node;
+ char *rsrc;
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: aggr_port_update aggr:%u port:%u\n",
+ aggr->da_aggrid, portid);
+ assert(MUTEX_HELD(&cache_lock));
+
+ rsrc = malloc(RCM_LINK_RESOURCE_MAX);
+ if (rsrc == NULL) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: resource malloc error(%s)\n"), strerror(errno));
+ goto done;
+ }
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, portid);
+
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node != NULL) {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: %s already registered (aggrid:%u)\n",
+ rsrc, aggr->da_aggrid);
+
+ free(rsrc);
+ node->vc_state &= ~CACHE_NODE_STALE;
+
+ assert(node->vc_linkid == portid);
+ /*
+ * Update vc_aggr directly as only one aggregation can be
+ * created on one port.
+ */
+ node->vc_aggr = aggr;
+ } else {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: %s is a new resource (aggrid:%u)\n",
+ rsrc, aggr->da_aggrid);
+
+ node = calloc(1, sizeof (link_cache_t));
+ if (node == NULL) {
+ free(rsrc);
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: calloc: %s\n"), strerror(errno));
+ return (ret);
+ }
+
+ node->vc_resource = rsrc;
+ node->vc_aggr = aggr;
+ node->vc_linkid = portid;
+ node->vc_state |= CACHE_NODE_NEW;
+
+
+ cache_insert(node);
+ }
+
+ ret = 0;
+done:
+ return (ret);
+}
+
+typedef struct aggr_update_arg_s {
+ rcm_handle_t *hd;
+ int retval;
+} aggr_update_arg_t;
+
+/*
+ * aggr_update() - Update physical interface properties
+ */
+static int
+aggr_update(datalink_id_t aggrid, void *arg)
+{
+ aggr_update_arg_t *aggr_update_argp = arg;
+ rcm_handle_t *hd = aggr_update_argp->hd;
+ dladm_aggr_grp_attr_t aggr_attr;
+ dl_aggr_t *aggr;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+ boolean_t exist = B_FALSE;
+ uint32_t i;
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE1, "AGGR: aggr_update(%u)\n", aggrid);
+
+ assert(MUTEX_HELD(&aggr_list_lock));
+ status = dladm_aggr_info(aggrid, &aggr_attr, DLADM_OPT_ACTIVE);
+ if (status != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: cannot get aggr information for %u error(%s)\n",
+ aggrid, dladm_status2str(status, errmsg));
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ /*
+ * Try to find the aggr from the aggr list.
+ */
+ for (aggr = aggr_head.da_next; aggr != &aggr_tail; aggr = aggr->da_next)
+ if (aggr->da_aggrid == aggr_attr.lg_linkid)
+ break;
+
+ if (aggr != NULL) {
+ exist = B_TRUE;
+ } else {
+ if ((aggr = calloc(1, sizeof (dl_aggr_t))) == NULL) {
+ rcm_log_message(RCM_ERROR, _("AGGR: malloc: %s\n"),
+ strerror(errno));
+ goto done;
+ }
+ }
+
+ /* Update aggregation information. */
+ if (aggr_attr.lg_nports == 1)
+ aggr->da_lastport = aggr_attr.lg_ports[0].lp_linkid;
+ else
+ aggr->da_lastport = DATALINK_INVALID_LINKID;
+ aggr->da_aggrid = aggr_attr.lg_linkid;
+
+ for (i = 0; i < aggr_attr.lg_nports; i++) {
+ datalink_id_t portid = (aggr_attr.lg_ports[i]).lp_linkid;
+
+ if (aggr_port_update(hd, aggr, portid) != 0)
+ goto done;
+ }
+
+ if (!exist)
+ aggr_list_insert(aggr);
+
+ aggr->da_stale = B_FALSE;
+ rcm_log_message(RCM_TRACE3,
+ "AGGR: aggr_update: succeeded(%u)\n", aggrid);
+
+ ret = 0;
+done:
+ if (!exist && ret != 0)
+ free(aggr);
+ free(aggr_attr.lg_ports);
+ aggr_update_argp->retval = ret;
+ return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
+}
+
+/*
+ * aggr_update_all() - Determine all AGGR links in the system
+ */
+static int
+aggr_update_all(rcm_handle_t *hd)
+{
+ aggr_update_arg_t arg = {NULL, 0};
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_update_all\n");
+ assert(MUTEX_HELD(&cache_lock));
+
+ arg.hd = hd;
+ (void) dladm_walk_datalink_id(aggr_update, &arg, DATALINK_CLASS_AGGR,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
+ return (arg.retval);
+}
+
+/*
+ * cache_update() - Update cache with latest interface info
+ */
+static int
+cache_update(rcm_handle_t *hd)
+{
+ link_cache_t *node, *next;
+ dl_aggr_t *aggr;
+ int ret = 0;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: cache_update\n");
+ (void) mutex_lock(&aggr_list_lock);
+ (void) mutex_lock(&cache_lock);
+
+ /* first we walk the entire aggr list, marking each entry stale */
+ for (aggr = aggr_head.da_next; aggr != &aggr_tail; aggr = aggr->da_next)
+ aggr->da_stale = B_TRUE;
+
+ /* then we walk the entire cache, marking each entry stale */
+ node = cache_head.vc_next;
+ for (; node != &cache_tail; node = node->vc_next)
+ node->vc_state |= CACHE_NODE_STALE;
+
+ ret = aggr_update_all(hd);
+
+ /*
+ * Even aggr_update_all() fails, continue to delete all the stale
+ * resources. First, unregister links that are not offlined and
+ * still in cache.
+ */
+ for (node = cache_head.vc_next; node != &cache_tail; node = next) {
+
+ next = node->vc_next;
+ if (node->vc_state & CACHE_NODE_STALE) {
+ (void) rcm_unregister_interest(hd, node->vc_resource,
+ 0);
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: unregistered %s\n", node->vc_resource);
+ cache_remove(node);
+ node_free(node);
+ continue;
+ }
+
+ if (!(node->vc_state & CACHE_NODE_NEW))
+ continue;
+
+ if (rcm_register_interest(hd, node->vc_resource, 0,
+
+ NULL) != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to register %s\n"),
+ node->vc_resource);
+ ret = -1;
+ } else {
+ rcm_log_message(RCM_DEBUG, "AGGR: registered %s\n",
+ node->vc_resource);
+
+ node->vc_state &= ~CACHE_NODE_NEW;
+ }
+ }
+
+ aggr = aggr_head.da_next;
+ while (aggr != &aggr_tail) {
+ dl_aggr_t *next = aggr->da_next;
+
+ /* delete stale AGGRs */
+ if (aggr->da_stale) {
+ aggr_list_remove(aggr);
+ free(aggr);
+ }
+ aggr = next;
+ }
+
+done:
+ (void) mutex_unlock(&cache_lock);
+ (void) mutex_unlock(&aggr_list_lock);
+ return (ret);
+}
+
+/*
+ * aggr_log_err() - RCM error log wrapper
+ */
+static void
+aggr_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
+{
+ char link[MAXLINKNAMELEN];
+ char errstr[DLADM_STRSIZE];
+ dladm_status_t status;
+ int len;
+ const char *errfmt;
+ char *error;
+
+ link[0] = '\0';
+ if (linkid != DATALINK_INVALID_LINKID) {
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, linkid);
+
+ rcm_log_message(RCM_ERROR, _("AGGR: %s(%s)\n"), errmsg, rsrc);
+
+ if ((status = dladm_datalink_id2info(linkid, NULL, NULL,
+ NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: cannot get link name of (%s) %s\n"),
+ rsrc, dladm_status2str(status, errstr));
+ }
+ } else {
+ rcm_log_message(RCM_ERROR, _("AGGR: %s\n"), errmsg);
+ }
+
+ errfmt = strlen(link) > 0 ? _("AGGR: %s(%s)") : _("AGGR: %s");
+ len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
+ if ((error = malloc(len)) != NULL) {
+ if (strlen(link) > 0)
+ (void) sprintf(error, errfmt, errmsg, link);
+ else
+ (void) sprintf(error, errfmt, errmsg);
+ }
+
+ if (errorp != NULL)
+ *errorp = error;
+}
+
+/*
+ * aggr_consumer_offline()
+ *
+ * Offline AGGR consumers.
+ */
+static int
+aggr_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
+ uint_t flags, rcm_info_t **depend_info)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ int ret;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_offline %s\n",
+ node->vc_resource);
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, node->vc_aggr->da_aggrid);
+
+ /*
+ * Inform associated VLANs and IP interfaces to be offlined
+ */
+ ret = rcm_request_offline(hd, rsrc, flags, depend_info);
+ if (ret != RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: rcm_request_offline failed (%s)\n", rsrc);
+ return (ret);
+ }
+
+ node->vc_state |= CACHE_AGGR_CONSUMER_OFFLINED;
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_offline done\n");
+ return (ret);
+}
+
+/*
+ * aggr_consumer_online()
+ *
+ * online AGGR consumers.
+ */
+static int
+aggr_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
+ uint_t flags, rcm_info_t **depend_info)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ int ret;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_online %s\n",
+ node->vc_resource);
+
+ if (!(node->vc_state & CACHE_AGGR_CONSUMER_OFFLINED)) {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: no consumers offlined (%s)\n", node->vc_resource);
+ return (RCM_SUCCESS);
+ }
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, node->vc_aggr->da_aggrid);
+
+ ret = rcm_notify_online(hd, rsrc, flags, depend_info);
+ if (ret != RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG,
+ "AGGR: rcm_notify_online failed (%s)\n", rsrc);
+ return (ret);
+ }
+
+ node->vc_state &= ~CACHE_AGGR_CONSUMER_OFFLINED;
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_online done\n");
+ return (ret);
+}
+
+/*
+ * Send RCM_RESOURCE_LINK_NEW events to other modules about new aggregations.
+ * Return 0 on success, -1 on failure.
+ */
+static int
+aggr_notify_new_aggr(rcm_handle_t *hd, char *rsrc)
+{
+ link_cache_t *node;
+ dl_aggr_t *aggr;
+ nvlist_t *nvl = NULL;
+ uint64_t id;
+ boolean_t is_only_port;
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_notify_new_aggr (%s)\n", rsrc);
+
+ /* Check for the interface in the cache */
+ (void) mutex_lock(&cache_lock);
+ if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: aggr_notify_new_aggr() unrecognized resource (%s)\n",
+ rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (0);
+ }
+
+ if (nvlist_alloc(&nvl, 0, 0) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: failed to allocate nvlist\n"));
+ (void) mutex_unlock(&cache_lock);
+ goto done;
+ }
+
+ aggr = node->vc_aggr;
+ is_only_port = (aggr->da_lastport == node->vc_linkid);
+
+ if (is_only_port) {
+ rcm_log_message(RCM_TRACE2,
+ "AGGR: aggr_notify_new_aggr add (%u)\n",
+ aggr->da_aggrid);
+
+ id = aggr->da_aggrid;
+ if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to construct nvlist\n"));
+ (void) mutex_unlock(&cache_lock);
+ goto done;
+ }
+ }
+
+ (void) mutex_unlock(&cache_lock);
+
+ /*
+ * If this link is not the only port in the aggregation, the aggregation
+ * is not new. No need to inform other consumers in that case.
+ */
+ if (is_only_port && rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW,
+ 0, nvl, NULL) != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("AGGR: failed to notify %s event for %s\n"),
+ RCM_RESOURCE_LINK_NEW, node->vc_resource);
+ goto done;
+ }
+
+ ret = 0;
+done:
+ if (nvl != NULL)
+ nvlist_free(nvl);
+ return (ret);
+}
+
+/*
+ * aggr_consumer_notify() - Notify consumers of AGGRs coming back online.
+ */
+static int
+aggr_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
+ uint_t flags, rcm_info_t **depend_info)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ link_cache_t *node;
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, linkid);
+
+ rcm_log_message(RCM_TRACE1, "AGGR: aggr_consumer_notify(%s)\n", rsrc);
+
+ /*
+ * Inform IP and VLAN consumers to be online.
+ */
+ if (aggr_notify_new_aggr(hd, rsrc) != 0) {
+ (void) mutex_lock(&cache_lock);
+ if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL)
+ (void) aggr_offline_port(node, CACHE_NODE_STALE);
+ (void) mutex_unlock(&cache_lock);
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: aggr_notify_new_aggr failed(%s)\n", rsrc);
+ return (-1);
+ }
+
+ rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_notify succeeded\n");
+ return (0);
+}
+
+typedef struct aggr_configure_arg {
+ datalink_id_t portid;
+ int retval;
+ boolean_t up;
+} aggr_configure_arg_t;
+
+static int
+aggr_configure(datalink_id_t aggrid, void *arg)
+{
+ aggr_configure_arg_t *aggr_configure_argp = arg;
+ datalink_id_t portid;
+ dladm_aggr_grp_attr_t aggr_attr;
+ dladm_aggr_port_attr_db_t port_attr;
+ dladm_status_t status;
+ uint32_t flags;
+ char errmsg[DLADM_STRSIZE];
+ int i;
+
+ status = dladm_datalink_id2info(aggrid, &flags, NULL, NULL, NULL, 0);
+ if (status != DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ status = dladm_aggr_info(aggrid, &aggr_attr, DLADM_OPT_PERSIST);
+ if (status != DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ portid = aggr_configure_argp->portid;
+ for (i = 0; i < aggr_attr.lg_nports; i++)
+ if (aggr_attr.lg_ports[i].lp_linkid == portid)
+ break;
+
+ if (i == aggr_attr.lg_nports) {
+ /*
+ * The aggregation doesn't contain this port.
+ */
+ free(aggr_attr.lg_ports);
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ /*
+ * If this aggregation already exists, add this port to this
+ * aggregation, otherwise, bring up this aggregation.
+ */
+ if (flags & DLADM_OPT_ACTIVE) {
+ rcm_log_message(RCM_TRACE3,
+ "AGGR: aggr_configure dladm_aggr_add port %u (%u)\n",
+ portid, aggrid);
+ port_attr.lp_linkid = portid;
+ status = dladm_aggr_add(aggrid, 1, &port_attr,
+ DLADM_OPT_ACTIVE);
+ } else {
+ rcm_log_message(RCM_TRACE3,
+ "AGGR: aggr_configure dladm_aggr_up (%u)\n", aggrid);
+ status = dladm_aggr_up(aggrid);
+ }
+
+ if (status != DLADM_STATUS_OK) {
+ /*
+ * Print a warning message and continue to UP other AGGRs.
+ */
+ rcm_log_message(RCM_WARNING,
+ _("AGGR: AGGR online failed (%u): %s\n"),
+ aggrid, dladm_status2str(status, errmsg));
+ aggr_configure_argp->retval = -1;
+ } else if (!(flags & DLADM_OPT_ACTIVE)) {
+ aggr_configure_argp->up = B_TRUE;
+ }
+
+ free(aggr_attr.lg_ports);
+ return (DLADM_WALK_TERMINATE);
+}
+
+/*
+ * aggr_configure_all() - Configure AGGRs over a physical link after it attaches
+ */
+static int
+aggr_configure_all(rcm_handle_t *hd, datalink_id_t linkid, boolean_t *up)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ link_cache_t *node;
+ aggr_configure_arg_t arg = {DATALINK_INVALID_LINKID, 0, B_FALSE};
+
+ *up = B_FALSE;
+
+ /* Check for the AGGRs in the cache */
+ (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
+
+ rcm_log_message(RCM_TRACE1, "AGGR: aggr_configure_all(%s)\n", rsrc);
+
+ /* Check if the link is new or was previously offlined */
+ (void) mutex_lock(&cache_lock);
+ if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
+ (!(node->vc_state & CACHE_NODE_OFFLINED))) {
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: Skipping configured link(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (0);
+ }
+ (void) mutex_unlock(&cache_lock);
+
+ arg.portid = linkid;
+ (void) dladm_walk_datalink_id(aggr_configure, &arg, DATALINK_CLASS_AGGR,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
+
+ if (arg.retval == 0) {
+ *up = arg.up;
+ rcm_log_message(RCM_TRACE1,
+ "AGGR: aggr_configure_all succeeded(%s)\n", rsrc);
+ }
+ return (arg.retval);
+}
diff --git a/usr/src/cmd/rcm_daemon/common/ip_rcm.c b/usr/src/cmd/rcm_daemon/common/ip_rcm.c
index f4a896e41a..5421d7364a 100644
--- a/usr/src/cmd/rcm_daemon/common/ip_rcm.c
+++ b/usr/src/cmd/rcm_daemon/common/ip_rcm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,6 +54,7 @@
#include <netdb.h>
#include <inet/ip.h>
#include <libinetutil.h>
+#include <libdllink.h>
#include <ipmp_mpathd.h>
#include "rcm_module.h"
@@ -72,8 +73,8 @@
#define IP_MAX_MODS 9 /* max modules pushed on intr */
#define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */
-#define RCM_NET_PREFIX "SUNW_network" /* RCM network name prefix */
-#define RCM_NET_RESOURCE_MAX (13 + LIFNAMSIZ) /* RCM_NET_PREFIX+LIFNAMSIZ */
+#define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
+#define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
#define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */
#define RCM_SIZE_SUNW_IP 9 /* strlen("SUNW_ip/") + 1 */
@@ -134,13 +135,6 @@
#define MOD_REMOVE 1 /* Remove a mid-stream module */
#define MOD_CHECK 2 /* Check mid-stream module safety */
-/* VLAN format support */
-#define VLAN_MAX_PPA_ALLOWED 1000
-#define VLAN_GET_PPA(ppa) (ppa % VLAN_MAX_PPA_ALLOWED)
-
-/* devfsadm attach nvpair values */
-#define PROP_NV_DDI_NETWORK "ddi_network"
-
/*
* in.mpathd(1M) message passing formats
*/
@@ -217,31 +211,6 @@ static mutex_t cache_lock;
static int events_registered = 0;
/*
- * Global NIC list to be configured after DR-attach
- */
-#define NIL_NULL ((struct ni_list *)0)
-
-struct net_interface {
- char *type; /* Name of type of interface (le, ie, etc.) */
- char *name; /* Qualified name of interface (le0, ie0, etc.) */
-};
-
-struct ni_list {
- struct net_interface *nifp;
- struct ni_list *next;
-};
-
-static mutex_t nil_lock; /* NIC list lock */
-static int num_ni = 0; /* Global new interface count */
-static struct ni_list *nil_head = NIL_NULL; /* Global new if list */
-
-struct devfs_minor_data {
- int32_t minor_type;
- char *minor_name;
- char *minor_node_type;
-};
-
-/*
* RCM module interface prototypes
*/
static int ip_register(rcm_handle_t *);
@@ -276,7 +245,7 @@ static int if_cfginfo(ip_cache_t *, uint_t);
static int if_unplumb(ip_cache_t *);
static int if_replumb(ip_cache_t *);
static void ip_log_err(ip_cache_t *, char **, char *);
-static char *get_physical_resource(const char *);
+static char *get_link_resource(const char *);
static void clr_cfg_state(ip_pif_t *);
static uint64_t if_get_flags(ip_pif_t *);
static int mpathd_send_cmd(mpathd_cmd_t *);
@@ -291,12 +260,10 @@ static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
rcm_info_t **);
static char **ip_get_addrlist(ip_cache_t *);
static void ip_free_addrlist(char **);
-static void ip_consumer_notify(rcm_handle_t *, char *, char **, uint_t,
- rcm_info_t **);
+static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
+ uint_t, rcm_info_t **);
-static int process_nvlist(nvlist_t *);
-static void process_minor(char *, char *, int32_t, struct devfs_minor_data *);
-static int if_configure(char *);
+static int if_configure(datalink_id_t);
static int isgrouped(char *);
static int if_ipmp_config(char *, int, int);
static int if_mpathd_configure(char *, char *, int, int);
@@ -335,7 +302,6 @@ rcm_mod_init(void)
cache_tail.ip_prev = &cache_head;
cache_tail.ip_next = NULL;
(void) mutex_init(&cache_lock, NULL, NULL);
- (void) mutex_init(&nil_lock, NULL, NULL);
/* Return the ops vectors */
return (&ip_ops);
@@ -361,7 +327,6 @@ rcm_mod_fini(void)
rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
free_cache();
- (void) mutex_destroy(&nil_lock);
(void) mutex_destroy(&cache_lock);
return (RCM_SUCCESS);
}
@@ -386,15 +351,15 @@ ip_register(rcm_handle_t *hd)
* getting attached, so we get attach event notifications
*/
if (!events_registered) {
- if (rcm_register_event(hd, RCM_RESOURCE_NETWORK_NEW, 0, NULL)
+ if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
!= RCM_SUCCESS) {
rcm_log_message(RCM_ERROR,
_("IP: failed to register %s\n"),
- RCM_RESOURCE_NETWORK_NEW);
+ RCM_RESOURCE_LINK_NEW);
return (RCM_FAILURE);
} else {
rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
- RCM_RESOURCE_NETWORK_NEW);
+ RCM_RESOURCE_LINK_NEW);
events_registered++;
}
}
@@ -435,15 +400,15 @@ ip_unregister(rcm_handle_t *hd)
* Need to unregister interest in all new resources
*/
if (events_registered) {
- if (rcm_unregister_event(hd, RCM_RESOURCE_NETWORK_NEW, 0)
+ if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
!= RCM_SUCCESS) {
rcm_log_message(RCM_ERROR,
_("IP: failed to unregister %s\n"),
- RCM_RESOURCE_NETWORK_NEW);
+ RCM_RESOURCE_LINK_NEW);
return (RCM_FAILURE);
} else {
rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
- RCM_RESOURCE_NETWORK_NEW);
+ RCM_RESOURCE_LINK_NEW);
events_registered--;
}
}
@@ -828,9 +793,9 @@ static int
ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
{
- struct ni_list *nilp, *onilp;
- struct net_interface *nip;
- int n;
+ datalink_id_t linkid;
+ nvpair_t *nvp = NULL;
+ uint64_t id64;
assert(hd != NULL);
assert(rsrc != NULL);
@@ -839,7 +804,7 @@ ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
- if (!STREQ(rsrc, RCM_RESOURCE_NETWORK_NEW)) {
+ if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
rcm_log_message(RCM_INFO,
_("IP: unrecognized event for %s\n"), rsrc);
ip_log_err(NULL, errorp, "unrecognized event");
@@ -847,61 +812,37 @@ ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
return (RCM_FAILURE);
}
- /* Update cache to reflect latest interfaces */
+ /* Update cache to reflect latest interfaces */
if (update_cache(hd) < 0) {
rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
ip_log_err(NULL, errorp, "Private Cache update failed");
return (RCM_FAILURE);
}
- /* Process the nvlist for the event */
- if (process_nvlist(nvl) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: Error processing resource attributes(%s)\n"), rsrc);
- rcm_log_message(RCM_WARNING,
- _("IP: One or more devices may not be configured.\n"));
- ip_log_err(NULL, errorp, "Error processing device properties");
- /* Continue processing interfaces that were valid */
- }
-
- (void) mutex_lock(&nil_lock);
-
- /* Configure all new interfaces found */
- for (nilp = nil_head, n = 0; n < num_ni; nilp = nilp->next, n++) {
- nip = nilp->nifp;
- if (if_configure(nip->name) != 0) {
- rcm_log_message(RCM_ERROR,
- _("IP: Configuration failed (%s)\n"), nip->name);
- ip_log_err(NULL, errorp,
- "Failed configuring one or more IP addresses");
- /* continue configuring rest of the interfaces */
- }
- }
-
- /* Notify all IP address consumers and clean up interface list */
- for (nilp = nil_head; nilp; ) {
- nip = nilp->nifp;
- if (nip != (struct net_interface *)0) {
- if (nip->name != 0) {
- ip_consumer_notify(hd, nip->name, errorp, flags,
- depend_info);
- free(nip->name);
+ rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
+ if (nvpair_value_uint64(nvp, &id64) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("IP: cannot get linkid\n"));
+ return (RCM_FAILURE);
+ }
+ linkid = (datalink_id_t)id64;
+ if (if_configure(linkid) != 0) {
+ rcm_log_message(RCM_ERROR,
+ _("IP: Configuration failed (%u)\n"),
+ linkid);
+ ip_log_err(NULL, errorp,
+ "Failed configuring one or more IP "
+ "addresses");
}
- if (nip->type != 0)
- free(nip->type);
- free((char *)nip);
- }
- onilp = nilp;
- nilp = nilp->next;
- free((char *)onilp);
+ /* Notify all IP address consumers */
+ ip_consumer_notify(hd, linkid, errorp, flags,
+ depend_info);
+ }
}
- num_ni = 0; /* reset new if count */
- nil_head = NIL_NULL; /* reset list head */
-
- (void) mutex_unlock(&nil_lock);
-
rcm_log_message(RCM_TRACE1,
"IP: notify_event: device configuration complete\n");
@@ -919,17 +860,42 @@ ip_usage(ip_cache_t *node)
ip_lif_t *lif;
int numifs;
char *buf;
- char *nic;
+ char *linkidstr;
+ datalink_id_t linkid;
const char *fmt;
char *sep;
+ char link[MAXLINKNAMELEN];
char addrstr[INET6_ADDRSTRLEN];
+ char errmsg[DLADM_STRSIZE];
+ dladm_status_t status;
int offline = 0;
size_t bufsz;
rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
- nic = strchr(node->ip_resource, '/');
- nic = nic ? nic + 1 : node->ip_resource;
+ /*
+ * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
+ */
+ linkidstr = strchr(node->ip_resource, '/');
+ assert(linkidstr != NULL);
+ linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
+
+ errno = 0;
+ linkid = strtol(linkidstr, &buf, 10);
+ if (errno != 0 || *buf != '\0') {
+ rcm_log_message(RCM_ERROR,
+ _("IP: usage(%s) parse linkid failure (%s)\n"),
+ node->ip_resource, strerror(errno));
+ return (NULL);
+ }
+
+ if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
+ sizeof (link))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("IP: usage(%s) get link name failure(%s)\n"),
+ node->ip_resource, dladm_status2str(status, errmsg));
+ return (NULL);
+ }
/* TRANSLATION_NOTE: separator used between IP addresses */
sep = _(", ");
@@ -955,7 +921,7 @@ ip_usage(ip_cache_t *node)
/* space for addresses and separators, plus message */
bufsz = ((numifs * (INET6_ADDRSTRLEN + strlen(sep))) +
- strlen(fmt) + strlen(nic) + 1);
+ strlen(fmt) + strlen(link) + 1);
if ((buf = malloc(bufsz)) == NULL) {
rcm_log_message(RCM_ERROR,
_("IP: usage(%s) malloc failure(%s)\n"),
@@ -963,7 +929,7 @@ ip_usage(ip_cache_t *node)
return (NULL);
}
bzero(buf, bufsz);
- (void) sprintf(buf, fmt, nic);
+ (void) sprintf(buf, fmt, link);
if (offline || (numifs == 0)) { /* Nothing else to do */
rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
@@ -1019,7 +985,7 @@ ip_usage(ip_cache_t *node)
*/
/*
- * cache_lookup() - Get a cache node for a resource. Supports VLAN interfaces.
+ * cache_lookup() - Get a cache node for a resource.
* Call with cache lock held.
*
* This ensures that the cache is consistent with the system state and
@@ -1029,7 +995,6 @@ static ip_cache_t *
cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
{
ip_cache_t *probe;
- char *resource; /* physical resource */
rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
@@ -1040,23 +1005,16 @@ cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
(void) mutex_lock(&cache_lock);
}
- if ((resource = get_physical_resource(rsrc)) == NULL) {
- errno = ENOENT;
- return (NULL);
- }
-
probe = cache_head.ip_next;
while (probe != &cache_tail) {
if (probe->ip_resource &&
- STREQ(resource, probe->ip_resource)) {
+ STREQ(rsrc, probe->ip_resource)) {
rcm_log_message(RCM_TRACE2,
"IP: cache lookup success(%s)\n", rsrc);
- free(resource);
return (probe);
}
probe = probe->ip_next;
}
- free(resource);
return (NULL);
}
@@ -1098,6 +1056,9 @@ free_node(ip_cache_t *node)
static void
cache_insert(ip_cache_t *node)
{
+ rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
+ node->ip_resource);
+
/* insert at the head for best performance */
node->ip_next = cache_head.ip_next;
node->ip_prev = &cache_head;
@@ -1113,6 +1074,9 @@ cache_insert(ip_cache_t *node)
static void
cache_remove(ip_cache_t *node)
{
+ rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
+ node->ip_resource);
+
node->ip_next->ip_prev = node->ip_prev;
node->ip_prev->ip_next = node->ip_next;
node->ip_next = NULL;
@@ -1127,7 +1091,7 @@ cache_remove(ip_cache_t *node)
static int
update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
{
- char ifname[RCM_NET_RESOURCE_MAX];
+ char *rsrc;
ifspec_t ifspec;
ushort_t ifnumber = 0;
ip_cache_t *probe;
@@ -1191,29 +1155,28 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
}
(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
- /* Search for the interface in our cache */
- (void) snprintf(ifname, sizeof (ifname), "%s/%s", RCM_NET_PREFIX,
- pif.pi_ifname);
+ rsrc = get_link_resource(pif.pi_ifname);
+ if (rsrc == NULL) {
+ rcm_log_message(RCM_ERROR,
+ _("IP: get_link_resource(%s) failed\n"),
+ lifreq.lifr_name);
+ return (-1);
+ }
- probe = cache_lookup(hd, ifname, CACHE_NO_REFRESH);
+ probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
if (probe != NULL) {
+ free(rsrc);
probe->ip_cachestate &= ~(CACHE_IF_STALE);
} else {
if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
/* malloc errors are bad */
+ free(rsrc);
rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
strerror(errno));
return (-1);
}
- probe->ip_resource = get_physical_resource(ifname);
- if (!probe->ip_resource) {
- rcm_log_message(RCM_ERROR, _("IP: strdup: %s\n"),
- strerror(errno));
- free(probe);
- return (-1);
- }
-
+ probe->ip_resource = rsrc;
probe->ip_pif = NULL;
probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
probe->ip_cachestate |= CACHE_IF_NEW;
@@ -1503,21 +1466,20 @@ free_cache()
static void
ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
{
- char *nic = NULL;
+ char *ifname = NULL;
int len;
const char *errfmt;
char *error;
if ((node != NULL) && (node->ip_pif != NULL) &&
(node->ip_pif->pi_ifname != NULL)) {
- nic = strrchr(node->ip_pif->pi_ifname, '/');
- nic = nic ? nic + 1 : node->ip_pif->pi_ifname;
+ ifname = node->ip_pif->pi_ifname;
}
if (errorp != NULL)
*errorp = NULL;
- if (nic == NULL) {
+ if (ifname == NULL) {
rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
errfmt = _("IP: %s");
len = strlen(errfmt) + strlen(errmsg) + 1;
@@ -1525,11 +1487,11 @@ ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
(void) sprintf(error, errfmt, errmsg);
}
} else {
- rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, nic);
+ rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
errfmt = _("IP: %s(%s)");
- len = strlen(errfmt) + strlen(errmsg) + strlen(nic) + 1;
+ len = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
if (error = (char *)calloc(1, len)) {
- (void) sprintf(error, errfmt, errmsg, nic);
+ (void) sprintf(error, errfmt, errmsg, ifname);
}
}
@@ -1696,7 +1658,7 @@ if_unplumb(ip_cache_t *node)
} else {
/* Unlikely case */
rcm_log_message(RCM_DEBUG,
- _("IP: Unplumb ignored (%s:%d)\n"),
+ "IP: Unplumb ignored (%s:%d)\n",
pif->pi_ifname, lif->li_ifnum);
lif = lif->li_next;
continue;
@@ -1781,7 +1743,7 @@ if_replumb(ip_cache_t *node)
} else {
/* Unlikely case */
rcm_log_message(RCM_DEBUG,
- _("IP: Re-plumb ignored (%s:%d)\n"),
+ "IP: Re-plumb ignored (%s:%d)\n",
pif->pi_ifname, lif->li_ifnum);
lif = lif->li_next;
continue;
@@ -1958,37 +1920,46 @@ ip_ipmp_undo_offline(ip_cache_t *node)
}
/*
- * get_physical_resource() - Convert a name (e.g., "SUNW_network/hme0:1" or
- * "SUNW_network/hme1000") into a dynamically allocated string containing the
- * associated physical device resource name ("SUNW_network/hme0"). Since we
- * assume that interface names map directly to device names, this is a
- * pass-through operation, with the exception that logical interface numbers
- * and VLANs encoded in the PPA are stripped. This logic will need to be
- * revisited to support administratively-chosen interface names.
+ * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
+ * dynamically allocated string containing the associated link resource
+ * name ("SUNW_datalink/<linkid>").
*/
static char *
-get_physical_resource(const char *rsrc)
+get_link_resource(const char *link)
{
- char *rsrc_ifname, *ifname;
- ifspec_t ifspec;
+ char errmsg[DLADM_STRSIZE];
+ datalink_id_t linkid;
+ uint32_t flags;
+ char *resource;
+ dladm_status_t status;
- rsrc_ifname = strchr(rsrc, '/');
- if (rsrc_ifname == NULL || !ifparse_ifspec(rsrc_ifname + 1, &ifspec)) {
- rcm_log_message(RCM_ERROR, _("IP: bad resource: %s\n"), rsrc);
- return (NULL);
+ if ((status = dladm_name2info(link, &linkid, &flags, NULL, NULL))
+ != DLADM_STATUS_OK) {
+ goto fail;
}
- ifname = malloc(RCM_NET_RESOURCE_MAX);
- if (ifname == NULL) {
+ if (!(flags & DLADM_OPT_ACTIVE)) {
+ status = DLADM_STATUS_FAILED;
+ goto fail;
+ }
+
+ resource = malloc(RCM_LINK_RESOURCE_MAX);
+ if (resource == NULL) {
rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
- strerror(errno), rsrc);
+ strerror(errno), link);
return (NULL);
}
- (void) snprintf(ifname, RCM_NET_RESOURCE_MAX, "%s/%s%d", RCM_NET_PREFIX,
- ifspec.ifsp_devnm, VLAN_GET_PPA(ifspec.ifsp_ppa));
+ (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, linkid);
- return (ifname);
+ return (resource);
+
+fail:
+ rcm_log_message(RCM_ERROR,
+ _("IP: get_link_resource for %s error(%s)\n"),
+ link, dladm_status2str(status, errmsg));
+ return (NULL);
}
/*
@@ -2107,7 +2078,7 @@ mpathd_send_cmd(mpathd_cmd_t *mpd)
if (mpr.resp_sys_errno == EAGAIN) {
(void) sleep(1);
rcm_log_message(RCM_DEBUG,
- _("IP: mpathd retrying\n"));
+ "IP: mpathd retrying\n");
continue; /* Retry */
}
errno = mpr.resp_sys_errno;
@@ -2605,36 +2576,24 @@ ip_free_addrlist(char **addrlist)
*/
static void
-ip_consumer_notify(rcm_handle_t *hd, char *ifinst, char **errorp, uint_t flags,
- rcm_info_t **depend_info)
+ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
+ uint_t flags, rcm_info_t **depend_info)
{
- char ifname[LIFNAMSIZ + 1];
- char cached_name[RCM_NET_RESOURCE_MAX];
+ char cached_name[RCM_LINK_RESOURCE_MAX];
ip_cache_t *node;
- char *cp;
-
- rcm_log_message(RCM_TRACE1, "IP: ip_consumer_notify(%s)\n", ifinst);
- if (ifinst == NULL)
- return;
+ assert(linkid != DATALINK_INVALID_LINKID);
- (void) memcpy(&ifname, ifinst, sizeof (ifname));
- ifname[sizeof (ifname) - 1] = '\0';
-
- /* remove LIF component */
- cp = strchr(ifname, ':');
- if (cp) {
- *cp = 0;
- }
+ rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
/* Check for the interface in the cache */
- (void) snprintf(cached_name, sizeof (cached_name), "%s/%s",
- RCM_NET_PREFIX, ifname);
+ (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
+ RCM_LINK_PREFIX, linkid);
(void) mutex_lock(&cache_lock);
if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
- rcm_log_message(RCM_TRACE1, "IP: Skipping interface(%s) \n",
- ifname);
+ rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
+ linkid);
(void) mutex_unlock(&cache_lock);
return;
}
@@ -2650,281 +2609,47 @@ ip_consumer_notify(rcm_handle_t *hd, char *ifinst, char **errorp, uint_t flags,
return;
}
-/*
- * process_nvlist() - Determine network interfaces on a new attach by
- * processing the nvlist
- */
-/*ARGSUSED*/
-static int
-process_nvlist(nvlist_t *nvl)
-{
- nvpair_t *nvp = NULL;
- char *driver_name;
- char *devfs_path;
- int32_t instance;
- char *minor_byte_array; /* packed nvlist of minor_data */
- uint_t nminor; /* # of minor nodes */
- struct devfs_minor_data *mdata;
- nvlist_t *mnvl;
- nvpair_t *mnvp = NULL;
-
- rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
-
- while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
- /* Get driver name */
- if (STREQ(nvpair_name(nvp), RCM_NV_DRIVER_NAME)) {
- if (nvpair_value_string(nvp, &driver_name) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get driver name\n"));
- return (-1);
- }
- }
- /* Get instance */
- if (STREQ(nvpair_name(nvp), RCM_NV_INSTANCE)) {
- if (nvpair_value_int32(nvp, &instance) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get device instance\n"));
- return (-1);
- }
- }
- /* Get devfs_path */
- if (STREQ(nvpair_name(nvp), RCM_NV_DEVFS_PATH)) {
- if (nvpair_value_string(nvp, &devfs_path) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get device path\n"));
- return (-1);
- }
- }
- /* Get minor data */
- if (STREQ(nvpair_name(nvp), RCM_NV_MINOR_DATA)) {
- if (nvpair_value_byte_array(nvp,
- (uchar_t **)&minor_byte_array, &nminor) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get device minor data\n"));
- return (-1);
- }
- if (nvlist_unpack(minor_byte_array,
- nminor, &mnvl, 0) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get minor node data\n"));
- return (-1);
- }
- mdata = (struct devfs_minor_data *)calloc(1,
- sizeof (struct devfs_minor_data));
- if (mdata == NULL) {
- rcm_log_message(RCM_WARNING,
- _("IP: calloc error(%s)\n"),
- strerror(errno));
- nvlist_free(mnvl);
- return (-1);
- }
- /* Enumerate minor node data */
- while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) !=
- NULL) {
- /* Get minor type */
- if (STREQ(nvpair_name(mnvp),
- RCM_NV_MINOR_TYPE)) {
- if (nvpair_value_int32(mnvp,
- &mdata->minor_type) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get minor "
- "type \n"));
- nvlist_free(mnvl);
- return (-1);
- }
- }
- /* Get minor name */
- if (STREQ(nvpair_name(mnvp),
- RCM_NV_MINOR_NAME)) {
- if (nvpair_value_string(mnvp,
- &mdata->minor_name) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get minor "
- "name \n"));
- nvlist_free(mnvl);
- return (-1);
- }
- }
- /* Get minor node type */
- if (STREQ(nvpair_name(mnvp),
- RCM_NV_MINOR_NODE_TYPE)) {
- if (nvpair_value_string(mnvp,
- &mdata->minor_node_type) != 0) {
- rcm_log_message(RCM_WARNING,
- _("IP: cannot get minor "
- "node type \n"));
- nvlist_free(mnvl);
- return (-1);
- }
- }
- }
- (void) process_minor(devfs_path, driver_name, instance,
- mdata);
- nvlist_free(mnvl);
- }
- }
-
- rcm_log_message(RCM_TRACE1, "IP: process_nvlist success\n");
- return (0);
-}
-
-static void
-process_minor(char *devfs_path, char *name, int instance,
- struct devfs_minor_data *mdata)
-{
- struct net_interface *nip;
- struct ni_list *nilp;
- struct ni_list *p;
- struct ni_list **pp;
- char *cname;
- size_t cnamelen;
-
- rcm_log_message(RCM_TRACE1, "IP: process_minor\n");
-
- if ((mdata->minor_node_type != NULL) &&
- !STREQ(mdata->minor_node_type, PROP_NV_DDI_NETWORK)) {
- /* Process network devices only */
- return;
- }
-
- rcm_log_message(RCM_TRACE1, "IP: Examining %s (%s)\n",
- devfs_path, mdata->minor_name);
-
- /* Sanity check, instances > 999 are illegal */
- if (instance > 999) {
- errno = EINVAL;
- rcm_log_message(RCM_ERROR, _("IP: invalid instance %d(%s)\n"),
- instance, strerror(errno));
- return;
- }
-
- /* Now, let's add the node to the interface list */
- if ((nip = malloc(sizeof (struct net_interface))) == NULL) {
- rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
- strerror(errno));
- return;
- }
- (void) memset(nip, 0, sizeof (struct net_interface));
-
- cnamelen = strlen(name) + 1;
- /* Set NIC type */
- if ((nip->type = (char *)malloc(cnamelen)) == NULL) {
- free(nip);
- rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
- strerror(errno));
- return;
- }
- (void) memcpy(nip->type, name, cnamelen);
-
- cnamelen += 3;
- if ((cname = (char *)malloc(cnamelen)) == NULL) {
- free(nip->type);
- free(nip);
- rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
- strerror(errno));
- return;
- }
- (void) snprintf(cname, cnamelen, "%s%d", name, instance);
-
- rcm_log_message(RCM_TRACE1, "IP: Found SUNW_network/%s%d\n", name,
- instance);
-
- /* Set NIC name */
- if ((nip->name = strdup(cname)) == NULL) {
- free(nip->type);
- free(nip);
- free(cname);
- rcm_log_message(RCM_ERROR, _("IP: strdup failure(%s)\n"),
- strerror(errno));
- return;
- }
- free(cname);
-
- /* Add new interface to the list */
- (void) mutex_lock(&nil_lock);
- for (pp = &nil_head; (p = *pp) != NULL; pp = &(p->next)) {
- cname = p->nifp->name;
- if (strcmp(cname, nip->name) == 0)
- break;
- }
-
- if (p != NULL) {
- (void) mutex_unlock(&nil_lock);
- free(nip->name);
- free(nip->type);
- free(nip);
- rcm_log_message(RCM_TRACE1, "IP: secondary node - ignoring\n");
- return;
- }
-
- if ((nilp = malloc(sizeof (struct ni_list))) == NULL) {
- (void) mutex_unlock(&nil_lock);
- free(nip->name);
- free(nip->type);
- free(nip);
- rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
- strerror(errno));
- return;
- }
-
- nilp->nifp = nip;
- nilp->next = NULL;
- *pp = nilp;
-
- num_ni++; /* Increment interface count */
-
- (void) mutex_unlock(&nil_lock);
- rcm_log_message(RCM_TRACE1, "IP: added new node\n");
-}
/*
* if_configure() - Configure a physical interface after attach
*/
static int
-if_configure(char *ifinst)
+if_configure(datalink_id_t linkid)
{
+ char ifinst[MAXLINKNAMELEN];
char cfgfile[MAXPATHLEN];
- char ifname[LIFNAMSIZ + 1];
- char cached_name[RCM_NET_RESOURCE_MAX];
+ char cached_name[RCM_LINK_RESOURCE_MAX];
struct stat statbuf;
ip_cache_t *node;
- char *cp;
int af = 0;
int ipmp = 0;
- if (ifinst == NULL)
- return (0);
+ assert(linkid != DATALINK_INVALID_LINKID);
- rcm_log_message(RCM_TRACE1, "IP: if_configure(%s)\n", ifinst);
-
- /*
- * Check if the interface is already configured
- */
-
- (void) memcpy(&ifname, ifinst, sizeof (ifname));
- ifname[sizeof (ifname) - 1] = '\0';
-
- /* remove LIF component */
- cp = strchr(ifname, ':');
- if (cp) {
- *cp = 0;
- }
+ rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid);
/* Check for the interface in the cache */
- (void) snprintf(cached_name, sizeof (cached_name), "%s/%s",
- RCM_NET_PREFIX, ifname);
+ (void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
+ RCM_LINK_PREFIX, linkid);
/* Check if the interface is new or was previously offlined */
(void) mutex_lock(&cache_lock);
if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
(!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
rcm_log_message(RCM_TRACE1,
- "IP: Skipping configured interface(%s) \n", ifname);
+ _("IP: Skipping configured interface(%u)\n"), linkid);
(void) mutex_unlock(&cache_lock);
return (0);
}
(void) mutex_unlock(&cache_lock);
+ if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, ifinst,
+ sizeof (ifinst)) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("IP: get %u link name failed\n"), linkid);
+ return (-1);
+ }
+
/* Scan IPv4 configuration first */
(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst);
cfgfile[MAXPATHLEN - 1] = '\0';
@@ -3101,7 +2826,7 @@ if_ipmp_config(char *ifinst, int af, int ipmp)
if (stat(cfgfile, &statb) != 0) {
rcm_log_message(RCM_TRACE1,
- _("IP: No config file(%s)\n"), ifinst);
+ "IP: No config file(%s)\n", ifinst);
return (0);
}
@@ -3142,7 +2867,7 @@ if_ipmp_config(char *ifinst, int af, int ipmp)
/* Check if config file is empty, if so, nothing else to do */
if (statb.st_size == 0) {
rcm_log_message(RCM_TRACE1,
- _("IP: Zero size config file(%s)\n"), ifinst);
+ "IP: Zero size config file(%s)\n", ifinst);
return (0);
}
@@ -3387,7 +3112,7 @@ if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp)
if (mpathd_send_cmd(&mpdcmd) < 0) {
rcm_log_message(RCM_TRACE1,
- _("IP: mpathd set original index unsuccessful: %s\n"),
+ "IP: mpathd set original index unsuccessful: %s\n",
strerror(errno));
return (-1);
}
@@ -3400,7 +3125,7 @@ if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp)
}
/*
- * get_mpathd_addr() - Return current destination for lif; caller is
+ * get_mpathd_dest() - Return current destination for lif; caller is
* responsible to free memory allocated for address
*/
static char *
diff --git a/usr/src/cmd/rcm_daemon/common/network_rcm.c b/usr/src/cmd/rcm_daemon/common/network_rcm.c
index 040fe76a6c..5ec088e808 100644
--- a/usr/src/cmd/rcm_daemon/common/network_rcm.c
+++ b/usr/src/cmd/rcm_daemon/common/network_rcm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,7 +41,7 @@
#include <libdevinfo.h>
#include <sys/types.h>
#include <net/if.h>
-#include <libdlaggr.h>
+#include <libdllink.h>
#include "rcm_module.h"
/*
@@ -56,6 +56,20 @@
#define CACHE_STALE 1 /* flags */
#define CACHE_NEW 2 /* flags */
+/* devfsadm attach nvpair values */
+#define PROP_NV_DDI_NETWORK "ddi_network"
+
+/*
+ * Global NIC list to be configured after DR-attach
+ */
+struct ni_list {
+ struct ni_list *next;
+ char dev[MAXNAMELEN]; /* device instance name (le0, ie0, etc.) */
+};
+
+static struct ni_list *nil_head = NULL; /* Global new if list */
+static mutex_t nil_lock; /* NIC list lock */
+
/* operations */
#define NET_OFFLINE 1
#define NET_ONLINE 2
@@ -66,9 +80,7 @@
typedef struct net_cache
{
char *resource;
- char *exported;
- char *driver;
- int ppa;
+ datalink_id_t linkid;
int flags;
struct net_cache *next;
struct net_cache *prev;
@@ -77,6 +89,13 @@ typedef struct net_cache
static net_cache_t cache_head;
static net_cache_t cache_tail;
static mutex_t cache_lock;
+static int events_registered = 0;
+
+struct devfs_minor_data {
+ int32_t minor_type;
+ char *minor_name;
+ char *minor_node_type;
+};
/* module interface routines */
static int net_register(rcm_handle_t *);
@@ -93,6 +112,8 @@ static int net_online(rcm_handle_t *, char *, id_t, uint_t, char **,
rcm_info_t **);
static int net_remove(rcm_handle_t *, char *, id_t, uint_t, char **,
rcm_info_t **);
+static int net_notify_event(rcm_handle_t *, char *, id_t, uint_t,
+ char **, nvlist_t *, rcm_info_t **);
/* module private routines */
static void free_cache(void);
@@ -102,7 +123,9 @@ static void cache_remove(net_cache_t *node);
static net_cache_t *cache_lookup(const char *resource);
static void free_node(net_cache_t *);
static void cache_insert(net_cache_t *);
-static boolean_t is_aggregated(char *driver, int ppa);
+static int notify_new_link(rcm_handle_t *, const char *);
+static void process_minor(char *, int, struct devfs_minor_data *);
+static int process_nvlist(rcm_handle_t *, nvlist_t *);
/*
* Module-Private data
@@ -116,7 +139,10 @@ static struct rcm_mod_ops net_ops = {
net_resume,
net_offline,
net_online,
- net_remove
+ net_remove,
+ NULL,
+ NULL,
+ net_notify_event
};
/*
@@ -179,6 +205,24 @@ static int
net_register(rcm_handle_t *hd)
{
update_cache(hd);
+ /*
+ * Need to register interest in all new resources
+ * getting attached, so we get attach event notifications
+ */
+ if (!events_registered) {
+ if (rcm_register_event(hd, RCM_RESOURCE_NETWORK_NEW, 0, NULL)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("NET: failed to register %s\n"),
+ RCM_RESOURCE_NETWORK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, _("NET: registered %s\n"),
+ RCM_RESOURCE_NETWORK_NEW);
+ events_registered++;
+ }
+ }
+
return (RCM_SUCCESS);
}
@@ -207,6 +251,24 @@ net_unregister(rcm_handle_t *hd)
probe = cache_head.next;
}
(void) mutex_unlock(&cache_lock);
+
+ /*
+ * Need to unregister interest in all new resources
+ */
+ if (events_registered) {
+ if (rcm_unregister_event(hd, RCM_RESOURCE_NETWORK_NEW, 0)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("NET: failed to unregister %s\n"),
+ RCM_RESOURCE_NETWORK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"),
+ RCM_RESOURCE_NETWORK_NEW);
+ events_registered--;
+ }
+ }
+
return (RCM_SUCCESS);
}
@@ -221,6 +283,8 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
{
net_cache_t *node;
char *exported;
+ datalink_id_t linkid;
+ int len;
int rv;
/*
@@ -237,13 +301,15 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
}
/*
- * Since node->exported could be freed after we drop cache_lock,
- * allocate a stack-local copy. We don't use strdup() because some of
- * the operations (such as NET_REMOVE) are not allowed to fail. Note
- * that node->exported is never more than MAXPATHLEN bytes.
+ * Since node could be freed after we drop cache_lock, allocate a
+ * stack-local copy. We don't use malloc() because some of the
+ * operations (such as NET_REMOVE) are not allowed to fail. Note
+ * that exported is never more than MAXPATHLEN bytes.
*/
- exported = alloca(strlen(node->exported) + 1);
- (void) strlcpy(exported, node->exported, strlen(node->exported) + 1);
+ len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1;
+ exported = alloca(len);
+ linkid = node->linkid;
+ (void) snprintf(exported, len, "SUNW_datalink/%u", linkid);
/*
* Remove notifications are unconditional in the RCM state model,
@@ -263,18 +329,6 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
(timespec_t *)arg, dependent_reason);
break;
case NET_OFFLINE:
- if (is_aggregated(node->driver, node->ppa)) {
- /* device is aggregated */
- *reason = strdup(gettext(
- "Resource is in use by aggregation"));
- if (*reason == NULL) {
- rcm_log_message(RCM_ERROR,
- gettext("NET: malloc failure"));
- }
- errno = EBUSY;
- return (RCM_FAILURE);
- }
-
rv = rcm_request_offline(hd, exported, flag, dependent_reason);
break;
case NET_ONLINE:
@@ -282,6 +336,19 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
break;
case NET_REMOVE:
rv = rcm_notify_remove(hd, exported, flag, dependent_reason);
+ if (rv == RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG,
+ _("NET: mark link %d as removed\n"), linkid);
+
+ /*
+ * Delete active linkprop before this active link
+ * is deleted.
+ */
+ (void) dladm_set_linkprop(linkid, NULL, NULL, 0,
+ DLADM_OPT_ACTIVE);
+ (void) dladm_destroy_datalink_id(linkid,
+ DLADM_OPT_ACTIVE);
+ }
break;
case NET_RESUME:
rv = rcm_notify_resume(hd, exported, flag, dependent_reason);
@@ -300,7 +367,6 @@ net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
exported);
rcm_log_message(RCM_WARNING, "NET: %s\n", format);
}
-
return (rv);
}
@@ -321,7 +387,7 @@ net_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
assert(reason != NULL);
assert(dependent_reason != NULL);
- rcm_log_message(RCM_TRACE1, "NET: offline(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: offline(%s)\n"), rsrc);
return (net_passthru(hd, NET_OFFLINE, rsrc, flags, reason,
dependent_reason, NULL));
@@ -340,7 +406,7 @@ net_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **reason,
assert(rsrc != NULL);
assert(id == (id_t)0);
- rcm_log_message(RCM_TRACE1, "NET: online(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: online(%s)\n"), rsrc);
return (net_passthru(hd, NET_ONLINE, rsrc, flag, reason,
dependent_reason, NULL));
@@ -362,8 +428,10 @@ net_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag,
char **info, char **errstr, nvlist_t *proplist, rcm_info_t **depend_info)
{
int len;
+ dladm_status_t status;
+ char link[MAXLINKNAMELEN];
+ char errmsg[DLADM_STRSIZE];
char *exported;
- char nic[64];
const char *info_fmt;
net_cache_t *node;
@@ -373,7 +441,7 @@ net_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag,
assert(info != NULL);
assert(depend_info != NULL);
- rcm_log_message(RCM_TRACE1, "NET: getinfo(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: getinfo(%s)\n"), rsrc);
info_fmt = _("Network interface %s");
@@ -386,25 +454,34 @@ net_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag,
errno = ENOENT;
return (RCM_FAILURE);
}
- exported = strdup(node->exported);
- if (!exported) {
- rcm_log_message(RCM_ERROR, _("NET: strdup failure"));
+
+ len = strlen(info_fmt) + MAXLINKNAMELEN + 1;
+ if ((status = dladm_datalink_id2info(node->linkid, NULL, NULL, NULL,
+ link, sizeof (link))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("NET: usage(%s) get link name failure(%s)\n"),
+ node->resource, dladm_status2str(status, errmsg));
(void) mutex_unlock(&cache_lock);
return (RCM_FAILURE);
- }
-
- (void) snprintf(nic, sizeof (nic), "%s%d", node->driver, node->ppa);
- (void) mutex_unlock(&cache_lock);
-
- len = strlen(info_fmt) + strlen(nic) + 1;
- if ((*info = (char *)malloc(len)) == NULL) {
+ } else if ((*info = (char *)malloc(len)) == NULL) {
rcm_log_message(RCM_ERROR, _("NET: malloc failure"));
- free(exported);
+ (void) mutex_unlock(&cache_lock);
return (RCM_FAILURE);
}
/* Fill in the string */
- (void) snprintf(*info, len, info_fmt, nic);
+ (void) snprintf(*info, len, info_fmt, link);
+
+ len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1;
+ exported = malloc(len);
+ if (!exported) {
+ rcm_log_message(RCM_ERROR, _("NET: allocation failure"));
+ free(*info);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+ (void) snprintf(exported, len, "SUNW_datalink/%u", node->linkid);
+ (void) mutex_unlock(&cache_lock);
/* Get dependent info if requested */
if ((flag & RCM_INCLUDE_DEPENDENT) || (flag & RCM_INCLUDE_SUBTREE)) {
@@ -439,7 +516,7 @@ net_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
assert(reason != NULL);
assert(dependent_reason != NULL);
- rcm_log_message(RCM_TRACE1, "NET: suspend(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: suspend(%s)\n"), rsrc);
return (net_passthru(hd, NET_SUSPEND, rsrc, flag, reason,
dependent_reason, (void *)interval));
@@ -463,7 +540,7 @@ net_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info,
assert(info != NULL);
assert(dependent_info != NULL);
- rcm_log_message(RCM_TRACE1, "NET: resume(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: resume(%s)\n"), rsrc);
return (net_passthru(hd, NET_RESUME, rsrc, flag, info, dependent_info,
NULL));
@@ -488,7 +565,7 @@ net_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info,
assert(info != NULL);
assert(dependent_info != NULL);
- rcm_log_message(RCM_TRACE1, "NET: remove(%s)\n", rsrc);
+ rcm_log_message(RCM_TRACE1, _("NET: remove(%s)\n"), rsrc);
return (net_passthru(hd, NET_REMOVE, rsrc, flag, info, dependent_info,
NULL));
@@ -532,8 +609,6 @@ free_node(net_cache_t *node)
{
if (node) {
free(node->resource);
- free(node->exported);
- free(node->driver);
free(node);
}
}
@@ -577,12 +652,12 @@ cache_remove(net_cache_t *node)
static int
devfs_entry(di_node_t node, di_minor_t minor, void *arg)
{
- char ifname [MAXPATHLEN]; /* should be big enough! */
char *devfspath;
char resource[MAXPATHLEN];
- char *name;
+ char dev[MAXNAMELEN];
+ datalink_id_t linkid;
+ char *drv;
char *cp;
- int instance;
net_cache_t *probe;
cp = di_minor_nodetype(minor);
@@ -591,28 +666,23 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg)
return (DI_WALK_CONTINUE);
}
- name = di_driver_name(node);
- if (name == NULL) {
+ drv = di_driver_name(node);
+ if (drv == NULL) {
/* what else can we do? */
return (DI_WALK_CONTINUE);
}
- instance = di_instance(node);
-
- (void) snprintf(ifname, sizeof (ifname), "SUNW_network/%s%d",
- name, instance);
-
devfspath = di_devfs_path(node);
if (!devfspath) {
/* no devfs path?!? */
- rcm_log_message(RCM_DEBUG, "NET: missing devfs path\n");
+ rcm_log_message(RCM_DEBUG, _("NET: missing devfs path\n"));
return (DI_WALK_CONTINUE);
}
if (strncmp("/pseudo", devfspath, strlen("/pseudo")) == 0) {
/* ignore pseudo devices, probably not really NICs */
- rcm_log_message(RCM_DEBUG, "NET: ignoring pseudo device %s\n",
- devfspath);
+ rcm_log_message(RCM_DEBUG,
+ _("NET: ignoring pseudo device %s\n"), devfspath);
di_devfs_path_free(devfspath);
return (DI_WALK_CONTINUE);
}
@@ -620,14 +690,24 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg)
(void) snprintf(resource, sizeof (resource), "/devices%s", devfspath);
di_devfs_path_free(devfspath);
+ (void) snprintf(dev, sizeof (dev), "%s%d", drv, di_instance(node));
+ if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_DEBUG,
+ _("NET: failed to find the linkid for %s\n"), dev);
+ return (DI_WALK_CONTINUE);
+ }
+
probe = cache_lookup(resource);
if (probe != NULL) {
- rcm_log_message(RCM_DEBUG, "NET: %s already registered\n",
- resource);
+ rcm_log_message(RCM_DEBUG,
+ _("NET: %s already registered (linkid %u)\n"),
+ resource, linkid);
+ probe->linkid = linkid;
probe->flags &= ~(CACHE_STALE);
} else {
- rcm_log_message(RCM_DEBUG, "NET: %s is new resource\n",
- resource);
+ rcm_log_message(RCM_DEBUG,
+ _("NET: %s is new resource (linkid %u)\n"),
+ resource, linkid);
probe = calloc(1, sizeof (net_cache_t));
if (!probe) {
rcm_log_message(RCM_ERROR, _("NET: malloc failure"));
@@ -635,12 +715,9 @@ devfs_entry(di_node_t node, di_minor_t minor, void *arg)
}
probe->resource = strdup(resource);
- probe->ppa = instance;
- probe->driver = strdup(name);
- probe->exported = strdup(ifname);
+ probe->linkid = linkid;
- if ((!probe->resource) || (!probe->exported) ||
- (!probe->driver)) {
+ if (!probe->resource) {
free_node(probe);
return (DI_WALK_CONTINUE);
}
@@ -688,7 +765,7 @@ update_cache(rcm_handle_t *hd)
net_cache_t *freeit;
if (probe->flags & CACHE_STALE) {
(void) rcm_unregister_interest(hd, probe->resource, 0);
- rcm_log_message(RCM_DEBUG, "NET: unregistered %s\n",
+ rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"),
probe->resource);
freeit = probe;
probe = probe->next;
@@ -702,7 +779,7 @@ update_cache(rcm_handle_t *hd)
continue;
}
- rcm_log_message(RCM_DEBUG, "NET: registering %s\n",
+ rcm_log_message(RCM_DEBUG, _("NET: registering %s\n"),
probe->resource);
rv = rcm_register_interest(hd, probe->resource, 0, NULL);
if (rv != RCM_SUCCESS) {
@@ -711,8 +788,8 @@ update_cache(rcm_handle_t *hd)
probe->resource);
} else {
rcm_log_message(RCM_DEBUG,
- "NET: registered %s (as %s)\n",
- probe->resource, probe->exported);
+ _("NET: registered %s as SUNW_datalink/%u\n"),
+ probe->resource, probe->linkid);
probe->flags &= ~(CACHE_NEW);
}
probe = probe->next;
@@ -741,52 +818,282 @@ free_cache(void)
}
/*
- * is_aggregated() checks whether a NIC being removed is part of an
- * aggregation.
+ * net_notify_event - Project private implementation to receive new
+ * resource events. It intercepts all new resource
+ * events. If the new resource is a network resource,
+ * pass up a event for the resource. The new resource
+ * need not be cached, since it is done at register again.
*/
+/*ARGSUSED*/
+static int
+net_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
+{
+ assert(hd != NULL);
+ assert(rsrc != NULL);
+ assert(id == (id_t)0);
+ assert(nvl != NULL);
-typedef struct aggr_walker_state_s {
- uint_t naggr;
- char dev_name[LIFNAMSIZ];
-} aggr_walker_state_t;
+ rcm_log_message(RCM_TRACE1, _("NET: notify_event(%s)\n"), rsrc);
+ if (strcmp(rsrc, RCM_RESOURCE_NETWORK_NEW) != 0) {
+ rcm_log_message(RCM_INFO,
+ _("NET: unrecognized event for %s\n"), rsrc);
+ errno = EINVAL;
+ return (RCM_FAILURE);
+ }
+
+ /* Update cache to reflect latest physical links */
+ update_cache(hd);
+
+ /* Process the nvlist for the event */
+ if (process_nvlist(hd, nvl) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: Error processing resource attributes(%s)\n"), rsrc);
+ rcm_log_message(RCM_WARNING,
+ _("NET: One or more devices may not be configured.\n"));
+ }
+
+ rcm_log_message(RCM_TRACE1,
+ _("NET: notify_event: device configuration complete\n"));
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * process_nvlist() - Determine network interfaces on a new attach by
+ * processing the nvlist
+ */
static int
-aggr_walker(void *arg, dladm_aggr_grp_attr_t *grp)
+process_nvlist(rcm_handle_t *hd, nvlist_t *nvl)
{
- aggr_walker_state_t *state = arg;
- dladm_aggr_port_attr_t *port;
- int i;
-
- for (i = 0; i < grp->lg_nports; i++) {
- port = &grp->lg_ports[i];
+ nvpair_t *nvp = NULL;
+ char *driver;
+ char *devfspath;
+ int32_t instance;
+ char *minor_byte_array; /* packed nvlist of minor_data */
+ uint_t nminor; /* # of minor nodes */
+ struct devfs_minor_data *mdata;
+ nvlist_t *mnvl;
+ nvpair_t *mnvp = NULL;
+ struct ni_list *nilp, *next;
+
+ rcm_log_message(RCM_TRACE1, "NET: process_nvlist\n");
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ /* Get driver name */
+ if (strcmp(nvpair_name(nvp), RCM_NV_DRIVER_NAME) == 0) {
+ if (nvpair_value_string(nvp, &driver) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get driver name\n"));
+ return (-1);
+ }
+ }
+ /* Get instance */
+ if (strcmp(nvpair_name(nvp), RCM_NV_INSTANCE) == 0) {
+ if (nvpair_value_int32(nvp, &instance) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get device instance\n"));
+ return (-1);
+ }
+ }
+ /* Get devfspath */
+ if (strcmp(nvpair_name(nvp), RCM_NV_DEVFS_PATH) == 0) {
+ if (nvpair_value_string(nvp, &devfspath) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get device path\n"));
+ return (-1);
+ }
+ if (strncmp("/pseudo", devfspath,
+ strlen("/pseudo")) == 0) {
+ /* Ignore pseudo devices, not really NICs */
+ rcm_log_message(RCM_DEBUG,
+ _("NET: ignoring pseudo device %s\n"),
+ devfspath);
+ return (0);
+ }
+ }
- rcm_log_message(RCM_TRACE1, "MAC: aggr (%d) port %s\n",
- grp->lg_key, port->lp_devname);
+ /* Get minor data */
+ if (strcmp(nvpair_name(nvp), RCM_NV_MINOR_DATA) == 0) {
+ if (nvpair_value_byte_array(nvp,
+ (uchar_t **)&minor_byte_array, &nminor) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get device minor data\n"));
+ return (-1);
+ }
+ if (nvlist_unpack(minor_byte_array,
+ nminor, &mnvl, 0) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get minor node data\n"));
+ return (-1);
+ }
+ mdata = (struct devfs_minor_data *)calloc(1,
+ sizeof (struct devfs_minor_data));
+ if (mdata == NULL) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: calloc error(%s)\n"),
+ strerror(errno));
+ nvlist_free(mnvl);
+ return (-1);
+ }
+ /* Enumerate minor node data */
+ while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) !=
+ NULL) {
+ /* Get minor type */
+ if (strcmp(nvpair_name(mnvp),
+ RCM_NV_MINOR_TYPE) == 0) {
+ if (nvpair_value_int32(mnvp,
+ &mdata->minor_type) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get minor "
+ "type \n"));
+ nvlist_free(mnvl);
+ return (-1);
+ }
+ }
+ /* Get minor name */
+ if (strcmp(nvpair_name(mnvp),
+ RCM_NV_MINOR_NAME) == 0) {
+ if (nvpair_value_string(mnvp,
+ &mdata->minor_name) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get minor "
+ "name \n"));
+ nvlist_free(mnvl);
+ return (-1);
+ }
+ }
+ /* Get minor node type */
+ if (strcmp(nvpair_name(mnvp),
+ RCM_NV_MINOR_NODE_TYPE) == 0) {
+ if (nvpair_value_string(mnvp,
+ &mdata->minor_node_type) != 0) {
+ rcm_log_message(RCM_WARNING,
+ _("NET: cannot get minor "
+ "node type \n"));
+ nvlist_free(mnvl);
+ return (-1);
+ }
+ }
+ }
+ (void) process_minor(driver, instance, mdata);
+ nvlist_free(mnvl);
+ }
+ }
- if (strcmp(port->lp_devname, state->dev_name) != 0)
- continue;
+ (void) mutex_lock(&nil_lock);
- /* found matching MAC port */
- state->naggr++;
+ /* Notify the event for all new devices found, then clean up the list */
+ for (nilp = nil_head; nilp != NULL; nilp = next) {
+ if (notify_new_link(hd, nilp->dev) != 0) {
+ rcm_log_message(RCM_ERROR,
+ _(": Notify %s event failed (%s)\n"),
+ RCM_RESOURCE_LINK_NEW, nilp->dev);
+ }
+ next = nilp->next;
+ free(nilp);
}
+ nil_head = NULL;
+
+ (void) mutex_unlock(&nil_lock);
+ rcm_log_message(RCM_TRACE1, _("NET: process_nvlist success\n"));
return (0);
}
-static boolean_t
-is_aggregated(char *driver, int ppa)
+static void
+process_minor(char *name, int instance, struct devfs_minor_data *mdata)
{
- aggr_walker_state_t state;
+ char dev[MAXNAMELEN];
+ struct ni_list **pp;
+ struct ni_list *p;
+
+ rcm_log_message(RCM_TRACE1, _("NET: process_minor %s%d\n"),
+ name, instance);
+
+ if ((mdata->minor_node_type != NULL) &&
+ strcmp(mdata->minor_node_type, PROP_NV_DDI_NETWORK) != 0) {
+ /* Process network devices only */
+ return;
+ }
+
+ (void) snprintf(dev, sizeof (dev), "%s%d", name, instance);
- state.naggr = 0;
- (void) snprintf(state.dev_name, sizeof (state.dev_name), "%s%d",
- driver, ppa);
+ /* Add new interface to the list */
+ (void) mutex_lock(&nil_lock);
+ for (pp = &nil_head; (p = *pp) != NULL; pp = &(p->next)) {
+ if (strcmp(dev, p->dev) == 0)
+ break;
+ }
+ if (p != NULL) {
+ rcm_log_message(RCM_TRACE1,
+ _("NET: secondary node - ignoring\n"));
+ goto done;
+ }
- if (dladm_aggr_walk(aggr_walker, &state) != 0) {
- rcm_log_message(RCM_ERROR, gettext("NET: cannot walk "
- "aggregations (%s)\n"), strerror(errno));
- return (B_FALSE);
+ /* Add new device to the list */
+ if ((p = malloc(sizeof (struct ni_list))) == NULL) {
+ rcm_log_message(RCM_ERROR, _("NET: malloc failure(%s)\n"),
+ strerror(errno));
+ goto done;
}
+ (void) strncpy(p->dev, dev, sizeof (p->dev));
+ p->next = NULL;
+ *pp = p;
+
+ rcm_log_message(RCM_TRACE1, _("NET: added new node %s\n"), dev);
+done:
+ (void) mutex_unlock(&nil_lock);
+}
- return (state.naggr > 0);
+/*
+ * Notify the RCM_RESOURCE_LINK_NEW event to other modules.
+ * Return 0 on success, -1 on failure.
+ */
+static int
+notify_new_link(rcm_handle_t *hd, const char *dev)
+{
+ nvlist_t *nvl = NULL;
+ datalink_id_t linkid;
+ uint64_t id;
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE1, _("NET: notify_new_link %s\n"), dev);
+ if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_TRACE1,
+ _("NET: new link %s has not attached yet\n"), dev);
+ ret = 0;
+ goto done;
+ }
+
+ id = linkid;
+ if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
+ (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0)) {
+ rcm_log_message(RCM_ERROR,
+ _("NET: failed to construct nvlist for %s\n"), dev);
+ goto done;
+ }
+
+ /*
+ * Reset the active linkprop of this specific link.
+ */
+ (void) dladm_init_linkprop(linkid);
+
+ rcm_log_message(RCM_TRACE1, _("NET: notify new link %u (%s)\n"),
+ linkid, dev);
+
+ if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
+ RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("NET: failed to notify %s event for %s\n"),
+ RCM_RESOURCE_LINK_NEW, dev);
+ goto done;
+ }
+
+ ret = 0;
+done:
+ if (nvl != NULL)
+ nvlist_free(nvl);
+ return (ret);
}
diff --git a/usr/src/cmd/rcm_daemon/common/vlan_rcm.c b/usr/src/cmd/rcm_daemon/common/vlan_rcm.c
new file mode 100644
index 0000000000..4960040dec
--- /dev/null
+++ b/usr/src/cmd/rcm_daemon/common/vlan_rcm.c
@@ -0,0 +1,1327 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This RCM module adds support to the RCM framework for VLAN links
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <synch.h>
+#include <assert.h>
+#include <strings.h>
+#include "rcm_module.h"
+#include <libintl.h>
+#include <libdllink.h>
+#include <libdlvlan.h>
+#include <libdlpi.h>
+
+/*
+ * Definitions
+ */
+#ifndef lint
+#define _(x) gettext(x)
+#else
+#define _(x) x
+#endif
+
+/* Some generic well-knowns and defaults used in this module */
+#define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
+#define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
+
+/* VLAN link flags */
+typedef enum {
+ VLAN_OFFLINED = 0x1,
+ VLAN_CONSUMER_OFFLINED = 0x2,
+ VLAN_STALE = 0x4
+} vlan_flag_t;
+
+/* link representation */
+typedef struct dl_vlan {
+ struct dl_vlan *dv_next; /* next VLAN on the same link */
+ struct dl_vlan *dv_prev; /* prev VLAN on the same link */
+ datalink_id_t dv_vlanid;
+ boolean_t dv_implicit;
+ vlan_flag_t dv_flags; /* VLAN link flags */
+} dl_vlan_t;
+
+/* VLAN Cache state flags */
+typedef enum {
+ CACHE_NODE_STALE = 0x1, /* stale cached data */
+ CACHE_NODE_NEW = 0x2, /* new cached nodes */
+ CACHE_NODE_OFFLINED = 0x4 /* nodes offlined */
+} cache_node_state_t;
+
+/* Network Cache lookup options */
+#define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
+#define CACHE_REFRESH 0x2 /* refresh cache */
+
+/* Cache element */
+typedef struct link_cache {
+ struct link_cache *vc_next; /* next cached resource */
+ struct link_cache *vc_prev; /* prev cached resource */
+ char *vc_resource; /* resource name */
+ datalink_id_t vc_linkid; /* linkid */
+ dl_vlan_t *vc_vlan; /* VLAN list on this link */
+ cache_node_state_t vc_state; /* cache state flags */
+} link_cache_t;
+
+/*
+ * Global cache for network VLANs
+ */
+static link_cache_t cache_head;
+static link_cache_t cache_tail;
+static mutex_t cache_lock;
+static int events_registered = 0;
+
+/*
+ * RCM module interface prototypes
+ */
+static int vlan_register(rcm_handle_t *);
+static int vlan_unregister(rcm_handle_t *);
+static int vlan_get_info(rcm_handle_t *, char *, id_t, uint_t,
+ char **, char **, nvlist_t *, rcm_info_t **);
+static int vlan_suspend(rcm_handle_t *, char *, id_t,
+ timespec_t *, uint_t, char **, rcm_info_t **);
+static int vlan_resume(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int vlan_offline(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int vlan_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int vlan_remove(rcm_handle_t *, char *, id_t, uint_t,
+ char **, rcm_info_t **);
+static int vlan_notify_event(rcm_handle_t *, char *, id_t, uint_t,
+ char **, nvlist_t *, rcm_info_t **);
+static int vlan_configure(rcm_handle_t *, datalink_id_t);
+
+/* Module private routines */
+static void cache_free();
+static int cache_update(rcm_handle_t *);
+static void cache_remove(link_cache_t *);
+static void node_free(link_cache_t *);
+static void cache_insert(link_cache_t *);
+static link_cache_t *cache_lookup(rcm_handle_t *, char *, char);
+static int vlan_consumer_offline(rcm_handle_t *, link_cache_t *,
+ char **, uint_t, rcm_info_t **);
+static void vlan_consumer_online(rcm_handle_t *, link_cache_t *,
+ char **, uint_t, rcm_info_t **);
+static int vlan_offline_vlan(link_cache_t *, uint32_t,
+ cache_node_state_t);
+static void vlan_online_vlan(link_cache_t *);
+static char *vlan_usage(link_cache_t *);
+static void vlan_log_err(datalink_id_t, char **, char *);
+static int vlan_consumer_notify(rcm_handle_t *, datalink_id_t,
+ char **, uint_t, rcm_info_t **);
+
+/* Module-Private data */
+static struct rcm_mod_ops vlan_ops =
+{
+ RCM_MOD_OPS_VERSION,
+ vlan_register,
+ vlan_unregister,
+ vlan_get_info,
+ vlan_suspend,
+ vlan_resume,
+ vlan_offline,
+ vlan_undo_offline,
+ vlan_remove,
+ NULL,
+ NULL,
+ vlan_notify_event
+};
+
+/*
+ * rcm_mod_init() - Update registrations, and return the ops structure.
+ */
+struct rcm_mod_ops *
+rcm_mod_init(void)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: mod_init\n");
+
+ cache_head.vc_next = &cache_tail;
+ cache_head.vc_prev = NULL;
+ cache_tail.vc_prev = &cache_head;
+ cache_tail.vc_next = NULL;
+ (void) mutex_init(&cache_lock, 0, NULL);
+
+ /* Return the ops vectors */
+ return (&vlan_ops);
+}
+
+/*
+ * rcm_mod_info() - Return a string describing this module.
+ */
+const char *
+rcm_mod_info(void)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: mod_info\n");
+
+ return ("VLAN module version %I%");
+}
+
+/*
+ * rcm_mod_fini() - Destroy the network VLAN cache.
+ */
+int
+rcm_mod_fini(void)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: mod_fini\n");
+
+ /*
+ * Note that vlan_unregister() does not seem to be called anywhere,
+ * therefore we free the cache nodes here. In theory we should call
+ * rcm_register_interest() for each node before we free it, the
+ * framework does not provide the rcm_handle to allow us to do so.
+ */
+ cache_free();
+ (void) mutex_destroy(&cache_lock);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_register() - Make sure the cache is properly sync'ed, and its
+ * registrations are in order.
+ */
+static int
+vlan_register(rcm_handle_t *hd)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: register\n");
+
+ if (cache_update(hd) < 0)
+ return (RCM_FAILURE);
+
+ /*
+ * Need to register interest in all new resources
+ * getting attached, so we get attach event notifications
+ */
+ if (!events_registered) {
+ if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to register %s\n"),
+ RCM_RESOURCE_LINK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
+ RCM_RESOURCE_LINK_NEW);
+ events_registered++;
+ }
+ }
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_unregister() - Walk the cache, unregistering all the networks.
+ */
+static int
+vlan_unregister(rcm_handle_t *hd)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: unregister\n");
+
+ /* Walk the cache, unregistering everything */
+ (void) mutex_lock(&cache_lock);
+ node = cache_head.vc_next;
+ while (node != &cache_tail) {
+ if (rcm_unregister_interest(hd, node->vc_resource, 0)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to unregister %s\n"),
+ node->vc_resource);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+ cache_remove(node);
+ node_free(node);
+ node = cache_head.vc_next;
+ }
+ (void) mutex_unlock(&cache_lock);
+
+ /*
+ * Unregister interest in all new resources
+ */
+ if (events_registered) {
+ if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
+ != RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to unregister %s\n"),
+ RCM_RESOURCE_LINK_NEW);
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
+ RCM_RESOURCE_LINK_NEW);
+ events_registered--;
+ }
+ }
+
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_offline() - Offline VLANs on a specific node.
+ */
+static int
+vlan_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **info)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: offline(%s)\n", rsrc);
+
+ /* Lock the cache and lookup the resource */
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_REFRESH);
+ if (node == NULL) {
+ /* should not happen because the resource is registered. */
+ vlan_log_err(node->vc_linkid, errorp, "unrecognized resource");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+ }
+
+ /*
+ * Inform consumers (IP interfaces) of associated VLANs to be offlined
+ */
+ if (vlan_consumer_offline(hd, node, errorp, flags, info) ==
+ RCM_SUCCESS) {
+ rcm_log_message(RCM_DEBUG,
+ "VLAN: consumers agreed on offline\n");
+ } else {
+ vlan_log_err(node->vc_linkid, errorp,
+ "consumers failed to offline");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+
+ /* Check if it's a query */
+ if (flags & RCM_QUERY) {
+ rcm_log_message(RCM_TRACE1,
+ "VLAN: offline query succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+ }
+
+ if (vlan_offline_vlan(node, VLAN_OFFLINED, CACHE_NODE_OFFLINED) !=
+ RCM_SUCCESS) {
+ vlan_online_vlan(node);
+ vlan_log_err(node->vc_linkid, errorp, "offline failed");
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_FAILURE);
+ }
+
+ rcm_log_message(RCM_TRACE1, "VLAN: Offline succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_undo_offline() - Undo offline of a previously offlined node.
+ */
+/*ARGSUSED*/
+static int
+vlan_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **info)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: online(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node == NULL) {
+ vlan_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ /* Check if no attempt should be made to online the link here */
+ if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
+ vlan_log_err(node->vc_linkid, errorp, "link not offlined");
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOTSUP;
+ return (RCM_SUCCESS);
+ }
+
+ vlan_online_vlan(node);
+
+ /*
+ * Inform IP interfaces on associated VLANs to be onlined
+ */
+ vlan_consumer_online(hd, node, errorp, flags, info);
+
+ node->vc_state &= ~CACHE_NODE_OFFLINED;
+ rcm_log_message(RCM_TRACE1, "VLAN: online succeeded(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (RCM_SUCCESS);
+}
+
+static void
+vlan_online_vlan(link_cache_t *node)
+{
+ dl_vlan_t *vlan;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+
+ /*
+ * Try to bring on all offlined VLANs
+ */
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ if (!(vlan->dv_flags & VLAN_OFFLINED))
+ continue;
+
+ assert(!vlan->dv_implicit);
+ if ((status = dladm_vlan_up(vlan->dv_vlanid)) !=
+ DLADM_STATUS_OK) {
+ /*
+ * Print a warning message and continue to online
+ * other VLANs.
+ */
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: VLAN online failed (%u): %s\n"),
+ vlan->dv_vlanid, dladm_status2str(status, errmsg));
+ } else {
+ vlan->dv_flags &= ~VLAN_OFFLINED;
+ }
+ }
+}
+
+static int
+vlan_offline_vlan(link_cache_t *node, uint32_t flags, cache_node_state_t state)
+{
+ dl_vlan_t *vlan;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_offline_vlan (%s %u %u)\n",
+ node->vc_resource, flags, state);
+
+ /*
+ * Try to delete all explicit created VLAN
+ */
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+
+ if (vlan->dv_implicit)
+ continue;
+
+ if ((status = dladm_vlan_delete(vlan->dv_vlanid,
+ DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: VLAN offline failed (%u): %s\n"),
+ vlan->dv_vlanid, dladm_status2str(status, errmsg));
+ return (RCM_FAILURE);
+ } else {
+ rcm_log_message(RCM_TRACE1,
+ "VLAN: VLAN offline succeeded(%u)\n",
+ vlan->dv_vlanid);
+ vlan->dv_flags |= flags;
+ }
+ }
+
+ node->vc_state |= state;
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_get_info() - Gather usage information for this resource.
+ */
+/*ARGSUSED*/
+int
+vlan_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_REFRESH);
+ if (node == NULL) {
+ rcm_log_message(RCM_INFO,
+ _("VLAN: get_info(%s) unrecognized resource\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ *usagep = vlan_usage(node);
+ (void) mutex_unlock(&cache_lock);
+ if (*usagep == NULL) {
+ /* most likely malloc failure */
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: get_info(%s) malloc failure\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOMEM;
+ return (RCM_FAILURE);
+ }
+
+ /* Set client/role properties */
+ (void) nvlist_add_string(props, RCM_CLIENT_NAME, "VLAN");
+
+ rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s) info = %s\n",
+ rsrc, *usagep);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_suspend() - Nothing to do, always okay
+ */
+/*ARGSUSED*/
+static int
+vlan_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
+ uint_t flags, char **errorp, rcm_info_t **info)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: suspend(%s)\n", rsrc);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_resume() - Nothing to do, always okay
+ */
+/*ARGSUSED*/
+static int
+vlan_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **info)
+{
+ rcm_log_message(RCM_TRACE1, "VLAN: resume(%s)\n", rsrc);
+ return (RCM_SUCCESS);
+}
+
+/*
+ * vlan_consumer_remove()
+ *
+ * Notify VLAN consumers to remove cache.
+ */
+static int
+vlan_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
+ rcm_info_t **info)
+{
+ dl_vlan_t *vlan = NULL;
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ int ret = RCM_SUCCESS;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove (%s)\n",
+ node->vc_resource);
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+
+ /*
+ * This will only be called when the offline operation
+ * succeeds, so the VLAN consumers must have been offlined
+ * at this point.
+ */
+ assert(vlan->dv_flags & VLAN_CONSUMER_OFFLINED);
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, vlan->dv_vlanid);
+
+ ret = rcm_notify_remove(hd, rsrc, flags, info);
+ if (ret != RCM_SUCCESS) {
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: notify remove failed (%s)\n"), rsrc);
+ break;
+ }
+ }
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove done\n");
+ return (ret);
+}
+
+/*
+ * vlan_remove() - remove a resource from cache
+ */
+/*ARGSUSED*/
+static int
+vlan_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, rcm_info_t **info)
+{
+ link_cache_t *node;
+ int rv;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: remove(%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node == NULL) {
+ rcm_log_message(RCM_INFO,
+ _("VLAN: remove(%s) unrecognized resource\n"), rsrc);
+ (void) mutex_unlock(&cache_lock);
+ errno = ENOENT;
+ return (RCM_FAILURE);
+ }
+
+ /* remove the cached entry for the resource */
+ cache_remove(node);
+ (void) mutex_unlock(&cache_lock);
+
+ rv = vlan_consumer_remove(hd, node, flags, info);
+ node_free(node);
+ return (rv);
+}
+
+/*
+ * vlan_notify_event - Project private implementation to receive new resource
+ * events. It intercepts all new resource events. If the
+ * new resource is a network resource, pass up a notify
+ * for it too. The new resource need not be cached, since
+ * it is done at register again.
+ */
+/*ARGSUSED*/
+static int
+vlan_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
+ char **errorp, nvlist_t *nvl, rcm_info_t **info)
+{
+ nvpair_t *nvp = NULL;
+ datalink_id_t linkid;
+ uint64_t id64;
+ int rv = RCM_SUCCESS;
+
+ rcm_log_message(RCM_TRACE1, "VLAN: notify_event(%s)\n", rsrc);
+
+ if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
+ vlan_log_err(DATALINK_INVALID_LINKID, errorp,
+ "unrecognized event");
+ errno = EINVAL;
+ return (RCM_FAILURE);
+ }
+
+ /* Update cache to reflect latest VLANs */
+ if (cache_update(hd) < 0) {
+ vlan_log_err(DATALINK_INVALID_LINKID, errorp,
+ "private Cache update failed");
+ return (RCM_FAILURE);
+ }
+
+ /*
+ * Try best to recover all configuration.
+ */
+ rcm_log_message(RCM_DEBUG, "VLAN: process_nvlist\n");
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
+ continue;
+
+ if (nvpair_value_uint64(nvp, &id64) != 0) {
+ vlan_log_err(DATALINK_INVALID_LINKID, errorp,
+ "cannot get linkid");
+ rv = RCM_FAILURE;
+ continue;
+ }
+
+ linkid = (datalink_id_t)id64;
+ if (vlan_configure(hd, linkid) != 0) {
+ vlan_log_err(linkid, errorp, "configuring failed");
+ rv = RCM_FAILURE;
+ continue;
+ }
+
+ /* Notify all VLAN consumers */
+ if (vlan_consumer_notify(hd, linkid, errorp, flags,
+ info) != 0) {
+ vlan_log_err(linkid, errorp, "consumer notify failed");
+ rv = RCM_FAILURE;
+ }
+ }
+
+ rcm_log_message(RCM_TRACE1,
+ "VLAN: notify_event: link configuration complete\n");
+ return (rv);
+}
+
+/*
+ * vlan_usage - Determine the usage of a link.
+ * The returned buffer is owned by caller, and the caller
+ * must free it up when done.
+ */
+static char *
+vlan_usage(link_cache_t *node)
+{
+ dl_vlan_t *vlan;
+ int nvlan;
+ char *buf;
+ const char *fmt;
+ char *sep;
+ char errmsg[DLADM_STRSIZE];
+ char name[MAXLINKNAMELEN];
+ dladm_status_t status;
+ size_t bufsz;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: usage(%s)\n", node->vc_resource);
+
+ assert(MUTEX_HELD(&cache_lock));
+ if ((status = dladm_datalink_id2info(node->vc_linkid, NULL, NULL, NULL,
+ name, sizeof (name))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: usage(%s) get link name failure(%s)\n"),
+ node->vc_resource, dladm_status2str(status, errmsg));
+ return (NULL);
+ }
+
+ if (node->vc_state & CACHE_NODE_OFFLINED)
+ fmt = _("%1$s offlined");
+ else
+ fmt = _("%1$s VLANs: ");
+
+ /* TRANSLATION_NOTE: separator used between VLAN linkids */
+ sep = _(", ");
+
+ nvlan = 0;
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
+ nvlan++;
+
+ /* space for VLANs and separators, plus message */
+ bufsz = nvlan * (MAXLINKNAMELEN + strlen(sep)) +
+ strlen(fmt) + MAXLINKNAMELEN + 1;
+ if ((buf = malloc(bufsz)) == NULL) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: usage(%s) malloc failure(%s)\n"),
+ node->vc_resource, strerror(errno));
+ return (NULL);
+ }
+ (void) snprintf(buf, bufsz, fmt, name);
+
+ if (node->vc_state & CACHE_NODE_OFFLINED) {
+ /* Nothing else to do */
+ rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
+ node->vc_resource, buf);
+ return (buf);
+ }
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ rcm_log_message(RCM_DEBUG, "VLAN:= %u\n", vlan->dv_vlanid);
+
+ if ((status = dladm_datalink_id2info(vlan->dv_vlanid, NULL,
+ NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: usage(%s) get vlan %u name failure(%s)\n"),
+ node->vc_resource, vlan->dv_vlanid,
+ dladm_status2str(status, errmsg));
+ free(buf);
+ return (NULL);
+ }
+
+ (void) strlcat(buf, name, bufsz);
+ if (vlan->dv_next != NULL)
+ (void) strlcat(buf, sep, bufsz);
+ }
+
+ rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
+ node->vc_resource, buf);
+
+ return (buf);
+}
+
+/*
+ * Cache management routines, all cache management functions should be
+ * be called with cache_lock held.
+ */
+
+/*
+ * cache_lookup() - Get a cache node for a resource.
+ * Call with cache lock held.
+ *
+ * This ensures that the cache is consistent with the system state and
+ * returns a pointer to the cache element corresponding to the resource.
+ */
+static link_cache_t *
+cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: cache lookup(%s)\n", rsrc);
+
+ assert(MUTEX_HELD(&cache_lock));
+ if (options & CACHE_REFRESH) {
+ /* drop lock since update locks cache again */
+ (void) mutex_unlock(&cache_lock);
+ (void) cache_update(hd);
+ (void) mutex_lock(&cache_lock);
+ }
+
+ node = cache_head.vc_next;
+ for (; node != &cache_tail; node = node->vc_next) {
+ if (strcmp(rsrc, node->vc_resource) == 0) {
+ rcm_log_message(RCM_TRACE2,
+ "VLAN: cache lookup succeeded(%s)\n", rsrc);
+ return (node);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * node_free - Free a node from the cache
+ */
+static void
+node_free(link_cache_t *node)
+{
+ dl_vlan_t *vlan, *next;
+
+ if (node != NULL) {
+ free(node->vc_resource);
+
+ /* free the VLAN list */
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
+ next = vlan->dv_next;
+ free(vlan);
+ }
+ free(node);
+ }
+}
+
+/*
+ * cache_insert - Insert a resource node in cache
+ */
+static void
+cache_insert(link_cache_t *node)
+{
+ assert(MUTEX_HELD(&cache_lock));
+
+ /* insert at the head for best performance */
+ node->vc_next = cache_head.vc_next;
+ node->vc_prev = &cache_head;
+
+ node->vc_next->vc_prev = node;
+ node->vc_prev->vc_next = node;
+}
+
+/*
+ * cache_remove() - Remove a resource node from cache.
+ */
+static void
+cache_remove(link_cache_t *node)
+{
+ assert(MUTEX_HELD(&cache_lock));
+ node->vc_next->vc_prev = node->vc_prev;
+ node->vc_prev->vc_next = node->vc_next;
+ node->vc_next = NULL;
+ node->vc_prev = NULL;
+}
+
+typedef struct vlan_update_arg_s {
+ rcm_handle_t *hd;
+ int retval;
+} vlan_update_arg_t;
+
+/*
+ * vlan_update() - Update physical interface properties
+ */
+static int
+vlan_update(datalink_id_t vlanid, void *arg)
+{
+ vlan_update_arg_t *vlan_update_argp = arg;
+ rcm_handle_t *hd = vlan_update_argp->hd;
+ link_cache_t *node;
+ dl_vlan_t *vlan;
+ char *rsrc;
+ dladm_vlan_attr_t vlan_attr;
+ dladm_status_t status;
+ char errmsg[DLADM_STRSIZE];
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_update(%u)\n", vlanid);
+
+ assert(MUTEX_HELD(&cache_lock));
+ status = dladm_vlan_info(vlanid, &vlan_attr, DLADM_OPT_ACTIVE);
+ if (status != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_TRACE1,
+ "VLAN: vlan_update() cannot get vlan information for "
+ "%u(%s)\n", vlanid, dladm_status2str(status, errmsg));
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ rsrc = malloc(RCM_LINK_RESOURCE_MAX);
+ if (rsrc == NULL) {
+ rcm_log_message(RCM_ERROR, _("VLAN: malloc error(%s): %u\n"),
+ strerror(errno), vlanid);
+ goto done;
+ }
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, vlan_attr.dv_linkid);
+
+ node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
+ if (node != NULL) {
+ rcm_log_message(RCM_DEBUG,
+ "VLAN: %s already registered (vlanid:%d)\n",
+ rsrc, vlan_attr.dv_vid);
+ free(rsrc);
+ } else {
+ rcm_log_message(RCM_DEBUG,
+ "VLAN: %s is a new resource (vlanid:%d)\n",
+ rsrc, vlan_attr.dv_vid);
+ if ((node = calloc(1, sizeof (link_cache_t))) == NULL) {
+ free(rsrc);
+ rcm_log_message(RCM_ERROR, _("VLAN: calloc: %s\n"),
+ strerror(errno));
+ goto done;
+ }
+
+ node->vc_resource = rsrc;
+ node->vc_vlan = NULL;
+ node->vc_linkid = vlan_attr.dv_linkid;
+ node->vc_state |= CACHE_NODE_NEW;
+ }
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ if (vlan->dv_vlanid == vlanid) {
+ vlan->dv_flags &= ~VLAN_STALE;
+ break;
+ }
+ }
+
+ if (vlan == NULL) {
+ if ((vlan = calloc(1, sizeof (dl_vlan_t))) == NULL) {
+ rcm_log_message(RCM_ERROR, _("VLAN: malloc: %s\n"),
+ strerror(errno));
+ if (node->vc_state & CACHE_NODE_NEW) {
+ free(rsrc);
+ free(node);
+ }
+ goto done;
+ }
+ vlan->dv_vlanid = vlanid;
+ vlan->dv_next = node->vc_vlan;
+ vlan->dv_prev = NULL;
+ if (node->vc_vlan != NULL)
+ node->vc_vlan->dv_prev = vlan;
+ node->vc_vlan = vlan;
+ }
+
+ vlan->dv_implicit = vlan_attr.dv_implicit;
+ node->vc_state &= ~CACHE_NODE_STALE;
+
+ if (node->vc_state & CACHE_NODE_NEW)
+ cache_insert(node);
+
+ rcm_log_message(RCM_TRACE3, "VLAN: vlan_update: succeeded(%u)\n",
+ vlanid);
+ ret = 0;
+done:
+ vlan_update_argp->retval = ret;
+ return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
+}
+
+/*
+ * vlan_update_all() - Determine all VLAN links in the system
+ */
+static int
+vlan_update_all(rcm_handle_t *hd)
+{
+ vlan_update_arg_t arg = {NULL, 0};
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_update_all\n");
+
+ assert(MUTEX_HELD(&cache_lock));
+ arg.hd = hd;
+ (void) dladm_walk_datalink_id(vlan_update, &arg, DATALINK_CLASS_VLAN,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
+ return (arg.retval);
+}
+
+/*
+ * cache_update() - Update cache with latest interface info
+ */
+static int
+cache_update(rcm_handle_t *hd)
+{
+ link_cache_t *node, *nnode;
+ dl_vlan_t *vlan;
+ int rv;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: cache_update\n");
+
+ (void) mutex_lock(&cache_lock);
+
+ /* first we walk the entire cache, marking each entry stale */
+ node = cache_head.vc_next;
+ for (; node != &cache_tail; node = node->vc_next) {
+ node->vc_state |= CACHE_NODE_STALE;
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
+ vlan->dv_flags |= VLAN_STALE;
+ }
+
+ rv = vlan_update_all(hd);
+
+ /*
+ * Continue to delete all stale nodes from the cache even
+ * vlan_update_all() failed. Unregister link that are not offlined
+ * and still in cache
+ */
+ for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
+ dl_vlan_t *vlan, *next;
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
+ next = vlan->dv_next;
+
+ /* clear stale VLANs */
+ if (vlan->dv_flags & VLAN_STALE) {
+ if (vlan->dv_prev != NULL)
+ vlan->dv_prev->dv_next = next;
+ else
+ node->vc_vlan = next;
+
+ if (next != NULL)
+ next->dv_prev = vlan->dv_prev;
+ free(vlan);
+ }
+ }
+
+ nnode = node->vc_next;
+ if (node->vc_state & CACHE_NODE_STALE) {
+ (void) rcm_unregister_interest(hd, node->vc_resource,
+ 0);
+ rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
+ node->vc_resource);
+ assert(node->vc_vlan == NULL);
+ cache_remove(node);
+ node_free(node);
+ continue;
+ }
+
+ if (!(node->vc_state & CACHE_NODE_NEW))
+ continue;
+
+ if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
+ RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to register %s\n"),
+ node->vc_resource);
+ rv = -1;
+ } else {
+ rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
+ node->vc_resource);
+ node->vc_state &= ~CACHE_NODE_NEW;
+ }
+ }
+
+ (void) mutex_unlock(&cache_lock);
+ return (rv);
+}
+
+/*
+ * cache_free() - Empty the cache
+ */
+static void
+cache_free()
+{
+ link_cache_t *node;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: cache_free\n");
+
+ (void) mutex_lock(&cache_lock);
+ node = cache_head.vc_next;
+ while (node != &cache_tail) {
+ cache_remove(node);
+ node_free(node);
+ node = cache_head.vc_next;
+ }
+ (void) mutex_unlock(&cache_lock);
+}
+
+/*
+ * vlan_log_err() - RCM error log wrapper
+ */
+static void
+vlan_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
+{
+ char link[MAXLINKNAMELEN];
+ char errstr[DLADM_STRSIZE];
+ dladm_status_t status;
+ int len;
+ const char *errfmt;
+ char *error;
+
+ link[0] = '\0';
+ if (linkid != DATALINK_INVALID_LINKID) {
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+
+ (void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
+ RCM_LINK_PREFIX, linkid);
+
+ rcm_log_message(RCM_ERROR, _("VLAN: %s(%s)\n"), errmsg, rsrc);
+ if ((status = dladm_datalink_id2info(linkid, NULL, NULL,
+ NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: cannot get link name for (%s) %s\n"),
+ rsrc, dladm_status2str(status, errstr));
+ }
+ } else {
+ rcm_log_message(RCM_ERROR, _("VLAN: %s\n"), errmsg);
+ }
+
+ errfmt = strlen(link) > 0 ? _("VLAN: %s(%s)") : _("VLAN: %s");
+ len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
+ if ((error = malloc(len)) != NULL) {
+ if (strlen(link) > 0)
+ (void) snprintf(error, len, errfmt, errmsg, link);
+ else
+ (void) snprintf(error, len, errfmt, errmsg);
+ }
+
+ if (errorp != NULL)
+ *errorp = error;
+}
+
+/*
+ * vlan_consumer_online()
+ *
+ * Notify online to VLAN consumers.
+ */
+/* ARGSUSED */
+static void
+vlan_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
+ uint_t flags, rcm_info_t **info)
+{
+ dl_vlan_t *vlan;
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online (%s)\n",
+ node->vc_resource);
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ if (!(vlan->dv_flags & VLAN_CONSUMER_OFFLINED))
+ continue;
+
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, vlan->dv_vlanid);
+
+ if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS)
+ vlan->dv_flags &= ~VLAN_CONSUMER_OFFLINED;
+ }
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online done\n");
+}
+
+/*
+ * vlan_consumer_offline()
+ *
+ * Offline VLAN consumers.
+ */
+static int
+vlan_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
+ uint_t flags, rcm_info_t **info)
+{
+ dl_vlan_t *vlan;
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ int ret = RCM_SUCCESS;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline (%s)\n",
+ node->vc_resource);
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
+ RCM_LINK_PREFIX, vlan->dv_vlanid);
+
+ ret = rcm_request_offline(hd, rsrc, flags, info);
+ if (ret != RCM_SUCCESS)
+ break;
+
+ vlan->dv_flags |= VLAN_CONSUMER_OFFLINED;
+ }
+
+ if (vlan != NULL)
+ vlan_consumer_online(hd, node, errorp, flags, info);
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline done\n");
+ return (ret);
+}
+
+/*
+ * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
+ * Return 0 on success, -1 on failure.
+ */
+static int
+vlan_notify_new_vlan(rcm_handle_t *hd, char *rsrc)
+{
+ link_cache_t *node;
+ dl_vlan_t *vlan;
+ nvlist_t *nvl = NULL;
+ uint64_t id;
+ int ret = -1;
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc);
+
+ (void) mutex_lock(&cache_lock);
+ if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
+ (void) mutex_unlock(&cache_lock);
+ return (0);
+ }
+
+ if (nvlist_alloc(&nvl, 0, 0) != 0) {
+ (void) mutex_unlock(&cache_lock);
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: failed to allocate nvlist\n"));
+ goto done;
+ }
+
+ for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
+ if (!vlan->dv_implicit) {
+ rcm_log_message(RCM_TRACE2,
+ "VLAN: vlan_notify_new_vlan add (%u)\n",
+ vlan->dv_vlanid);
+
+ id = vlan->dv_vlanid;
+ if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to construct nvlist\n"));
+ (void) mutex_unlock(&cache_lock);
+ goto done;
+ }
+ }
+ }
+ (void) mutex_unlock(&cache_lock);
+
+ if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
+ RCM_SUCCESS) {
+ rcm_log_message(RCM_ERROR,
+ _("VLAN: failed to notify %s event for %s\n"),
+ RCM_RESOURCE_LINK_NEW, node->vc_resource);
+ goto done;
+ }
+
+ ret = 0;
+done:
+ if (nvl != NULL)
+ nvlist_free(nvl);
+ return (ret);
+}
+
+/*
+ * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
+ */
+static int
+vlan_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
+ uint_t flags, rcm_info_t **info)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ link_cache_t *node;
+
+ /* Check for the interface in the cache */
+ (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
+ linkid);
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify(%s)\n", rsrc);
+
+ /*
+ * Inform IP consumers of the new link.
+ */
+ if (vlan_notify_new_vlan(hd, rsrc) != 0) {
+ (void) mutex_lock(&cache_lock);
+ if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) {
+ (void) vlan_offline_vlan(node, VLAN_STALE,
+ CACHE_NODE_STALE);
+ }
+ (void) mutex_unlock(&cache_lock);
+ rcm_log_message(RCM_TRACE2,
+ "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc);
+ return (-1);
+ }
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n");
+ return (0);
+}
+
+typedef struct vlan_up_arg_s {
+ datalink_id_t linkid;
+ int retval;
+} vlan_up_arg_t;
+
+static int
+vlan_up(datalink_id_t vlanid, void *arg)
+{
+ vlan_up_arg_t *vlan_up_argp = arg;
+ dladm_status_t status;
+ dladm_vlan_attr_t vlan_attr;
+ char errmsg[DLADM_STRSIZE];
+
+ status = dladm_vlan_info(vlanid, &vlan_attr, DLADM_OPT_PERSIST);
+ if (status != DLADM_STATUS_OK) {
+ rcm_log_message(RCM_TRACE1,
+ "VLAN: vlan_up(): cannot get information for VLAN %u "
+ "(%s)\n", vlanid, dladm_status2str(status, errmsg));
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (vlan_attr.dv_linkid != vlan_up_argp->linkid)
+ return (DLADM_WALK_CONTINUE);
+
+ rcm_log_message(RCM_TRACE3, "VLAN: vlan_up(%u)\n", vlanid);
+ if ((status = dladm_vlan_up(vlanid)) == DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ /*
+ * Prompt the warning message and continue to UP other VLANs.
+ */
+ rcm_log_message(RCM_WARNING,
+ _("VLAN: VLAN up failed (%u): %s\n"),
+ vlanid, dladm_status2str(status, errmsg));
+
+ vlan_up_argp->retval = -1;
+ return (DLADM_WALK_CONTINUE);
+}
+
+/*
+ * vlan_configure() - Configure VLANs over a physical link after it attaches
+ */
+static int
+vlan_configure(rcm_handle_t *hd, datalink_id_t linkid)
+{
+ char rsrc[RCM_LINK_RESOURCE_MAX];
+ link_cache_t *node;
+ vlan_up_arg_t arg = {DATALINK_INVALID_LINKID, 0};
+
+ /* Check for the VLANs in the cache */
+ (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
+
+ rcm_log_message(RCM_TRACE2, "VLAN: vlan_configure(%s)\n", rsrc);
+
+ /* Check if the link is new or was previously offlined */
+ (void) mutex_lock(&cache_lock);
+ if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
+ (!(node->vc_state & CACHE_NODE_OFFLINED))) {
+ rcm_log_message(RCM_TRACE2,
+ "VLAN: Skipping configured interface(%s)\n", rsrc);
+ (void) mutex_unlock(&cache_lock);
+ return (0);
+ }
+ (void) mutex_unlock(&cache_lock);
+
+ arg.linkid = linkid;
+ (void) dladm_walk_datalink_id(vlan_up, &arg, DATALINK_CLASS_VLAN,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
+
+ if (arg.retval == 0) {
+ rcm_log_message(RCM_TRACE2,
+ "VLAN: vlan_configure succeeded(%s)\n", rsrc);
+ }
+ return (arg.retval);
+}
diff --git a/usr/src/cmd/rpcsvc/rstat_proc.c b/usr/src/cmd/rpcsvc/rstat_proc.c
index c2a93dd933..6e347cbf07 100644
--- a/usr/src/cmd/rpcsvc/rstat_proc.c
+++ b/usr/src/cmd/rpcsvc/rstat_proc.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -975,9 +974,15 @@ init_net(void)
/*
* We found a device of interest.
* Now, let's see if there's a kstat for it.
+ * First we try to query the "link" kstats in case
+ * the link is renamed. If that fails, fallback
+ * to legacy ktats for those non-GLDv3 links.
*/
- if ((ksp = kstat_lookup(kc, NULL, -1, namebuf)) == NULL)
+ if (((ksp = kstat_lookup(kc, "link", 0, namebuf))
+ == NULL) && ((ksp = kstat_lookup(kc, NULL, -1,
+ namebuf)) == NULL)) {
continue;
+ }
if (ksp->ks_type != KSTAT_TYPE_NAMED)
continue;
if (kstat_read(kc, ksp, NULL) == -1)
diff --git a/usr/src/cmd/svc/milestone/manifest-import b/usr/src/cmd/svc/milestone/manifest-import
index d5d974fac6..363e410179 100644
--- a/usr/src/cmd/svc/milestone/manifest-import
+++ b/usr/src/cmd/svc/milestone/manifest-import
@@ -3,9 +3,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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
# or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -508,6 +507,18 @@ svccfg_apply /var/svc/profile/platform.xml
/var/svc/profile/upgrade.app.`date +\%Y\%m\%d\%H\%M\%S`
activity=true
fi
+
+ #
+ # Rename the datalink upgrade script file. This script is used in the
+ # network/physical service to upgrade datalink configuration, but
+ # the file cannot be renamed until now (when the file system becomes
+ # read-write).
+ #
+ datalink_script=/var/svc/profile/upgrade_datalink
+ if [ -f "${datalink_script}" ]; then
+ /usr/bin/mv "${datalink_script}" \
+ "${datalink_script}".app.`date +\%Y\%m\%d\%H\%M\%S`
+ fi
)
#
diff --git a/usr/src/cmd/svc/milestone/net-nwam b/usr/src/cmd/svc/milestone/net-nwam
index faee0c3c09..332b965aeb 100644
--- a/usr/src/cmd/svc/milestone/net-nwam
+++ b/usr/src/cmd/svc/milestone/net-nwam
@@ -20,13 +20,14 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
. /lib/svc/share/smf_include.sh
+. /lib/svc/share/net_include.sh
#
# In a shared-IP zone we need this service to be up, but all of the work
@@ -43,6 +44,20 @@ case "$1" in
'start')
if smf_is_globalzone; then
+ net_reconfigure || exit $SMF_EXIT_ERR_CONFIG
+
+ #
+ # Upgrade handling. The upgrade file consists of a series
+ # of dladm(1M) commands. Note that after we are done, we
+ # cannot rename the upgrade script file as the file system
+ # is still read-only at this point. Defer this to the
+ # manifest-import service.
+ #
+ upgrade_script=/var/svc/profile/upgrade_datalink
+ if [ -f "${upgrade_script}" ]; then
+ . "${upgrade_script}"
+ fi
+
# Initialize security objects.
/sbin/dladm init-secobj
fi
diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical
index 19787a6945..c562d22902 100644
--- a/usr/src/cmd/svc/milestone/net-physical
+++ b/usr/src/cmd/svc/milestone/net-physical
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
@@ -59,6 +59,19 @@ SUNW_NO_MPATHD=; export SUNW_NO_MPATHD
smf_netstrategy
if smf_is_globalzone; then
+ net_reconfigure || exit $SMF_EXIT_ERR_CONFIG
+
+ #
+ # Upgrade handling. The upgrade file consists of a series of dladm(1M)
+ # commands. Note that after we are done, we cannot rename the upgrade
+ # script file as the file system is still read-only at this point.
+ # Defer this to the manifest-import service.
+ #
+ upgrade_script=/var/svc/profile/upgrade_datalink
+ if [ -f "${upgrade_script}" ]; then
+ . "${upgrade_script}"
+ fi
+
#
# Bring up link aggregations and initialize security objects.
# Note that link property initialization is deferred until after
@@ -66,6 +79,7 @@ if smf_is_globalzone; then
# be unloaded (and the property settings lost).
#
/sbin/dladm up-aggr
+ /sbin/dladm up-vlan
/sbin/dladm init-secobj
fi
diff --git a/usr/src/cmd/svc/seed/Makefile b/usr/src/cmd/svc/seed/Makefile
index 37da95d671..807217466b 100644
--- a/usr/src/cmd/svc/seed/Makefile
+++ b/usr/src/cmd/svc/seed/Makefile
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -65,6 +65,7 @@ COMMON_DESCRIPTIONS = \
../milestone/root-fs.xml \
../milestone/single-user.xml \
../milestone/usr-fs.xml \
+ ../../dlmgmtd/dlmgmt.xml \
../../rpcbind/bind.xml \
#
diff --git a/usr/src/cmd/svc/seed/inc.flg b/usr/src/cmd/svc/seed/inc.flg
index 8224abb7f3..37575fd93e 100644
--- a/usr/src/cmd/svc/seed/inc.flg
+++ b/usr/src/cmd/svc/seed/inc.flg
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -28,6 +28,7 @@
echo_file usr/src/cmd/cmd-inet/usr.lib/inetd/inetd-upgrade.xml
echo_file usr/src/cmd/rpcbind/bind.xml
+echo_file usr/src/cmd/dlmgmtd/dlmgmt.xml
echo_file usr/src/cmd/utmpd/utmp.xml
echo_file usr/src/cmd/lvm/util/metainit.xml
echo_file usr/src/cmd/lvm/md_monitord/mdmonitor.xml
diff --git a/usr/src/cmd/svc/shell/net_include.sh b/usr/src/cmd/svc/shell/net_include.sh
index 4af6b40d30..989a780384 100644
--- a/usr/src/cmd/svc/shell/net_include.sh
+++ b/usr/src/cmd/svc/shell/net_include.sh
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -580,3 +580,65 @@ move_addresses()
done
echo "."
}
+
+#
+# net_reconfigure is called from the network/physical service (by the
+# net-physical and net-nwam method scripts) to perform tasks that only
+# need to be done during a reconfigure boot. This needs to be
+# isolated in a function since network/physical has two instances
+# (default and nwam) that have distinct method scripts that each need
+# to do these things.
+#
+net_reconfigure ()
+{
+ #
+ # Is this a reconfigure boot? If not, then there's nothing
+ # for us to do.
+ #
+ svcprop -q -p system/reconfigure system/svc/restarter:default
+ if [ $? -ne 0 ]; then
+ return 0
+ fi
+
+ #
+ # Ensure that the datalink-management service is running since
+ # manifest-import has not yet run for a first boot after
+ # upgrade. We wouldn't need to do that if manifest-import ran
+ # earlier in boot, since there is an explicit dependency
+ # between datalink-management and network/physical.
+ #
+ svcadm enable -ts network/datalink-management:default
+
+ #
+ # There is a bug in SMF which causes the svcadm command above
+ # to exit prematurely (with an error code of 3) before having
+ # waited for the service to come online after having enabled
+ # it. Until that bug is fixed, we need to have the following
+ # loop to explicitly wait for the service to come online.
+ #
+ i=0
+ while [ $i -lt 30 ]; do
+ i=`expr $i + 1`
+ sleep 1
+ state=`svcprop -p restarter/state \
+ network/datalink-management:default 2>/dev/null`
+ if [ $? -ne 0 ]; then
+ continue
+ elif [ "$state" = "online" ]; then
+ break
+ fi
+ done
+ if [ "$state" != "online" ]; then
+ echo "The network/datalink-management service \c"
+ echo "did not come online."
+ return 1
+ fi
+
+ #
+ # Initialize the set of physical links, and validate and
+ # remove all the physical links which were removed during the
+ # system shutdown.
+ #
+ /sbin/dladm init-phys
+ return 0
+}
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index b3c3d23352..f12895b7ed 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -839,8 +839,22 @@ const struct ioc {
{ (uint_t)LAIOC_MODIFY, "LAIOC_MODIFY", "laioc_modify"},
/* dld data-link ioctls */
- { (uint_t)DLDIOCATTR, "DLDIOCATTR", "dld_ioc_attr"},
- { (uint_t)DLDIOCVLAN, "DLDIOCVLAN", "dld_ioc_vlan"},
+ { (uint_t)DLDIOC_ATTR, "DLDIOC_ATTR", "dld_ioc_attr"},
+ { (uint_t)DLDIOC_PHYS_ATTR, "DLDIOC_PHYS_ATTR",
+ "dld_ioc_phys_attr"},
+ { (uint_t)DLDIOC_VLAN_ATTR, "DLDIOC_VLAN_ATTR",
+ "dld_ioc_vlan_attr"},
+ { (uint_t)DLDIOC_CREATE_VLAN, "DLDIOC_CREATE_VLAN",
+ "dld_ioc_create_vlan"},
+ { (uint_t)DLDIOC_DELETE_VLAN, "DLDIOC_DELETE_VLAN",
+ "dld_ioc_delete_vlan"},
+ { (uint_t)DLDIOC_SETAUTOPUSH, "DLDIOC_SETAUTOPUSH", "dld_ioc_ap"},
+ { (uint_t)DLDIOC_GETAUTOPUSH, "DLDIOC_GETAUTOPUSH", "dld_ioc_ap"},
+ { (uint_t)DLDIOC_CLRAUTOPUSH, "DLDIOC_CLRAUTOPUSH", "dld_ioc_ap"},
+ { (uint_t)DLDIOC_DOORSERVER, "DLDIOC_DOORSERVER", "dld_ioc_door"},
+ { (uint_t)DLDIOC_RENAME, "DLDIOC_RENAME", "dld_ioc_rename"},
+ { (uint_t)DLDIOC_SETZID, "DLDIOC_SETZID", "dld_ioc_setzid"},
+ { (uint_t)DLDIOC_GETZID, "DLDIOC_GETZID", "dld_ioc_getzid"},
/* ZFS ioctls */
{ (uint_t)ZFS_IOC_POOL_CREATE, "ZFS_IOC_POOL_CREATE",
diff --git a/usr/src/cmd/vna/vna.c b/usr/src/cmd/vna/vna.c
index cf13fd1140..c0bb80fd0a 100644
--- a/usr/src/cmd/vna/vna.c
+++ b/usr/src/cmd/vna/vna.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,125 +37,162 @@
#include <strings.h>
#include <sys/types.h>
#include <sys/ethernet.h>
+#include <libdllink.h>
#include <libdlvnic.h>
/*ARGSUSED*/
-static dladm_status_t
-v_print(void *arg, dladm_vnic_attr_sys_t *attr)
+static int
+v_print(datalink_id_t vnic_id, void *arg)
{
- if (attr->va_mac_len != ETHERADDRL)
- return (DLADM_STATUS_OK);
+ dladm_vnic_attr_sys_t attr;
+ char vnic[MAXLINKNAMELEN];
+ char link[MAXLINKNAMELEN];
- (void) printf("%d\t%s\t%s\n", attr->va_vnic_id, attr->va_dev_name,
- ether_ntoa((struct ether_addr *)(attr->va_mac_addr)));
+ if (dladm_vnic_info(vnic_id, &attr, DLADM_OPT_ACTIVE) !=
+ DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
- return (DLADM_STATUS_OK);
-}
+ if (attr.va_mac_len != ETHERADDRL)
+ return (DLADM_WALK_CONTINUE);
-static int
-v_list(void)
-{
- dladm_status_t status;
+ if (dladm_datalink_id2info(vnic_id, NULL, NULL, NULL, vnic,
+ sizeof (vnic)) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (dladm_datalink_id2info(attr.va_link_id, NULL, NULL, NULL, link,
+ sizeof (link)) != DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
- status = dladm_vnic_walk_sys(v_print, NULL);
+ (void) printf("%s\t%s\t%s\n", vnic, link,
+ ether_ntoa((struct ether_addr *)(attr.va_mac_addr)));
- if (status != DLADM_STATUS_OK)
- return (-1);
+ return (DLADM_WALK_CONTINUE);
+}
- return (0);
+static void
+v_list(void)
+{
+ (void) dladm_walk_datalink_id(v_print, NULL, DATALINK_CLASS_VNIC,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
}
-static dladm_status_t
-v_find(void *arg, dladm_vnic_attr_sys_t *attr)
+static int
+v_find(datalink_id_t vnic_id, void *arg)
{
dladm_vnic_attr_sys_t *specp = arg;
+ dladm_vnic_attr_sys_t attr;
- if (strncmp(attr->va_dev_name, specp->va_dev_name,
- strlen(attr->va_dev_name)) != 0)
- return (DLADM_STATUS_OK);
+ if (dladm_vnic_info(vnic_id, &attr, DLADM_OPT_ACTIVE) !=
+ DLADM_STATUS_OK) {
+ return (DLADM_WALK_CONTINUE);
+ }
- if (attr->va_mac_len != specp->va_mac_len)
- return (DLADM_STATUS_OK);
+ if (attr.va_link_id != specp->va_link_id)
+ return (DLADM_WALK_CONTINUE);
- if (memcmp(attr->va_mac_addr, specp->va_mac_addr,
- attr->va_mac_len) != 0)
- return (DLADM_STATUS_OK);
+ if (attr.va_mac_len != specp->va_mac_len)
+ return (DLADM_WALK_CONTINUE);
- specp->va_vnic_id = attr->va_vnic_id;
+ if (memcmp(attr.va_mac_addr, specp->va_mac_addr,
+ attr.va_mac_len) != 0) {
+ return (DLADM_WALK_CONTINUE);
+ }
- return (DLADM_STATUS_EXIST);
+ specp->va_vnic_id = attr.va_vnic_id;
+
+ return (DLADM_WALK_TERMINATE);
}
+/*
+ * Print out the link name of the VNIC.
+ */
static int
-v_add(char *dev, char *addr)
+v_add(char *link, char *addr)
{
struct ether_addr *ea;
dladm_vnic_attr_sys_t spec;
+ datalink_id_t vnic_id, linkid;
+ char vnic[MAXLINKNAMELEN];
dladm_status_t status;
- uint_t vid;
char buf[DLADM_STRSIZE];
ea = ether_aton(addr);
if (ea == NULL) {
- (void) fprintf(stderr, "Invalid ethernet address: %s\n",
- addr);
+ (void) fprintf(stderr, "Invalid ethernet address: %s\n", addr);
+ return (-1);
+ }
+
+ if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
+ DLADM_STATUS_OK) {
+ (void) fprintf(stderr, "Invalid link name: %s\n", link);
return (-1);
}
/*
- * If a VNIC already exists over the specified device
+ * If a VNIC already exists over the specified link
* with this MAC address, use it.
*/
- (void) strncpy(spec.va_dev_name, dev, sizeof (spec.va_dev_name) - 1);
+ spec.va_vnic_id = DATALINK_INVALID_LINKID;
+ spec.va_link_id = linkid;
spec.va_mac_len = ETHERADDRL;
(void) memcpy(spec.va_mac_addr, (uchar_t *)ea->ether_addr_octet,
spec.va_mac_len);
- status = dladm_vnic_walk_sys(v_find, &spec);
- switch (status) {
- case DLADM_STATUS_EXIST:
- vid = spec.va_vnic_id;
- break;
-
- case DLADM_STATUS_OK:
+ (void) dladm_walk_datalink_id(v_find, &spec, DATALINK_CLASS_VNIC,
+ DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
+ if (spec.va_vnic_id == DATALINK_INVALID_LINKID) {
/*
* None found, so create.
*/
- status = dladm_vnic_create(0, dev, VNIC_MAC_ADDR_TYPE_FIXED,
- (uchar_t *)ea->ether_addr_octet, ETHERADDRL,
- &vid, DLADM_VNIC_OPT_TEMP | DLADM_VNIC_OPT_AUTOID);
+ status = dladm_vnic_create(NULL, linkid,
+ VNIC_MAC_ADDR_TYPE_FIXED, (uchar_t *)ea->ether_addr_octet,
+ ETHERADDRL, &vnic_id, DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK) {
(void) fprintf(stderr, "dladm_vnic_create: %s\n",
dladm_status2str(status, buf));
return (-1);
}
- break;
+ } else {
+ vnic_id = spec.va_vnic_id;
+ }
- default:
- (void) fprintf(stderr, "dladm_vnic_walk_sys: %s\n",
+ if ((status = dladm_datalink_id2info(vnic_id, NULL, NULL, NULL, vnic,
+ sizeof (vnic))) != DLADM_STATUS_OK) {
+ (void) fprintf(stderr, "dladm_datalink_id2info: %s\n",
dladm_status2str(status, buf));
+ if (spec.va_vnic_id == DATALINK_INVALID_LINKID)
+ (void) dladm_vnic_delete(vnic_id, DLADM_OPT_ACTIVE);
return (-1);
- /* NOTREACHED */
}
- (void) printf("%d\n", vid);
+ (void) printf("%s\n", vnic);
return (0);
}
+/*
+ * v_remove() takes VNIC link name as the argument.
+ */
static int
-v_remove(char *vdev)
+v_remove(char *vnic)
{
- uint_t vid;
+ datalink_id_t vnic_id;
dladm_status_t status;
+ char buf[DLADM_STRSIZE];
- vid = atoi(vdev);
+ if ((status = dladm_name2info(vnic, &vnic_id, NULL, NULL, NULL)) !=
+ DLADM_STATUS_OK) {
+ (void) fprintf(stderr, "dladm_name2info: %s\n",
+ dladm_status2str(status, buf));
+ return (-1);
+ }
- status = dladm_vnic_delete(vid, DLADM_VNIC_OPT_TEMP);
+ status = dladm_vnic_delete(vnic_id, DLADM_OPT_ACTIVE);
if (status != DLADM_STATUS_OK) {
- char buf[DLADM_STRSIZE];
-
(void) fprintf(stderr, "dladm_vnic_delete: %s\n",
dladm_status2str(status, buf));
return (-1);
@@ -170,7 +207,8 @@ main(int argc, char *argv[])
switch (argc) {
case 1:
/* List operation. */
- return (v_list());
+ v_list();
+ return (0);
/* NOTREACHED */
case 2:
/* Remove operation. */
diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile
index 1b83c9b7e7..8f867e06ea 100644
--- a/usr/src/cmd/zoneadmd/Makefile
+++ b/usr/src/cmd/zoneadmd/Makefile
@@ -22,7 +22,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -43,7 +43,7 @@ CFLAGS += $(CCVERBOSE)
LAZYLIBS = $(ZLAZYLOAD) -ltsnet -ltsol $(ZNOLAZYLOAD)
lint := LAZYLIBS = -ltsnet -ltsol
LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
- -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ldlpi $(LAZYLIBS)
+ -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm $(LAZYLIBS)
XGETFLAGS += -a -x zoneadmd.xcl
.KEEP_STATE:
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 7e5941e02a..59225164a6 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -77,6 +77,7 @@
#include <sys/dlpi.h>
#include <libdlpi.h>
#include <libdllink.h>
+#include <libdlvlan.h>
#include <inet/tcp.h>
#include <arpa/inet.h>
@@ -122,8 +123,6 @@
#include <libtsnet.h>
#include <sys/priv.h>
-#include <sys/dld.h> /* DLIOCHOLDVLAN and friends */
-
#define V4_ADDR_LEN 32
#define V6_ADDR_LEN 128
@@ -148,8 +147,6 @@ static struct mnttab *resolve_lofs_mnts, *resolve_lofs_mnt_max;
static tsol_zcent_t *get_zone_label(zlog_t *, priv_set_t *);
static int tsol_mounts(zlog_t *, char *, char *);
static void tsol_unmounts(zlog_t *, char *);
-static int driver_hold_link(const char *name, zoneid_t zoneid);
-static int driver_rele_link(const char *name, zoneid_t zoneid);
static m_label_t *zlabel = NULL;
static m_label_t *zid_label = NULL;
@@ -2609,35 +2606,10 @@ add_datalink(zlog_t *zlogp, zoneid_t zoneid, char *dlname)
return (-1);
}
- /* Hold the link for this zone */
- if (dladm_hold_link(dlname, zoneid, B_FALSE) < 0) {
- int res, old_errno;
- dladm_attr_t da;
-
- /*
- * The following check is similar to 'dladm show-link'
- * to determine if this is a legacy interface.
- */
- old_errno = errno;
- res = dladm_info(dlname, &da);
- if (res < 0 && errno == ENODEV) {
- /*
- * Check if this is a link like 'ce*' which supports
- * a direct ioctl.
- */
- res = driver_hold_link(dlname, zoneid);
- if (res == 0)
- return (0);
-
- zerror(zlogp, B_FALSE, "WARNING: legacy network "
- "interface '%s'\nunsupported with an "
- "ip-type=exclusive configuration.", dlname);
- } else {
- errno = old_errno;
- zerror(zlogp, B_TRUE, "WARNING: unable to hold network "
- "interface '%s'.", dlname);
- }
-
+ /* Set zoneid of this link. */
+ if (dladm_setzid(dlname, zoneid) != DLADM_STATUS_OK) {
+ zerror(zlogp, B_TRUE, "WARNING: unable to add network "
+ "interface '%s'.", dlname);
(void) zone_remove_datalink(zoneid, dlname);
return (-1);
}
@@ -2661,13 +2633,10 @@ remove_datalink(zlog_t *zlogp, zoneid_t zoneid, char *dlname)
return (-1);
}
- if (dladm_rele_link(dlname, 0, B_FALSE) < 0) {
- /* Fallback to 'ce*' type link */
- if (driver_rele_link(dlname, 0) < 0) {
- zerror(zlogp, B_TRUE, "unable to release network "
- "interface '%s'", dlname);
- return (-1);
- }
+ if (dladm_setzid(dlname, GLOBAL_ZONEID) != DLADM_STATUS_OK) {
+ zerror(zlogp, B_TRUE, "unable to release network "
+ "interface '%s'", dlname);
+ return (-1);
}
return (0);
}
@@ -2733,21 +2702,34 @@ configure_exclusive_network_interfaces(zlog_t *zlogp)
}
/*
+ * Create the /dev entry for backward compatibility.
* Only create the /dev entry if it's not in use.
- * Note here the zone still boots when the interfaces
- * assigned is inaccessible, used by others, etc.
+ * Note that the zone still boots when the assigned
+ * interface is inaccessible, used by others, etc.
+ * Also, when vanity naming is used, some interface do
+ * do not have corresponding /dev node names (for example,
+ * vanity named aggregations). The /dev entry is not
+ * created in that case. The /dev/net entry is always
+ * accessible.
*/
if (add_datalink(zlogp, zoneid, nwiftab.zone_nwif_physical)
== 0) {
- if (di_prof_add_dev(prof, nwiftab.zone_nwif_physical)
- != 0) {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
- zerror(zlogp, B_TRUE,
- "failed to add network device");
- return (-1);
+ char name[DLPI_LINKNAME_MAX];
+ datalink_id_t linkid;
+
+ if (dladm_name2info(nwiftab.zone_nwif_physical,
+ &linkid, NULL, NULL, NULL) == DLADM_STATUS_OK &&
+ dladm_linkid2legacyname(linkid, name,
+ sizeof (name)) == DLADM_STATUS_OK) {
+ if (di_prof_add_dev(prof, name) != 0) {
+ (void) zonecfg_endnwifent(handle);
+ zonecfg_fini_handle(handle);
+ zerror(zlogp, B_TRUE,
+ "failed to add network device");
+ return (-1);
+ }
+ added = B_TRUE;
}
- added = B_TRUE;
}
}
(void) zonecfg_endnwifent(handle);
@@ -4679,71 +4661,3 @@ error:
lofs_discard_mnttab();
return (-1);
}
-
-/*
- * Common routine for driver_hold_link and driver_rele_link.
- * It invokes ioctl for a link like "ce*", for which the driver has been
- * enhanced to support DLDIOC{HOLD,RELE}VLAN.
- */
-static int
-driver_vlan_ioctl(const char *name, zoneid_t zoneid, int cmd)
-{
- int fd;
- uint_t ppa;
- dld_hold_vlan_t dhv;
- struct strioctl istr;
- char providername[IFNAMSIZ];
- char path[MAXPATHLEN];
-
- if (strlen(name) >= IFNAMSIZ) {
- errno = EINVAL;
- return (-1);
- }
-
- if (dlpi_parselink(name, providername, &ppa) != DLPI_SUCCESS) {
- errno = EINVAL;
- return (-1);
- }
-
- (void) snprintf(path, sizeof (path), "/dev/%s", providername);
- fd = open(path, O_RDWR);
- if (fd < 0)
- return (-1);
- bzero(&dhv, sizeof (dld_hold_vlan_t));
- (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
- dhv.dhv_zid = zoneid;
- dhv.dhv_docheck = B_FALSE;
-
- istr.ic_cmd = cmd;
- istr.ic_len = sizeof (dhv);
- istr.ic_dp = (void *)&dhv;
- istr.ic_timout = 0;
-
- if (ioctl(fd, I_STR, &istr) < 0) {
- int olderrno = errno;
- (void) close(fd);
- errno = olderrno;
- return (-1);
- }
- (void) close(fd);
- return (0);
-}
-
-/*
- * Hold a data-link where the style-2 datalink driver supports DLDIOCHOLDVLAN.
- */
-static int
-driver_hold_link(const char *name, zoneid_t zoneid)
-{
- return (driver_vlan_ioctl(name, zoneid, DLDIOCHOLDVLAN));
-}
-
-/*
- * Release a data-link where the style-2 datalink driver supports
- * DLDIOC{HOLD,RELE}VLAN.
- */
-static int
-driver_rele_link(const char *name, zoneid_t zoneid)
-{
- return (driver_vlan_ioctl(name, zoneid, DLDIOCRELEVLAN));
-}