diff options
Diffstat (limited to 'usr/src')
225 files changed, 25674 insertions, 9121 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index aebe1e341b..6ed5c8ab98 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -170,6 +170,7 @@ COMMON_SUBDIRS = \ cmd/ldapcachemgr \ cmd/line \ cmd/link \ + cmd/dlmgmtd \ cmd/locator \ cmd/lockstat \ cmd/lofiadm \ @@ -382,6 +383,7 @@ COMMON_SUBDIRS = \ lib/libtsnet \ lib/libtsol \ lib/libumem \ + lib/libuuid \ lib/libuutil \ lib/libwanboot \ lib/libwanbootutil \ diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index eaddb51f2a..f3a4937c83 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -67,6 +67,7 @@ ROOT.SYS= \ /dev \ /dev/dsk \ /dev/fd \ + /dev/net \ /dev/rdsk \ /dev/rmt \ /dev/pts \ @@ -919,10 +920,12 @@ $(ROOT)/usr/lib/libposix4.so:= REALPATH=../../lib/librt.so.1 $(ROOT)/usr/lib/libproc.so.1:= REALPATH=../../lib/libproc.so.1 $(ROOT)/usr/lib/libproc.so:= REALPATH=../../lib/libproc.so.1 $(ROOT)/usr/lib/libpthread.so.1:= REALPATH=../../lib/libpthread.so.1 +$(ROOT)/usr/lib/libpthread.so:= REALPATH=../../lib/libpthread.so.1 +$(ROOT)/usr/lib/librcm.so.1:= REALPATH=../../lib/librcm.so.1 +$(ROOT)/usr/lib/librcm.so:= REALPATH=../../lib/librcm.so.1 $(ROOT)/usr/lib/libresolv.so.1:= REALPATH=../../lib/libresolv.so.1 $(ROOT)/usr/lib/libresolv.so.2:= REALPATH=../../lib/libresolv.so.2 $(ROOT)/usr/lib/libresolv.so:= REALPATH=../../lib/libresolv.so.2 -$(ROOT)/usr/lib/libpthread.so:= REALPATH=../../lib/libpthread.so.1 $(ROOT)/usr/lib/librestart.so.1:= REALPATH=../../lib/librestart.so.1 $(ROOT)/usr/lib/librestart.so:= REALPATH=../../lib/librestart.so.1 $(ROOT)/usr/lib/librpcsvc.so.1:= REALPATH=../../lib/librpcsvc.so.1 @@ -1217,6 +1220,10 @@ $(ROOT)/usr/lib/$(MACH64)/libpthread.so.1:= \ REALPATH=../../../lib/$(MACH64)/libpthread.so.1 $(ROOT)/usr/lib/$(MACH64)/libpthread.so:= \ REALPATH=../../../lib/$(MACH64)/libpthread.so.1 +$(ROOT)/usr/lib/$(MACH64)/librcm.so.1:= \ + REALPATH=../../../lib/$(MACH64)/librcm.so.1 +$(ROOT)/usr/lib/$(MACH64)/librcm.so:= \ + REALPATH=../../../lib/$(MACH64)/librcm.so.1 $(ROOT)/usr/lib/$(MACH64)/libresolv.so.2:= \ REALPATH=../../../lib/$(MACH64)/libresolv.so.2 $(ROOT)/usr/lib/$(MACH64)/libresolv.so:= \ @@ -1504,6 +1511,8 @@ SYM.USRLIB= \ /usr/lib/libproc.so.1 \ /usr/lib/libpthread.so \ /usr/lib/libpthread.so.1 \ + /usr/lib/librcm.so \ + /usr/lib/librcm.so.1 \ /usr/lib/libresolv.so \ /usr/lib/libresolv.so.1 \ /usr/lib/libresolv.so.2 \ @@ -1736,6 +1745,8 @@ SYM.USRLIB64= \ /usr/lib/$(MACH64)/libproc.so.1 \ /usr/lib/$(MACH64)/libpthread.so \ /usr/lib/$(MACH64)/libpthread.so.1 \ + /usr/lib/$(MACH64)/librcm.so \ + /usr/lib/$(MACH64)/librcm.so.1 \ /usr/lib/$(MACH64)/libresolv.so \ /usr/lib/$(MACH64)/libresolv.so.2 \ /usr/lib/$(MACH64)/librestart.so \ 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 = ¬sup; } 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/dlmgmtd/svc-dlmgmtd b/usr/src/cmd/dlmgmtd/svc-dlmgmtd new file mode 100644 index 0000000000..7559207535 --- /dev/null +++ b/usr/src/cmd/dlmgmtd/svc-dlmgmtd @@ -0,0 +1,45 @@ +#!/sbin/sh +# +# 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" + +. /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)); -} diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 02d7c65ca7..05ac08225b 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -500,20 +500,20 @@ libdevinfo: libnvpair libsec libdhcpagent: libsocket libdhcputil libuuid libdlpi libdhcpsvc: libinetutil libdhcputil: libnsl libgen libinetutil libdlpi -libdladm: libdlpi libdevinfo libinetutil libsocket +libdladm: libdevinfo libinetutil libsocket libdll: libast -libdlpi: libinetutil +libdlpi: libinetutil libdladm libdtrace: libproc libgen libctf libdtrace_jni: libuutil libdtrace libefi: libuuid libfstyp: libnvpair libelfsign: libcryptoutil libkmf libidmap: libnsl -libinetcfg: libnsl libsocket libdevinfo +libinetcfg: libnsl libsocket libdlpi libkmf: libcryptoutil pkcs11 openssl libnsl: libmd5 libscf libmapid: libresolv -libuuid: libdlpi libdladm +libuuid: libdlpi libinetutil: libsocket libsecdb: libnsl libsasl: libgss libsocket pkcs11 libmd diff --git a/usr/src/lib/brand/native/zone/platform.xml b/usr/src/lib/brand/native/zone/platform.xml index 6e77521551..3d375db57c 100644 --- a/usr/src/lib/brand/native/zone/platform.xml +++ b/usr/src/lib/brand/native/zone/platform.xml @@ -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" @@ -61,6 +61,7 @@ <device match="lo3" /> <device match="log" /> <device match="logindmux" /> + <device match="net/*" /> <device match="null" /> <device match="openprom" arch="sparc" /> <device match="poll" /> diff --git a/usr/src/lib/brand/sn1/zone/platform.xml b/usr/src/lib/brand/sn1/zone/platform.xml index 9e9734e03e..7b1d23294a 100644 --- a/usr/src/lib/brand/sn1/zone/platform.xml +++ b/usr/src/lib/brand/sn1/zone/platform.xml @@ -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" @@ -61,6 +61,7 @@ <device match="lo3" /> <device match="log" /> <device match="logindmux" /> + <device match="net/*" /> <device match="null" /> <device match="openprom" arch="sparc" /> <device match="poll" /> diff --git a/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.c b/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.c index 6ae2eeb6f2..f917bb5ae4 100644 --- a/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.c +++ b/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.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 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -145,9 +144,9 @@ ap_rcm_ops[] = { #define RCM_MAX_FORMAT 80 #ifdef __sparcv9 -#define RCMLIB "/usr/lib/sparcv9/librcm.so"; +#define RCMLIB "/lib/sparcv9/librcm.so"; #else -#define RCMLIB "/usr/lib/librcm.so"; +#define RCMLIB "/lib/librcm.so"; #endif static cfga_err_t diff --git a/usr/src/lib/cfgadm_plugins/sbd/sbd.xcl b/usr/src/lib/cfgadm_plugins/sbd/sbd.xcl index ea151d89ff..a5ba213ee2 100644 --- a/usr/src/lib/cfgadm_plugins/sbd/sbd.xcl +++ b/usr/src/lib/cfgadm_plugins/sbd/sbd.xcl @@ -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 2000-2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -124,7 +123,7 @@ msgid "rcm_request_suspend" msgid "rcm_notify_resume" msgid "rcm_notify_remove" msgid "ap_rcm_init\n" -msgid "/usr/lib/librcm.so" +msgid "/lib/librcm.so" msgid "Looking for librcm.so\n" msgid "librcm.so found\n" msgid "ap_rcm_fini\n" diff --git a/usr/src/lib/libdladm/Makefile b/usr/src/lib/libdladm/Makefile index ceae6a3ad5..630a7e2e19 100644 --- a/usr/src/lib/libdladm/Makefile +++ b/usr/src/lib/libdladm/Makefile @@ -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" @@ -28,7 +28,8 @@ include $(SRC)/lib/Makefile.lib HDRS = libdladm.h libdladm_impl.h libdllink.h libdlaggr.h \ - libdlwlan.h libdlwlan_impl.h libdlvnic.h + libdlwlan.h libdlwlan_impl.h libdlvnic.h libdlvlan.h \ + libdlmgmt.h HDRDIR = common SUBDIRS = $(MACH) @@ -37,7 +38,8 @@ $(BUILD64)SUBDIRS += $(MACH64) POFILE = libdladm.po MSGFILES = common/libdladm.c common/linkprop.c common/secobj.c \ common/libdllink.c common/libdlaggr.c \ - common/libdlwlan.c common/libdlvnic.c + common/libdlwlan.c common/libdlvnic.c \ + common/libdlvlan.c common/libdlmgmt.c XGETFLAGS = -a -x libdladm.xcl all := TARGET = all diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com index cbb912d3ed..4caeb08465 100644 --- a/usr/src/lib/libdladm/Makefile.com +++ b/usr/src/lib/libdladm/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" @@ -28,7 +28,7 @@ LIBRARY = libdladm.a VERS = .1 OBJECTS = libdladm.o secobj.o linkprop.o libdllink.o libdlaggr.o \ - libdlwlan.o libdlvnic.o + libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o include ../../Makefile.lib @@ -36,7 +36,7 @@ include ../../Makefile.lib include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -ldevinfo -ldlpi -lc -linetutil -lsocket -lscf +LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair SRCDIR = ../common $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c index ea440f76e3..58f15038bc 100644 --- a/usr/src/lib/libdladm/common/libdladm.c +++ b/usr/src/lib/libdladm/common/libdladm.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. */ @@ -28,13 +28,14 @@ #include <unistd.h> #include <stropts.h> #include <errno.h> +#include <ctype.h> #include <fcntl.h> #include <strings.h> #include <dirent.h> #include <sys/stat.h> -#include <libdladm.h> #include <libdladm_impl.h> #include <libintl.h> +#include <libdlpi.h> static char dladm_rootdir[MAXPATHLEN] = "/"; @@ -127,24 +128,23 @@ dladm_status2str(dladm_status_t status, char *buf) case DLADM_STATUS_KEYINVAL: s = "invalid key"; break; - case DLADM_STATUS_INVALIDID: - s = "invalid VNIC id"; - break; case DLADM_STATUS_INVALIDMACADDRLEN: s = "invalid MAC address length"; break; case DLADM_STATUS_INVALIDMACADDRTYPE: s = "invalid MAC address type"; break; - case DLADM_STATUS_AUTOIDNOTEMP: - s = "automatic VNIC ID assigment not supported with" - "persistant operations"; + case DLADM_STATUS_LINKBUSY: + s = "link busy"; + break; + case DLADM_STATUS_VIDINVAL: + s = "invalid VLAN identifier"; break; - case DLADM_STATUS_AUTOIDNOAVAILABLEID: - s = "no available VNIC ID for automatic assignment"; + case DLADM_STATUS_TRYAGAIN: + s = "try again later"; break; - case DLADM_STATUS_BUSY: - s = "device busy"; + case DLADM_STATUS_NONOTIF: + s = "link notification is not supported"; break; default: s = "<unknown error>"; @@ -175,12 +175,16 @@ dladm_errno2status(int err) return (DLADM_STATUS_NOMEM); case ENOTSUP: return (DLADM_STATUS_NOTSUP); + case ENETDOWN: + return (DLADM_STATUS_NONOTIF); case EACCES: return (DLADM_STATUS_DENIED); case EIO: return (DLADM_STATUS_IOERR); case EBUSY: - return (DLADM_STATUS_BUSY); + return (DLADM_STATUS_LINKBUSY); + case EAGAIN: + return (DLADM_STATUS_TRYAGAIN); default: return (DLADM_STATUS_FAILED); } @@ -190,15 +194,15 @@ dladm_errno2status(int err) * These are the uid and gid of the user 'dladm'. * The directory /etc/dladm and all files under it are owned by this user. */ -#define DLADM_DB_OWNER 15 -#define DLADM_DB_GROUP 3 -#define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH +#define DLADM_DB_OWNER 15 +#define DLADM_DB_GROUP 3 +#define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH static int i_dladm_lock_db(const char *lock_file, short type) { int lock_fd; - struct flock lock; + struct flock lock; if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, LOCK_DB_PERMS)) < 0) @@ -238,6 +242,135 @@ i_dladm_unlock_db(const char *lock_file, int fd) (void) unlink(lock_file); } +/* + * Given a link class, returns its class string. + */ +const char * +dladm_class2str(datalink_class_t class, char *buf) +{ + const char *s; + + switch (class) { + case DATALINK_CLASS_PHYS: + s = "phys"; + break; + case DATALINK_CLASS_VLAN: + s = "vlan"; + break; + case DATALINK_CLASS_AGGR: + s = "aggr"; + break; + case DATALINK_CLASS_VNIC: + s = "vnic"; + break; + default: + s = "unknown"; + break; + } + + (void) snprintf(buf, DLADM_STRSIZE, "%s", s); + return (buf); +} + +/* + * Given a physical link media type, returns its media type string. + */ +const char * +dladm_media2str(uint32_t media, char *buf) +{ + const char *s; + + switch (media) { + case DL_ETHER: + s = "Ethernet"; + break; + case DL_WIFI: + s = "WiFi"; + break; + case DL_IB: + s = "Infiniband"; + break; + case DL_IPV4: + s = "IPv4Tunnel"; + break; + case DL_IPV6: + s = "IPv6Tunnel"; + break; + case DL_CSMACD: + s = "CSMA/CD"; + break; + case DL_TPB: + s = "TokenBus"; + break; + case DL_TPR: + s = "TokenRing"; + break; + case DL_METRO: + s = "MetroNet"; + break; + case DL_HDLC: + s = "HDLC"; + break; + case DL_CHAR: + s = "SyncCharacter"; + break; + case DL_CTCA: + s = "CTCA"; + break; + case DL_FDDI: + s = "FDDI"; + break; + case DL_FC: + s = "FiberChannel"; + break; + case DL_ATM: + s = "ATM"; + break; + case DL_IPATM: + s = "ATM(ClassicIP)"; + break; + case DL_X25: + s = "X.25"; + break; + case DL_IPX25: + s = "X.25(ClassicIP)"; + break; + case DL_ISDN: + s = "ISDN"; + break; + case DL_HIPPI: + s = "HIPPI"; + break; + case DL_100VG: + s = "100BaseVGEthernet"; + break; + case DL_100VGTPR: + s = "100BaseVGTokenRing"; + break; + case DL_ETH_CSMA: + s = "IEEE802.3"; + break; + case DL_100BT: + s = "100BaseT"; + break; + case DL_FRAME: + s = "FrameRelay"; + break; + case DL_MPFRAME: + s = "MPFrameRelay"; + break; + case DL_ASYNC: + s = "AsyncCharacter"; + break; + default: + s = "--"; + break; + } + + (void) snprintf(buf, DLADM_STRSIZE, "%s", s); + return (buf); +} + dladm_status_t i_dladm_rw_db(const char *db_file, mode_t db_perms, dladm_status_t (*process_db)(void *, FILE *, FILE *), @@ -350,3 +483,30 @@ dladm_set_rootdir(const char *rootdir) (void) closedir(dp); return (DLADM_STATUS_OK); } + +boolean_t +dladm_valid_linkname(const char *link) +{ + size_t len = strlen(link); + const char *cp; + + if (len + 1 >= MAXLINKNAMELEN) + return (B_FALSE); + + /* + * The link name cannot start with a digit and must end with a digit. + */ + if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) + return (B_FALSE); + + /* + * The legal characters in a link name are: + * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). + */ + for (cp = link; *cp != '\0'; cp++) { + if ((isalnum(*cp) == 0) && (*cp != '_')) + return (B_FALSE); + } + + return (B_TRUE); +} diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h index 8ed30b4ebf..a7077f5900 100644 --- a/usr/src/lib/libdladm/common/libdladm.h +++ b/usr/src/lib/libdladm/common/libdladm.h @@ -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. */ @@ -28,6 +28,9 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/dls.h> +#include <sys/dlpi.h> + /* * This file includes structures, macros and common routines shared by all * data-link administration, and routines which do not directly administrate @@ -38,10 +41,36 @@ extern "C" { #endif +#define LINKID_STR_WIDTH 10 #define DLADM_STRSIZE 256 -#define DLADM_OPT_TEMP 0x00000001 -#define DLADM_OPT_CREATE 0x00000002 -#define DLADM_OPT_PERSIST 0x00000004 + +/* + * option flags taken by the libdladm functions + * + * - DLADM_OPT_ACTIVE: + * The function requests to bringup some configuration that only take + * effect on active system (not persistent). + * + * - DLADM_OPT_PERSIST: + * The function requests to persist some configuration. + * + * - DLADM_OPT_CREATE: + * Today, only used by dladm_set_secobj() - requests to create a secobj. + * + * - DLADM_OPT_FORCE: + * The function requests to execute a specific operation forcefully. + * + * - DLADM_OPT_PREFIX: + * The function requests to generate a link name using the specified prefix. + */ +#define DLADM_OPT_ACTIVE 0x00000001 +#define DLADM_OPT_PERSIST 0x00000002 +#define DLADM_OPT_CREATE 0x00000004 +#define DLADM_OPT_FORCE 0x00000008 +#define DLADM_OPT_PREFIX 0x00000010 + +#define DLADM_WALK_TERMINATE 0 +#define DLADM_WALK_CONTINUE -1 typedef enum { DLADM_STATUS_OK = 0, @@ -66,23 +95,28 @@ typedef enum { DLADM_STATUS_REPOSITORYINVAL, DLADM_STATUS_MACADDRINVAL, DLADM_STATUS_KEYINVAL, - DLADM_STATUS_INVALIDID, DLADM_STATUS_INVALIDMACADDRLEN, DLADM_STATUS_INVALIDMACADDRTYPE, - DLADM_STATUS_AUTOIDNOTEMP, - DLADM_STATUS_AUTOIDNOAVAILABLEID, - DLADM_STATUS_BUSY + DLADM_STATUS_LINKBUSY, + DLADM_STATUS_VIDINVAL, + DLADM_STATUS_NONOTIF, + DLADM_STATUS_TRYAGAIN } dladm_status_t; typedef enum { - DLADM_PROP_VAL_CURRENT = 1, - DLADM_PROP_VAL_DEFAULT, - DLADM_PROP_VAL_MODIFIABLE, - DLADM_PROP_VAL_PERSISTENT -} dladm_prop_type_t; + DLADM_TYPE_STR, + DLADM_TYPE_BOOLEAN, + DLADM_TYPE_UINT64 +} dladm_datatype_t; + +typedef int dladm_conf_t; +#define DLADM_INVALID_CONF 0 extern const char *dladm_status2str(dladm_status_t, char *); extern dladm_status_t dladm_set_rootdir(const char *); +extern const char *dladm_class2str(datalink_class_t, char *); +extern const char *dladm_media2str(uint32_t, char *); +extern boolean_t dladm_valid_linkname(const char *); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h index c949219a5b..f71495e5d9 100644 --- a/usr/src/lib/libdladm/common/libdladm_impl.h +++ b/usr/src/lib/libdladm/common/libdladm_impl.h @@ -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. */ @@ -38,12 +38,41 @@ extern "C" { #define MAXLINELEN 1024 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) +typedef struct val_desc { + char *vd_name; + uintptr_t vd_val; +} val_desc_t; + +#define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) + extern int i_dladm_ioctl(int, int, void *, int); extern dladm_status_t dladm_errno2status(int); -extern dladm_status_t i_dladm_rw_db(const char *, mode_t, +extern dladm_status_t i_dladm_rw_db(const char *, mode_t, dladm_status_t (*)(void *, FILE *, FILE *), void *, boolean_t); +/* + * Link attributes persisted by dlmgmtd. + */ +/* + * Set for VLANs only + */ +#define FVLANID "vid" /* uint64_t */ +#define FLINKOVER "linkover" /* uint64_t */ + +/* + * Set for AGGRs only + */ +#define FKEY "key" /* uint64_t */ +#define FNPORTS "nports" /* uint64_t */ +#define FPORTS "portnames" /* string */ +#define FPOLICY "policy" /* uint64_t */ +#define FFIXMACADDR "fix_macaddr" /* boolean_t */ +#define FMACADDR "macaddr" /* string */ +#define FFORCE "force" /* boolean_t */ +#define FLACPMODE "lacp_mode" /* uint64_t */ +#define FLACPTIMER "lacp_timer" /* uint64_t */ + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdlaggr.c b/usr/src/lib/libdladm/common/libdlaggr.c index 0c622fc8a2..75291d0d1d 100644 --- a/usr/src/lib/libdladm/common/libdlaggr.c +++ b/usr/src/lib/libdladm/common/libdlaggr.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,10 +34,13 @@ #include <stropts.h> #include <stdlib.h> #include <errno.h> +#include <assert.h> #include <strings.h> #include <libintl.h> #include <net/if_types.h> #include <net/if_dl.h> +#include <libdllink.h> +#include <libdlvlan.h> #include <libdlaggr.h> #include <libdladm_impl.h> @@ -46,78 +49,39 @@ * * This library is used by administration tools such as dladm(1M) to * configure link aggregations. - * - * Link aggregation configuration information is saved in a text - * file of the following format: - * - * <db-file> ::= <groups>* - * <group> ::= <key> <sep> <policy> <sep> <nports> <sep> <ports> <sep> - * <mac> <sep> <lacp-mode> <sep> <lacp-timer> - * <sep> ::= ' ' | '\t' - * <key> ::= <number> - * <nports> ::= <number> - * <ports> ::= <port> <m-port>* - * <m-port> ::= ',' <port> - * <port> ::= <devname> - * <devname> ::= <string> - * <port-num> ::= <number> - * <policy> ::= <pol-level> <m-pol>* - * <m-pol> ::= ',' <pol-level> - * <pol-level> ::= 'L2' | 'L3' | 'L4' - * <mac> ::= 'auto' | <mac-addr> - * <mac-addr> ::= <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> - * <lacp-mode> ::= 'off' | 'active' | 'passive' - * <lacp-timer> ::= 'short' | 'long' */ -#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL -#define DLADM_AGGR_DB "/etc/dladm/aggregation.conf" -#define DLADM_AGGR_DB_TMP "/etc/dladm/aggregation.conf.new" -#define DLADM_AGGR_DB_LOCK "/tmp/aggregation.conf.lock" - -#define DLADM_AGGR_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#define DLADM_AGGR_DB_OWNER 15 /* "dladm" UID */ -#define DLADM_AGGR_DB_GROUP 3 /* "sys" GID */ - -/* - * The largest configurable aggregation key. Because by default the key is - * used as the DLPI device PPA and default VLAN PPA's are calculated as - * ((1000 * vid) + PPA), the largest key can't be > 999. - */ -#define DLADM_AGGR_MAX_KEY 999 - -#define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) +#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL /* Limits on buffer size for LAIOC_INFO request */ #define MIN_INFO_SIZE (4*1024) #define MAX_INFO_SIZE (128*1024) -#define MAXPATHLEN 1024 - static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; +#define VALID_PORT_MAC(mac) \ + (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ + (!(mac)[0] & 0x01)) -/* configuration database entry */ -typedef struct dladm_aggr_grp_attr_db { - uint32_t lt_key; - uint32_t lt_policy; - uint32_t lt_nports; - dladm_aggr_port_attr_db_t *lt_ports; - boolean_t lt_mac_fixed; - uchar_t lt_mac[ETHERADDRL]; - aggr_lacp_mode_t lt_lacp_mode; - aggr_lacp_timer_t lt_lacp_timer; -} dladm_aggr_grp_attr_db_t; - -typedef struct dladm_aggr_up { - uint32_t lu_key; - boolean_t lu_found; - int lu_fd; -} dladm_aggr_up_t; - -typedef struct dladm_aggr_down { - uint32_t ld_key; - boolean_t ld_found; -} dladm_aggr_down_t; +#define PORT_DELIMITER '.' + +#define WRITE_PORT(portstr, portid, size) { \ + char pstr[LINKID_STR_WIDTH + 2]; \ + (void) snprintf(pstr, LINKID_STR_WIDTH + 2, "%d%c", \ + (portid), PORT_DELIMITER); \ + (void) strlcat((portstr), pstr, (size)); \ +} + +#define READ_PORT(portstr, portid, status) { \ + errno = 0; \ + (status) = DLADM_STATUS_OK; \ + (portid) = (int)strtol((portstr), &(portstr), 10); \ + if (errno != 0 || *(portstr) != PORT_DELIMITER) { \ + (status) = DLADM_STATUS_REPOSITORYINVAL; \ + } else { \ + /* Skip the delimiter. */ \ + (portstr)++; \ + } \ +} typedef struct dladm_aggr_modify_attr { uint32_t ld_policy; @@ -175,106 +139,93 @@ static dladm_aggr_port_state_t port_states[] = { #define NPORT_STATES \ (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) -typedef struct delete_db_state { - uint32_t ds_key; - boolean_t ds_found; -} delete_db_state_t; +static int +i_dladm_aggr_strioctl(int cmd, void *ptr, int ilen) +{ + int err, fd; -typedef struct modify_db_state { - uint32_t us_key; - uint32_t us_mask; - dladm_aggr_modify_attr_t *us_attr_new; - dladm_aggr_modify_attr_t *us_attr_old; - boolean_t us_found; -} modify_db_state_t; + if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) + return (-1); -typedef struct add_db_state { - dladm_aggr_grp_attr_db_t *as_attr; - boolean_t as_found; -} add_db_state_t; + err = i_dladm_ioctl(fd, cmd, ptr, ilen); + (void) close(fd); -static int i_dladm_aggr_fput_grp(FILE *, dladm_aggr_grp_attr_db_t *); + return (err); +} /* - * Open and lock the aggregation configuration file lock. The lock is - * acquired as a reader (F_RDLCK) or writer (F_WRLCK). + * Caller must free attr.lg_ports. The ptr pointer is advanced while convert + * the laioc_info_t to the dladm_aggr_grp_attr_t structure. */ static int -i_dladm_aggr_lock_db(short type) +i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) { - int lock_fd; - struct flock lock; - int errno_save; + laioc_info_group_t *grp; + laioc_info_port_t *port; + int i; + void *where = (*ptr); - if ((lock_fd = open(DLADM_AGGR_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC, - DLADM_AGGR_DB_PERMS)) < 0) - return (-1); + grp = (laioc_info_group_t *)where; - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_linkid = grp->lg_linkid; + attrp->lg_key = grp->lg_key; + attrp->lg_nports = grp->lg_nports; + attrp->lg_policy = grp->lg_policy; + attrp->lg_lacp_mode = grp->lg_lacp_mode; + attrp->lg_lacp_timer = grp->lg_lacp_timer; + attrp->lg_force = grp->lg_force; - if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { - errno_save = errno; - (void) close(lock_fd); - (void) unlink(DLADM_AGGR_DB_LOCK); - errno = errno_save; - return (-1); + bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); + attrp->lg_mac_fixed = grp->lg_mac_fixed; + + if ((attrp->lg_ports = malloc(grp->lg_nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + errno = ENOMEM; + goto fail; } - return (lock_fd); -} -/* - * Unlock and close the specified file. - */ -static void -i_dladm_aggr_unlock_db(int fd) -{ - struct flock lock; + where = (grp + 1); - if (fd < 0) - return; + /* + * Go through each port that is part of the group. + */ + for (i = 0; i < grp->lg_nports; i++) { + port = (laioc_info_port_t *)where; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_ports[i].lp_linkid = port->lp_linkid; + bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); + attrp->lg_ports[i].lp_state = port->lp_state; + attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; - (void) fcntl(fd, F_SETLKW, &lock); - (void) close(fd); - (void) unlink(DLADM_AGGR_DB_LOCK); + where = (port + 1); + } + *ptr = where; + return (0); +fail: + return (-1); } /* - * Walk through the groups defined on the system and for each group <grp>, - * invoke <fn>(<arg>, <grp>); - * Terminate the walk if at any time <fn> returns non-NULL value + * Get active configuration of a specific aggregation. + * Caller must free attrp->la_ports. */ -int -dladm_aggr_walk(int (*fn)(void *, dladm_aggr_grp_attr_t *), void *arg) +static dladm_status_t +i_dladm_aggr_info_active(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { laioc_info_t *ioc; - laioc_info_group_t *grp; - laioc_info_port_t *port; - dladm_aggr_grp_attr_t attr; - int rc, i, j, bufsize, fd; - char *where; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) == -1) - return (-1); + int rc, bufsize; + void *where; + dladm_status_t status = DLADM_STATUS_OK; bufsize = MIN_INFO_SIZE; ioc = (laioc_info_t *)calloc(1, bufsize); - if (ioc == NULL) { - (void) close(fd); - errno = ENOMEM; - return (-1); - } + if (ioc == NULL) + return (DLADM_STATUS_NOMEM); -tryagain: - rc = i_dladm_ioctl(fd, LAIOC_INFO, ioc, bufsize); + ioc->li_group_linkid = linkid; +tryagain: + rc = i_dladm_aggr_strioctl(LAIOC_INFO, ioc, bufsize); if (rc != 0) { if (errno == ENOSPC) { /* @@ -290,6 +241,7 @@ tryagain: } } } + status = dladm_errno2status(errno); goto bail; } @@ -297,257 +249,329 @@ tryagain: * Go through each group returned by the aggregation driver. */ where = (char *)(ioc + 1); - for (i = 0; i < ioc->li_ngroups; i++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - grp = (laioc_info_group_t *)where; - - attr.lg_key = grp->lg_key; - attr.lg_nports = grp->lg_nports; - attr.lg_policy = grp->lg_policy; - attr.lg_lacp_mode = grp->lg_lacp_mode; - attr.lg_lacp_timer = grp->lg_lacp_timer; - - bcopy(grp->lg_mac, attr.lg_mac, ETHERADDRL); - attr.lg_mac_fixed = grp->lg_mac_fixed; - - attr.lg_ports = malloc(grp->lg_nports * - sizeof (dladm_aggr_port_attr_t)); - if (attr.lg_ports == NULL) { - errno = ENOMEM; - goto bail; - } - - where = (char *)(grp + 1); - - /* - * Go through each port that is part of the group. - */ - for (j = 0; j < grp->lg_nports; j++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - port = (laioc_info_port_t *)where; - - bcopy(port->lp_devname, attr.lg_ports[j].lp_devname, - MAXNAMELEN + 1); - bcopy(port->lp_mac, attr.lg_ports[j].lp_mac, - ETHERADDRL); - attr.lg_ports[j].lp_state = port->lp_state; - attr.lg_ports[j].lp_lacp_state = port->lp_lacp_state; - - where = (char *)(port + 1); - } - - rc = fn(arg, &attr); - free(attr.lg_ports); - if (rc != 0) - goto bail; + if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { + status = dladm_errno2status(errno); + goto bail; } bail: free(ioc); - (void) close(fd); - return (rc); + return (status); } /* - * Parse one line of the link aggregation DB, and return the corresponding - * group. Memory for the ports associated with the aggregation may be - * allocated. It is the responsibility of the caller to free the lt_ports - * aggregation group attribute. - * - * Returns -1 on parsing failure, or 0 on success. + * Get configuration information of a specific aggregation. + * Caller must free attrp->la_ports. */ -static int -i_dladm_aggr_parse_db(char *line, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +i_dladm_aggr_info_persist(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { - char *token; - int i; - int value; - char *endp = NULL; - char *lasts = NULL; - - bzero(attr, sizeof (*attr)); + dladm_conf_t conf; + uint32_t nports, i; + char *portstr, *next; + dladm_status_t status; + uint64_t u64; + int size; + char macstr[ETHERADDRL * 3]; - /* key */ - if ((token = strtok_r(line, " \t", &lasts)) == NULL) - goto failed; + attrp->lg_linkid = linkid; + if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) + return (status); - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_key = (uint16_t)u64; - attr->lt_key = value; + status = dladm_get_conf_field(conf, FPOLICY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_policy = (uint32_t)u64; - /* policy */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL || - !dladm_aggr_str2policy(token, &attr->lt_policy)) - goto failed; + status = dladm_get_conf_field(conf, FFIXMACADDR, &attrp->lg_mac_fixed, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* number of ports */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL) - return (-1); + if (attrp->lg_mac_fixed) { + boolean_t fixed; - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + if ((status = dladm_get_conf_field(conf, FMACADDR, macstr, + sizeof (macstr))) != DLADM_STATUS_OK) { + goto done; + } + if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { + status = DLADM_STATUS_REPOSITORYINVAL; + goto done; + } + } - attr->lt_nports = value; + status = dladm_get_conf_field(conf, FFORCE, &attrp->lg_force, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* ports */ - if ((attr->lt_ports = malloc(attr->lt_nports * - sizeof (dladm_aggr_port_attr_db_t))) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FLACPMODE, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; - for (i = 0; i < attr->lt_nports; i++) { - char *where, *devname; + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; - /* port */ - if ((token = strtok_r(NULL, ", \t\n", &lasts)) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FNPORTS, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + nports = (uint32_t)u64; + attrp->lg_nports = nports; - /* - * device name: In a previous version of this file, a port - * number could be specified using <devname>/<portnum>. - * This syntax is unecessary and obsolete. - */ - if ((devname = strtok_r(token, "/", &where)) == NULL) - goto failed; - if (strlcpy(attr->lt_ports[i].lp_devname, devname, - MAXNAMELEN) >= MAXNAMELEN) - goto failed; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - /* unicast MAC address */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2macaddr(token, &attr->lt_mac_fixed, - attr->lt_mac)) - goto failed; + status = dladm_get_conf_field(conf, FPORTS, portstr, size); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto done; + } - /* LACP mode */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacpmode(token, &attr->lt_lacp_mode)) - attr->lt_lacp_mode = AGGR_LACP_OFF; + if ((attrp->lg_ports = malloc(nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + free(portstr); + status = DLADM_STATUS_NOMEM; + goto done; + } - /* LACP timer */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacptimer(token, &attr->lt_lacp_timer)) - attr->lt_lacp_timer = AGGR_LACP_TIMER_SHORT; + for (next = portstr, i = 0; i < nports; i++) { + READ_PORT(next, attrp->lg_ports[i].lp_linkid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + free(attrp->lg_ports); + goto done; + } + } + free(portstr); - return (0); +done: + dladm_destroy_conf(conf); + return (status); +} -failed: - free(attr->lt_ports); - attr->lt_ports = NULL; - return (-1); +dladm_status_t +dladm_aggr_info(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp, + uint32_t flags) +{ + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + if (flags == DLADM_OPT_ACTIVE) + return (i_dladm_aggr_info_active(linkid, attrp)); + else + return (i_dladm_aggr_info_persist(linkid, attrp)); } /* - * Walk through the groups defined in the DB and for each group <grp>, - * invoke <fn>(<arg>, <grp>); + * Add or remove one or more ports to/from an existing link aggregation. */ static dladm_status_t -i_dladm_aggr_walk_db(dladm_status_t (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) +i_dladm_aggr_add_rmv(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) { - FILE *fp; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file; - char db_file_buf[MAXPATHLEN]; - int lock_fd; + char *orig_portstr = NULL, *portstr = NULL; + laioc_add_rem_t *iocp; + laioc_port_t *ioc_ports; + uint32_t orig_nports, result_nports, len, i, j; + dladm_conf_t conf; + datalink_class_t class; dladm_status_t status = DLADM_STATUS_OK; + int size; + uint64_t u64; + uint32_t media; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; - } - - lock_fd = i_dladm_aggr_lock_db(F_RDLCK); + if (nports == 0) + return (DLADM_STATUS_BADARG); - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); + /* + * Sanity check - aggregations can only be created over Ethernet + * physical links. + */ + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) || (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } } - bzero(&attr, sizeof (attr)); + /* + * First, update the persistent configuration if requested. We only + * need to update the FPORTS and FNPORTS fields of this aggregation. + * Note that FPORTS is a list of port linkids separated by + * PORT_DELIMITER ('.'). + */ + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - while (fgets(line, MAXLINELEN, fp) != NULL) { - /* skip comments */ - if (BLANK_LINE(line)) - continue; + /* + * Get the original configuration of FNPORTS and FPORTS. + */ + status = dladm_get_conf_field(conf, FNPORTS, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto destroyconf; + orig_nports = (uint32_t)u64; - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto done; + /* + * At least one port needs to be in the aggregation. + */ + if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { + status = DLADM_STATUS_BADARG; + goto destroyconf; } - if ((status = fn(arg, &attr)) != DLADM_STATUS_OK) - goto done; + size = orig_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((orig_portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - free(attr.lt_ports); - attr.lt_ports = NULL; - } + status = dladm_get_conf_field(conf, FPORTS, orig_portstr, size); + if (status != DLADM_STATUS_OK) + goto destroyconf; -done: - free(attr.lt_ports); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); -} + result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : + orig_nports; -/* - * Send an add or remove command to the link aggregation driver. - */ -static dladm_status_t -i_dladm_aggr_add_rem_sys(dladm_aggr_grp_attr_db_t *attr, int cmd) -{ - int i, rc, fd, len; - laioc_add_rem_t *iocp; - laioc_port_t *ports; - dladm_status_t status = DLADM_STATUS_OK; + size = result_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); - iocp = malloc(len); - if (iocp == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } + /* + * get the new configuration and set to result_nports and + * portstr. + */ + if (cmd == LAIOC_ADD) { + (void) strlcpy(portstr, orig_portstr, size); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + } else { + char *next; + datalink_id_t portid; + uint32_t remove = 0; + + for (next = orig_portstr, j = 0; j < orig_nports; j++) { + /* + * Read the portids from the old configuration + * one by one. + */ + READ_PORT(next, portid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } + + /* + * See whether this port is in the removal + * list. If not, copy to the new config. + */ + for (i = 0; i < nports; i++) { + if (ports[i].lp_linkid == portid) + break; + } + if (i == nports) { + WRITE_PORT(portstr, portid, size); + } else { + remove++; + } + } + if (remove != nports) { + status = DLADM_STATUS_LINKINVAL; + free(portstr); + goto destroyconf; + } + result_nports -= nports; + } + + u64 = result_nports; + if ((status = dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } - iocp->la_key = attr->lt_key; - iocp->la_nports = attr->lt_nports; - ports = (laioc_port_t *)(iocp + 1); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + portstr); + free(portstr); + if (status != DLADM_STATUS_OK) + goto destroyconf; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - status = DLADM_STATUS_BADARG; - goto done; + /* + * Write the new configuration to the persistent repository. + */ + status = dladm_write_conf(conf); + +destroyconf: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) { + free(orig_portstr); + return (status); } } - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) { - status = dladm_errno2status(errno); + /* + * If the caller only requested to update the persistent + * configuration, we are done. + */ + if (!(flags & DLADM_OPT_ACTIVE)) goto done; - } - rc = i_dladm_ioctl(fd, cmd, iocp, len); - if (rc < 0) { - if (errno == EINVAL) - status = DLADM_STATUS_LINKINVAL; - else - status = dladm_errno2status(errno); + /* + * Update the active configuration. + */ + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); + if ((iocp = malloc(len)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); + iocp->la_linkid = linkid; + iocp->la_nports = nports; + if (cmd == LAIOC_ADD) + iocp->la_force = (flags & DLADM_OPT_FORCE); + + ioc_ports = (laioc_port_t *)(iocp + 1); + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; + + if (i_dladm_aggr_strioctl(cmd, iocp, len) < 0) + status = dladm_errno2status(errno); done: free(iocp); + + /* + * If the active configuration update fails, restore the old + * persistent configuration if we've changed that. + */ + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + u64 = orig_nports; + if ((dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && + (dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + orig_portstr) == DLADM_STATUS_OK)) { + (void) dladm_write_conf(conf); + } + (void) dladm_destroy_conf(conf); + } + } + free(orig_portstr); return (status); } @@ -555,14 +579,12 @@ done: * Send a modify command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, +i_dladm_aggr_modify_sys(datalink_id_t linkid, uint32_t mask, dladm_aggr_modify_attr_t *attr) { - int rc, fd; laioc_modify_t ioc; - dladm_status_t status = DLADM_STATUS_OK; - ioc.lu_key = key; + ioc.lu_linkid = linkid; ioc.lu_modify_mask = 0; if (mask & DLADM_AGGR_MODIFY_POLICY) @@ -580,68 +602,60 @@ i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, ioc.lu_lacp_mode = attr->ld_lacp_mode; ioc.lu_lacp_timer = attr->ld_lacp_timer; - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - rc = i_dladm_ioctl(fd, LAIOC_MODIFY, &ioc, sizeof (ioc)); - if (rc < 0) { + if (i_dladm_aggr_strioctl(LAIOC_MODIFY, &ioc, sizeof (ioc)) < 0) { if (errno == EINVAL) - status = DLADM_STATUS_MACADDRINVAL; + return (DLADM_STATUS_MACADDRINVAL); else - status = dladm_errno2status(errno); + return (dladm_errno2status(errno)); + } else { + return (DLADM_STATUS_OK); } - - (void) close(fd); - return (status); } /* * Send a create command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) +i_dladm_aggr_create_sys(datalink_id_t linkid, uint16_t key, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t policy, + boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) { int i, rc, len; - laioc_create_t *iocp; - laioc_port_t *ports; + laioc_create_t *iocp = NULL; + laioc_port_t *ioc_ports; dladm_status_t status = DLADM_STATUS_OK; - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); iocp = malloc(len); if (iocp == NULL) return (DLADM_STATUS_NOMEM); - iocp->lc_key = attr->lt_key; - iocp->lc_nports = attr->lt_nports; - iocp->lc_policy = attr->lt_policy; - iocp->lc_lacp_mode = attr->lt_lacp_mode; - iocp->lc_lacp_timer = attr->lt_lacp_timer; - - ports = (laioc_port_t *)(iocp + 1); + iocp->lc_key = key; + iocp->lc_linkid = linkid; + iocp->lc_nports = nports; + iocp->lc_policy = policy; + iocp->lc_lacp_mode = lacp_mode; + iocp->lc_lacp_timer = lacp_timer; + ioc_ports = (laioc_port_t *)(iocp + 1); + iocp->lc_force = force; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - free(iocp); - return (DLADM_STATUS_BADARG); - } - } + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; - if (attr->lt_mac_fixed && - ((bcmp(zero_mac, attr->lt_mac, ETHERADDRL) == 0) || - (attr->lt_mac[0] & 0x01))) { - free(iocp); - return (DLADM_STATUS_MACADDRINVAL); + if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; + goto done; } - bcopy(attr->lt_mac, iocp->lc_mac, ETHERADDRL); - iocp->lc_mac_fixed = attr->lt_mac_fixed; + bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); + iocp->lc_mac_fixed = mac_addr_fixed; - rc = i_dladm_ioctl(fd, LAIOC_CREATE, iocp, len); + rc = i_dladm_aggr_strioctl(LAIOC_CREATE, iocp, len); if (rc < 0) - status = DLADM_STATUS_LINKINVAL; + status = dladm_errno2status(errno); +done: free(iocp); return (status); } @@ -649,518 +663,109 @@ i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) /* * Invoked to bring up a link aggregation group. */ -static dladm_status_t -i_dladm_aggr_up(void *arg, dladm_aggr_grp_attr_db_t *attr) -{ - dladm_aggr_up_t *up = (dladm_aggr_up_t *)arg; - dladm_status_t status; - - if (up->lu_key != 0 && up->lu_key != attr->lt_key) - return (DLADM_STATUS_OK); - - up->lu_found = B_TRUE; - - status = i_dladm_aggr_create_sys(up->lu_fd, attr); - if (status != DLADM_STATUS_OK && up->lu_key != 0) - return (status); - - return (DLADM_STATUS_OK); -} - -/* - * Bring up a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_up(uint32_t key, const char *root) +static int +i_dladm_aggr_up(datalink_id_t linkid, void *arg) { - dladm_aggr_up_t up; + dladm_status_t *statusp = (dladm_status_t *)arg; + dladm_aggr_grp_attr_t attr; + dladm_aggr_port_attr_db_t *ports = NULL; + uint16_t key = 0; + int i, j; dladm_status_t status; - if ((up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - up.lu_key = key; - up.lu_found = B_FALSE; - - status = i_dladm_aggr_walk_db(i_dladm_aggr_up, &up, root); + status = dladm_aggr_info(linkid, &attr, DLADM_OPT_PERSIST); if (status != DLADM_STATUS_OK) { - (void) close(up.lu_fd); - return (status); + *statusp = status; + return (DLADM_WALK_CONTINUE); } - (void) close(up.lu_fd); - - /* - * only return error if user specified key and key was - * not found - */ - if (!up.lu_found && key != 0) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} -/* - * Send a delete command to the link aggregation driver. - */ -static int -i_dladm_aggr_delete_sys(int fd, dladm_aggr_grp_attr_t *attr) -{ - laioc_delete_t ioc; - - ioc.ld_key = attr->lg_key; - - return (i_dladm_ioctl(fd, LAIOC_DELETE, &ioc, sizeof (ioc))); -} - -/* - * Invoked to bring down a link aggregation group. - */ -static int -i_dladm_aggr_down(void *arg, dladm_aggr_grp_attr_t *attr) -{ - dladm_aggr_down_t *down = (dladm_aggr_down_t *)arg; - int fd, errno_save; - - if (down->ld_key != 0 && down->ld_key != attr->lg_key) - return (0); - down->ld_found = B_TRUE; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (-1); + if (attr.lg_key <= AGGR_MAX_KEY) + key = attr.lg_key; - if (i_dladm_aggr_delete_sys(fd, attr) < 0 && down->ld_key != 0) { - errno_save = errno; - (void) close(fd); - errno = errno_save; - return (-1); + ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); + if (ports == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); - return (0); -} - -/* - * Bring down a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_down(uint32_t key) -{ - dladm_aggr_down_t down; - - down.ld_key = key; - down.ld_found = B_FALSE; - - if (dladm_aggr_walk(i_dladm_aggr_down, &down) < 0) - return (dladm_errno2status(errno)); - /* - * only return error if user specified key and key was - * not found + * Validate (and purge) each physical link associated with this + * aggregation, if the specific hardware has been removed during + * the system shutdown. */ - if (!down.ld_found && key != 0) - return (DLADM_STATUS_NOTFOUND); + for (i = 0, j = 0; i < attr.lg_nports; i++) { + datalink_id_t portid = attr.lg_ports[i].lp_linkid; + uint32_t flags; + dladm_status_t s; - return (DLADM_STATUS_OK); -} - -/* - * For each group <grp> found in the DB, invokes <fn>(<grp>, <arg>). - * - * The following values can be returned by <fn>(): - * - * -1: an error occured. This will cause the walk to be terminated, - * and the original DB file to be preserved. - * - * 0: success and write. The walker will write the contents of - * the attribute passed as argument to <fn>(), and continue walking - * the entries found in the DB. - * - * 1: skip. The walker should not write the contents of the current - * group attributes to the new DB, but should continue walking - * the entries found in the DB. - */ -static dladm_status_t -i_dladm_aggr_walk_rw_db(int (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) -{ - FILE *fp, *nfp; - int nfd, fn_rc, lock_fd; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file, *tmp_db_file; - char db_file_buf[MAXPATHLEN]; - char tmp_db_file_buf[MAXPATHLEN]; - dladm_status_t status; - - if (root == NULL) { - db_file = DLADM_AGGR_DB; - tmp_db_file = DLADM_AGGR_DB_TMP; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB_TMP); - db_file = db_file_buf; - tmp_db_file = tmp_db_file_buf; - } - - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); - - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC, - DLADM_AGGR_DB_PERMS)) == -1) { - status = dladm_errno2status(errno); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfp = fdopen(nfd, "w")) == NULL) { - status = dladm_errno2status(errno); - (void) close(nfd); - (void) fclose(fp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - attr.lt_ports = NULL; - - while (fgets(line, MAXLINELEN, fp) != NULL) { - - /* skip comments */ - if (BLANK_LINE(line)) { - if (fputs(line, nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } + s = dladm_datalink_id2info(portid, &flags, NULL, NULL, NULL, 0); + if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) continue; - } - - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto failed; - } - - fn_rc = fn(arg, &attr); - - switch (fn_rc) { - case -1: - /* failure, stop walking */ - status = dladm_errno2status(errno); - goto failed; - case 0: - /* - * Success, write group attributes, which could - * have been modified by fn(). - */ - if (i_dladm_aggr_fput_grp(nfp, &attr) != 0) { - status = dladm_errno2status(errno); - goto failed; - } - break; - case 1: - /* skip current group */ - break; - } - - free(attr.lt_ports); - attr.lt_ports = NULL; - } - - if (getuid() == 0 || geteuid() == 0) { - if (fchmod(nfd, DLADM_AGGR_DB_PERMS) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - - if (fchown(nfd, DLADM_AGGR_DB_OWNER, - DLADM_AGGR_DB_GROUP) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - } - - if (fflush(nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } - - (void) fclose(fp); - (void) fclose(nfp); - - if (rename(tmp_db_file, db_file) == -1) { - status = dladm_errno2status(errno); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - i_dladm_aggr_unlock_db(lock_fd); - return (DLADM_STATUS_OK); - -failed: - free(attr.lt_ports); - (void) fclose(fp); - (void) fclose(nfp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - - return (status); -} - -/* - * Remove an entry from the DB. - */ -static int -i_dladm_aggr_del_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - delete_db_state_t *state = arg; - - if (grp->lt_key != state->ds_key) - return (0); - - state->ds_found = B_TRUE; - - /* don't save matching group */ - return (1); -} - -static dladm_status_t -i_dladm_aggr_del_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - delete_db_state_t state; - dladm_status_t status; - - state.ds_key = attr->lt_key; - state.ds_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_del_db_fn, &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.ds_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Modify the properties of an existing group in the DB. - */ -static int -i_dladm_aggr_modify_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - modify_db_state_t *state = arg; - dladm_aggr_modify_attr_t *new_attr = state->us_attr_new; - dladm_aggr_modify_attr_t *old_attr = state->us_attr_old; - - if (grp->lt_key != state->us_key) - return (0); - - state->us_found = B_TRUE; - - if (state->us_mask & DLADM_AGGR_MODIFY_POLICY) { - if (old_attr != NULL) - old_attr->ld_policy = grp->lt_policy; - grp->lt_policy = new_attr->ld_policy; + ports[j++].lp_linkid = portid; } - if (state->us_mask & DLADM_AGGR_MODIFY_MAC) { - if (old_attr != NULL) { - old_attr->ld_mac_fixed = grp->lt_mac_fixed; - bcopy(grp->lt_mac, old_attr->ld_mac, ETHERADDRL); - } - grp->lt_mac_fixed = new_attr->ld_mac_fixed; - bcopy(new_attr->ld_mac, grp->lt_mac, ETHERADDRL); + if (j == 0) { + /* + * All of the physical links are removed. + */ + status = DLADM_STATUS_BADARG; + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_MODE) { - if (old_attr != NULL) - old_attr->ld_lacp_mode = grp->lt_lacp_mode; - grp->lt_lacp_mode = new_attr->ld_lacp_mode; + /* + * Create active aggregation. + */ + if ((status = i_dladm_aggr_create_sys(linkid, + key, j, ports, attr.lg_policy, attr.lg_mac_fixed, + (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, + attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_TIMER) { - if (old_attr != NULL) - old_attr->ld_lacp_timer = grp->lt_lacp_timer; - grp->lt_lacp_timer = new_attr->ld_lacp_timer; + if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { + laioc_delete_t ioc; + ioc.ld_linkid = linkid; + (void) i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, sizeof (ioc)); + goto done; } - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_modify_db(uint32_t key, uint32_t mask, - dladm_aggr_modify_attr_t *new, dladm_aggr_modify_attr_t *old, - const char *root) -{ - modify_db_state_t state; - dladm_status_t status; - - state.us_key = key; - state.us_mask = mask; - state.us_attr_new = new; - state.us_attr_old = old; - state.us_found = B_FALSE; - - if ((status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_modify_db_fn, - &state, root)) != DLADM_STATUS_OK) { - return (status); - } + /* + * Reset the active linkprop of this specific link. + */ + (void) dladm_init_linkprop(linkid); - if (!state.us_found) - return (DLADM_STATUS_NOTFOUND); +done: + free(attr.lg_ports); + free(ports); - return (DLADM_STATUS_OK); + *statusp = status; + return (DLADM_WALK_CONTINUE); } /* - * Add ports to an existing group in the DB. + * Bring up one aggregation, or all persistent aggregations. In the latter + * case, the walk may terminate early if bringup of an aggregation fails. */ -static int -i_dladm_aggr_add_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - add_db_state_t *state = arg; - dladm_aggr_grp_attr_db_t *attr = state->as_attr; - void *ports; - int i, j; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->as_found = B_TRUE; - - /* are any of the ports to be added already members of the group? */ - for (i = 0; i < grp->lt_nports; i++) { - for (j = 0; j < attr->lt_nports; j++) { - if (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0) { - errno = EEXIST; - return (-1); - } - } - } - - /* add groups specified by attr to grp */ - ports = realloc(grp->lt_ports, (grp->lt_nports + - attr->lt_nports) * sizeof (dladm_aggr_port_attr_db_t)); - if (ports == NULL) - return (-1); - grp->lt_ports = ports; - - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(grp->lt_ports[grp->lt_nports + i].lp_devname, - attr->lt_ports[i].lp_devname, MAXNAMELEN + 1) >= - MAXNAMELEN + 1) - return (-1); - } - - grp->lt_nports += attr->lt_nports; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_add_db(dladm_aggr_grp_attr_db_t *attr, const char *root) +dladm_status_t +dladm_aggr_up(datalink_id_t linkid) { - add_db_state_t state; dladm_status_t status; - state.as_attr = attr; - state.as_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_add_db_fn, &state, root); - if (status != DLADM_STATUS_OK) + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_aggr_up, &status, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_aggr_up(linkid, &status); return (status); - - if (!state.as_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Remove ports from an existing group in the DB. - */ - -typedef struct remove_db_state { - dladm_aggr_grp_attr_db_t *rs_attr; - boolean_t rs_found; -} remove_db_state_t; - -static int -i_dladm_aggr_remove_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - remove_db_state_t *state = (remove_db_state_t *)arg; - dladm_aggr_grp_attr_db_t *attr = state->rs_attr; - int i, j, k, nremoved; - boolean_t match; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->rs_found = B_TRUE; - - /* remove the ports specified by attr from the group */ - nremoved = 0; - k = 0; - for (i = 0; i < grp->lt_nports; i++) { - match = B_FALSE; - for (j = 0; j < attr->lt_nports && !match; j++) { - match = (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0); - } - if (match) - nremoved++; - else - grp->lt_ports[k++] = grp->lt_ports[i]; - } - - if (nremoved != attr->lt_nports) { - errno = ENOENT; - return (-1); } - - grp->lt_nports -= nremoved; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_remove_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - remove_db_state_t state; - dladm_status_t status; - - state.rs_attr = attr; - state.rs_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_remove_db_fn, - &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.rs_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); } /* * Given a policy string, return a policy mask. Returns B_TRUE on - * success, or B_FALSE if an error occured during parsing. + * success, or B_FALSE if an error occurred during parsing. */ boolean_t dladm_aggr_str2policy(const char *str, uint32_t *policy) @@ -1199,6 +804,9 @@ dladm_aggr_policy2str(uint32_t policy, char *str) int i, npolicies = 0; policy_t *pol; + if (str == NULL) + return (NULL); + str[0] = '\0'; for (i = 0; i < NPOLICIES; i++) { @@ -1206,8 +814,8 @@ dladm_aggr_policy2str(uint32_t policy, char *str) if ((policy & pol->policy) != 0) { npolicies++; if (npolicies > 1) - (void) strcat(str, ","); - (void) strcat(str, pol->pol_name); + (void) strlcat(str, ",", DLADM_STRSIZE); + (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); } } @@ -1257,7 +865,7 @@ dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) * Returns a string containing a printable representation of a MAC address. */ const char * -dladm_aggr_macaddr2str(unsigned char *mac, char *buf) +dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) { static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; @@ -1265,9 +873,11 @@ dladm_aggr_macaddr2str(unsigned char *mac, char *buf) return (NULL); if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) - return (gettext("<unknown>")); + (void) strlcpy(buf, "unknown", DLADM_STRSIZE); else return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); + + return (buf); } /* @@ -1302,6 +912,9 @@ dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) int i; dladm_aggr_lacpmode_t *mode; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_MODES; i++) { mode = &lacp_modes[i]; if (mode->mode_id == mode_id) { @@ -1347,6 +960,9 @@ dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) int i; dladm_aggr_lacptimer_t *timer; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_TIMERS; i++) { timer = &lacp_timers[i]; if (timer->lt_id == timer_id) { @@ -1364,7 +980,10 @@ const char * dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) { int i; - dladm_aggr_port_state_t *state; + dladm_aggr_port_state_t *state; + + if (buf == NULL) + return (NULL); for (i = 0; i < NPORT_STATES; i++) { state = &port_states[i]; @@ -1379,123 +998,94 @@ dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) return (buf); } -#define FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1); - -/* - * Write the attribute of a group to the specified file. Returns 0 on - * success, -1 on failure. - */ -static int -i_dladm_aggr_fput_grp(FILE *fp, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +dladm_aggr_persist_aggr_conf(const char *link, datalink_id_t linkid, + uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, + uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, + boolean_t force) { - int i; - char addr_str[ETHERADDRL * 3]; - char buf[DLADM_STRSIZE]; - - /* key, policy */ - FPRINTF_ERR(fprintf(fp, "%d\t%s\t", attr->lt_key, - dladm_aggr_policy2str(attr->lt_policy, buf))); - - /* number of ports, ports */ - FPRINTF_ERR(fprintf(fp, "%d\t", attr->lt_nports)); - for (i = 0; i < attr->lt_nports; i++) { - if (i > 0) - FPRINTF_ERR(fprintf(fp, ",")); - FPRINTF_ERR(fprintf(fp, "%s", attr->lt_ports[i].lp_devname)); - } - FPRINTF_ERR(fprintf(fp, "\t")); + dladm_conf_t conf = DLADM_INVALID_CONF; + char *portstr = NULL; + char macstr[ETHERADDRL * 3]; + dladm_status_t status; + int i, size; + uint64_t u64; - /* MAC address */ - if (!attr->lt_mac_fixed) { - FPRINTF_ERR(fprintf(fp, "auto")); - } else { - FPRINTF_ERR(fprintf(fp, "%s", - dladm_aggr_macaddr2str(attr->lt_mac, addr_str))); + if ((status = dladm_create_conf(link, linkid, DATALINK_CLASS_AGGR, + DL_ETHER, &conf)) != DLADM_STATUS_OK) { + return (status); } - FPRINTF_ERR(fprintf(fp, "\t")); - - FPRINTF_ERR(fprintf(fp, "%s\t", - dladm_aggr_lacpmode2str(attr->lt_lacp_mode, buf))); - - FPRINTF_ERR(fprintf(fp, "%s\n", - dladm_aggr_lacptimer2str(attr->lt_lacp_timer, buf))); - return (0); -} + u64 = key; + status = dladm_set_conf_field(conf, FKEY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; -static dladm_status_t -i_dladm_aggr_create_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - FILE *fp; - char line[MAXLINELEN]; - uint32_t key; - int lock_fd; - char *db_file; - char db_file_buf[MAXPATHLEN]; - char *endp = NULL; - dladm_status_t status; + u64 = nports; + status = dladm_set_conf_field(conf, FNPORTS, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, portstr); + free(portstr); - if ((fp = fopen(db_file, "r+")) == NULL && - (fp = fopen(db_file, "w")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - /* look for existing group with same key */ - while (fgets(line, MAXLINELEN, fp) != NULL) { - char *holder, *lasts; + if (status != DLADM_STATUS_OK) + goto done; - /* skip comments */ - if (BLANK_LINE(line)) - continue; + u64 = policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - /* ignore corrupted lines */ - holder = strtok_r(line, " \t", &lasts); - if (holder == NULL) - continue; + status = dladm_set_conf_field(conf, FFIXMACADDR, DLADM_TYPE_BOOLEAN, + &mac_addr_fixed); + if (status != DLADM_STATUS_OK) + goto done; - /* port number */ - errno = 0; - key = (int)strtol(holder, &endp, 10); - if (errno != 0 || *endp != '\0') { - status = DLADM_STATUS_REPOSITORYINVAL; + if (mac_addr_fixed) { + if (!VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; goto done; } - if (key == attr->lt_key) { - /* group with key already exists */ - status = DLADM_STATUS_EXIST; + (void) dladm_aggr_macaddr2str(mac_addr, macstr); + status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, + macstr); + if (status != DLADM_STATUS_OK) goto done; - } } - /* - * If we get here, we've verified that no existing group with - * the same key already exists. It's now time to add the - * new group to the DB. - */ - if (i_dladm_aggr_fput_grp(fp, attr) != 0) { - status = dladm_errno2status(errno); + status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); + if (status != DLADM_STATUS_OK) goto done; - } - status = DLADM_STATUS_OK; + u64 = lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + u64 = lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Commit the link aggregation configuration. + */ + status = dladm_write_conf(conf); done: - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); + dladm_destroy_conf(conf); return (status); } @@ -1504,60 +1094,168 @@ done: * file and bring it up. */ dladm_status_t -dladm_aggr_create(uint32_t key, uint32_t nports, +dladm_aggr_create(const char *name, uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, - uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, - boolean_t tempop, const char *root) + const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + uint32_t media; + uint32_t i; + datalink_class_t class; dladm_status_t status; + boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; - if (key == 0 || key > DLADM_AGGR_MAX_KEY) + if (key != 0 && key > AGGR_MAX_KEY) return (DLADM_STATUS_KEYINVAL); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - attr.lt_policy = policy; - attr.lt_mac_fixed = mac_addr_fixed; - if (attr.lt_mac_fixed) - bcopy(mac_addr, attr.lt_mac, ETHERADDRL); - else - bzero(attr.lt_mac, ETHERADDRL); - attr.lt_lacp_mode = lacp_mode; - attr.lt_lacp_timer = lacp_timer; + if (nports == 0) + return (DLADM_STATUS_BADARG); - /* add the link aggregation group to the DB */ - if (!tempop) { - status = i_dladm_aggr_create_db(&attr, root); + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) && (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } + } + + flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); + if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_AGGR, + DL_ETHER, flags, &linkid)) != DLADM_STATUS_OK) { + goto fail; + } + + if ((flags & DLADM_OPT_PERSIST) && + (status = dladm_aggr_persist_aggr_conf(name, linkid, key, nports, + ports, policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, + force)) != DLADM_STATUS_OK) { + goto fail; + } + + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_create_sys(linkid, key, nports, ports, policy, + mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); + + if (status != DLADM_STATUS_OK) { + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(linkid); + goto fail; + } + + return (DLADM_STATUS_OK); + +fail: + if (linkid != DATALINK_INVALID_LINKID) + (void) dladm_destroy_datalink_id(linkid, flags); + + return (status); +} + +static dladm_status_t +i_dladm_aggr_get_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + status = dladm_get_conf_field(conf, FPOLICY, &u64, + sizeof (u64)); if (status != DLADM_STATUS_OK) return (status); - } else { - dladm_aggr_up_t up; + attrp->ld_policy = (uint32_t)u64; + } - up.lu_key = key; - up.lu_found = B_FALSE; - up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR); - if (up.lu_fd < 0) - return (dladm_errno2status(errno)); + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_get_conf_field(conf, FFIXMACADDR, + &attrp->ld_mac_fixed, sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + return (status); - status = i_dladm_aggr_up((void *)&up, &attr); - (void) close(up.lu_fd); - return (status); + if (attrp->ld_mac_fixed) { + boolean_t fixed; + + status = dladm_get_conf_field(conf, FMACADDR, + macstr, sizeof (macstr)); + if (status != DLADM_STATUS_OK) + return (status); + + if (!dladm_aggr_str2macaddr(macstr, &fixed, + attrp->ld_mac)) { + return (DLADM_STATUS_REPOSITORYINVAL); + } + } } - /* bring up the link aggregation group */ - status = dladm_aggr_up(key, root); - /* - * If the operation fails because the aggregation already exists, - * then only update the persistent configuration repository and - * return success. - */ - if (status == DLADM_STATUS_EXIST) - status = DLADM_STATUS_OK; + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + status = dladm_get_conf_field(conf, FLACPMODE, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; + } + + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; + } + + return (status); +} + +static dladm_status_t +i_dladm_aggr_set_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + u64 = attrp->ld_policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_set_conf_field(conf, FFIXMACADDR, + DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); + if (status != DLADM_STATUS_OK) + return (status); + + if (attrp->ld_mac_fixed) { + (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); + status = dladm_set_conf_field(conf, FMACADDR, + DLADM_TYPE_STR, macstr); + if (status != DLADM_STATUS_OK) + return (status); + } + } + + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + u64 = attrp->ld_lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_del_db(&attr, root); + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + u64 = attrp->ld_lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } return (status); } @@ -1567,146 +1265,211 @@ dladm_aggr_create(uint32_t key, uint32_t nports, * the configuration file and pass the changes to the kernel. */ dladm_status_t -dladm_aggr_modify(uint32_t key, uint32_t modify_mask, uint32_t policy, - boolean_t mac_fixed, uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, - aggr_lacp_timer_t lacp_timer, boolean_t tempop, const char *root) +dladm_aggr_modify(datalink_id_t linkid, uint32_t modify_mask, uint32_t policy, + boolean_t mac_fixed, const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { dladm_aggr_modify_attr_t new_attr, old_attr; + dladm_conf_t conf; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + new_attr.ld_policy = policy; + new_attr.ld_mac_fixed = mac_fixed; + new_attr.ld_lacp_mode = lacp_mode; + new_attr.ld_lacp_timer = lacp_timer; + bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - if (modify_mask & DLADM_AGGR_MODIFY_POLICY) - new_attr.ld_policy = policy; + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - if (modify_mask & DLADM_AGGR_MODIFY_MAC) { - new_attr.ld_mac_fixed = mac_fixed; - bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - } + if ((status = i_dladm_aggr_get_aggr_attr(conf, modify_mask, + &old_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) - new_attr.ld_lacp_mode = lacp_mode; + if ((status = i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &new_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) - new_attr.ld_lacp_timer = lacp_timer; + status = dladm_write_conf(conf); - /* update the DB */ - if (!tempop && ((status = i_dladm_aggr_modify_db(key, modify_mask, - &new_attr, &old_attr, root)) != DLADM_STATUS_OK)) { - return (status); +done: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) + return (status); } - status = i_dladm_aggr_modify_sys(key, modify_mask, &new_attr); - if (status != DLADM_STATUS_OK && !tempop) { - (void) i_dladm_aggr_modify_db(key, modify_mask, &old_attr, - NULL, root); + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_modify_sys(linkid, modify_mask, &new_attr); + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + if (i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &old_attr) == DLADM_STATUS_OK) { + (void) dladm_write_conf(conf); + } + dladm_destroy_conf(conf); + } } return (status); } +typedef struct aggr_held_arg_s { + datalink_id_t aggrid; + boolean_t isheld; +} aggr_held_arg_t; + +static int +i_dladm_aggr_is_held(datalink_id_t linkid, void *arg) +{ + aggr_held_arg_t *aggr_held_arg = arg; + dladm_vlan_attr_t dva; + + if (dladm_vlan_info(linkid, &dva, DLADM_OPT_PERSIST) != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (dva.dv_linkid == aggr_held_arg->aggrid) { + /* + * This VLAN is created over the given aggregation. + */ + aggr_held_arg->isheld = B_TRUE; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); +} + /* - * Delete a previously created link aggregation group. + * Delete a previously created link aggregation group. Either the name "aggr" + * or the "key" is specified. */ dladm_status_t -dladm_aggr_delete(uint32_t key, boolean_t tempop, const char *root) +dladm_aggr_delete(datalink_id_t linkid, uint32_t flags) { - dladm_aggr_grp_attr_db_t db_attr; + laioc_delete_t ioc; + datalink_class_t class; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - if (tempop) { - dladm_aggr_down_t down; - dladm_aggr_grp_attr_t sys_attr; + if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != + DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { + return (DLADM_STATUS_BADARG); + } - down.ld_key = key; - down.ld_found = B_FALSE; - sys_attr.lg_key = key; - if (i_dladm_aggr_down((void *)&down, &sys_attr) < 0) - return (dladm_errno2status(errno)); - else - return (DLADM_STATUS_OK); - } else { - status = dladm_aggr_down(key); + if (flags & DLADM_OPT_ACTIVE) { + ioc.ld_linkid = linkid; + if ((i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, + sizeof (ioc)) < 0) && + ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { + status = dladm_errno2status(errno); + return (status); + } /* - * Only continue to delete the configuration repository - * either if we successfully delete the active aggregation - * or if the aggregation is not found. + * Delete ACTIVE linkprop first. */ - if (status != DLADM_STATUS_OK && - status != DLADM_STATUS_NOTFOUND) { - return (status); - } + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); } - if (tempop) - return (DLADM_STATUS_OK); + /* + * If we reach here, it means that the active aggregation has already + * been deleted, and there is no active VLANs holding this aggregation. + * Now we see whether there is any persistent VLANs holding this + * aggregation. If so, we fail the operation. + */ + if (flags & DLADM_OPT_PERSIST) { + aggr_held_arg_t arg; + + arg.aggrid = linkid; + arg.isheld = B_FALSE; + + (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, + &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + if (arg.isheld) + return (DLADM_STATUS_LINKBUSY); + + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid); + } - db_attr.lt_key = key; - return (i_dladm_aggr_del_db(&db_attr, root)); + return (DLADM_STATUS_OK); } /* * Add one or more ports to an existing link aggregation. */ dladm_status_t -dladm_aggr_add(uint32_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, - boolean_t tempop, const char *root) +dladm_aggr_add(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; - dladm_status_t status; - - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - - if (!tempop && - ((status = i_dladm_aggr_add_db(&attr, root)) != DLADM_STATUS_OK)) { - return (status); - } - - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_ADD); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_remove_db(&attr, root); - - return (status); + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, LAIOC_ADD)); } /* * Remove one or more ports from an existing link aggregation. */ dladm_status_t -dladm_aggr_remove(uint32_t key, uint32_t nports, - dladm_aggr_port_attr_db_t *ports, boolean_t tempop, const char *root) +dladm_aggr_remove(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) +{ + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, + LAIOC_REMOVE)); +} + +typedef struct i_walk_key_state_s { + uint16_t key; + datalink_id_t linkid; + boolean_t found; +} i_walk_key_state_t; + +static int +i_dladm_walk_key2linkid(datalink_id_t linkid, void *arg) { - dladm_aggr_grp_attr_db_t attr; + dladm_conf_t conf; + uint16_t key; dladm_status_t status; + i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; + uint64_t u64; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + if (dladm_read_conf(linkid, &conf) != 0) + return (DLADM_WALK_CONTINUE); - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + key = (uint16_t)u64; + dladm_destroy_conf(conf); - if (!tempop && - ((status = i_dladm_aggr_remove_db(&attr, root)) != - DLADM_STATUS_OK)) { - return (status); + if ((status == DLADM_STATUS_OK) && (key == statep->key)) { + statep->found = B_TRUE; + statep->linkid = linkid; + return (DLADM_WALK_TERMINATE); } - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_REMOVE); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_add_db(&attr, root); + return (DLADM_WALK_CONTINUE); +} - return (status); +dladm_status_t +dladm_key2linkid(uint16_t key, datalink_id_t *linkidp, uint32_t flags) +{ + i_walk_key_state_t state; + + if (key > AGGR_MAX_KEY) + return (DLADM_STATUS_NOTFOUND); + + state.found = B_FALSE; + state.key = key; + + (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, &state, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); + if (state.found == B_TRUE) { + *linkidp = state.linkid; + return (DLADM_STATUS_OK); + } else { + return (DLADM_STATUS_NOTFOUND); + } } diff --git a/usr/src/lib/libdladm/common/libdlaggr.h b/usr/src/lib/libdladm/common/libdlaggr.h index 40b8c72eeb..1b5df523c4 100644 --- a/usr/src/lib/libdladm/common/libdlaggr.h +++ b/usr/src/lib/libdladm/common/libdlaggr.h @@ -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. */ @@ -44,67 +44,65 @@ extern "C" { /* * Modification flags sent with the LAIOC_MODIFY ioctl */ -#define DLADM_AGGR_MODIFY_POLICY 0x01 -#define DLADM_AGGR_MODIFY_MAC 0x02 -#define DLADM_AGGR_MODIFY_LACP_MODE 0x04 -#define DLADM_AGGR_MODIFY_LACP_TIMER 0x08 +#define DLADM_AGGR_MODIFY_POLICY 0x01 +#define DLADM_AGGR_MODIFY_MAC 0x02 +#define DLADM_AGGR_MODIFY_LACP_MODE 0x04 +#define DLADM_AGGR_MODIFY_LACP_TIMER 0x08 typedef struct dladm_aggr_port_attr_db { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; } dladm_aggr_port_attr_db_t; typedef struct dladm_aggr_port_attr { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; uchar_t lp_mac[ETHERADDRL]; aggr_port_state_t lp_state; aggr_lacp_state_t lp_lacp_state; } dladm_aggr_port_attr_t; typedef struct dladm_aggr_grp_attr { + datalink_id_t lg_linkid; uint32_t lg_key; uint32_t lg_nports; dladm_aggr_port_attr_t *lg_ports; uint32_t lg_policy; uchar_t lg_mac[ETHERADDRL]; boolean_t lg_mac_fixed; + boolean_t lg_force; aggr_lacp_mode_t lg_lacp_mode; aggr_lacp_timer_t lg_lacp_timer; } dladm_aggr_grp_attr_t; -extern dladm_status_t dladm_aggr_create(uint32_t, uint32_t, +extern dladm_status_t dladm_aggr_create(const char *, uint16_t, uint32_t, dladm_aggr_port_attr_db_t *, uint32_t, boolean_t, - uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t, - boolean_t, const char *); -extern dladm_status_t dladm_aggr_delete(uint32_t, boolean_t, const char *); -extern dladm_status_t dladm_aggr_add(uint32_t, uint32_t, - dladm_aggr_port_attr_db_t *, boolean_t, - const char *); -extern dladm_status_t dladm_aggr_remove(uint32_t, uint32_t, - dladm_aggr_port_attr_db_t *, boolean_t, - const char *); -extern dladm_status_t dladm_aggr_modify(uint32_t, uint32_t, uint32_t, - boolean_t, uchar_t *, aggr_lacp_mode_t, - aggr_lacp_timer_t, boolean_t, const char *); -extern dladm_status_t dladm_aggr_up(uint32_t, const char *); -extern dladm_status_t dladm_aggr_down(uint32_t); + const uchar_t *, aggr_lacp_mode_t, + aggr_lacp_timer_t, uint32_t); +extern dladm_status_t dladm_aggr_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_aggr_add(datalink_id_t, uint32_t, + dladm_aggr_port_attr_db_t *, uint32_t); +extern dladm_status_t dladm_aggr_remove(datalink_id_t, uint32_t, + dladm_aggr_port_attr_db_t *, uint32_t); +extern dladm_status_t dladm_aggr_modify(datalink_id_t, uint32_t, uint32_t, + boolean_t, const uchar_t *, aggr_lacp_mode_t, + aggr_lacp_timer_t, uint32_t); +extern dladm_status_t dladm_aggr_up(datalink_id_t); +extern dladm_status_t dladm_aggr_info(datalink_id_t, dladm_aggr_grp_attr_t *, + uint32_t); extern boolean_t dladm_aggr_str2policy(const char *, uint32_t *); extern char *dladm_aggr_policy2str(uint32_t, char *); extern boolean_t dladm_aggr_str2macaddr(const char *, boolean_t *, uchar_t *); -extern const char *dladm_aggr_macaddr2str(unsigned char *, char *); - +extern const char *dladm_aggr_macaddr2str(const unsigned char *, char *); extern boolean_t dladm_aggr_str2lacpmode(const char *, aggr_lacp_mode_t *); extern const char *dladm_aggr_lacpmode2str(aggr_lacp_mode_t, char *); extern boolean_t dladm_aggr_str2lacptimer(const char *, aggr_lacp_timer_t *); extern const char *dladm_aggr_lacptimer2str(aggr_lacp_timer_t, char *); - extern const char *dladm_aggr_portstate2str(aggr_port_state_t, char *); - -extern int dladm_aggr_walk(int (*)(void *, - dladm_aggr_grp_attr_t *), void *); +extern dladm_status_t dladm_key2linkid(uint16_t, datalink_id_t *, + uint32_t); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/common/libdllink.c b/usr/src/lib/libdladm/common/libdllink.c index 45f4641588..bd046acda9 100644 --- a/usr/src/lib/libdladm/common/libdllink.c +++ b/usr/src/lib/libdladm/common/libdllink.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. */ @@ -29,213 +29,85 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> +#include <assert.h> +#include <ctype.h> #include <strings.h> #include <sys/stat.h> #include <sys/dld.h> +#include <sys/vlan.h> +#include <librcm.h> #include <libdlpi.h> #include <libdevinfo.h> +#include <libdlaggr.h> +#include <libdlvlan.h> #include <libdllink.h> +#include <libdlmgmt.h> #include <libdladm_impl.h> -typedef struct dladm_dev { - char dd_name[IFNAMSIZ]; - struct dladm_dev *dd_next; -} dladm_dev_t; - -typedef struct dladm_walk { - dladm_dev_t *dw_dev_list; -} dladm_walk_t; - /* * Return the attributes of the specified datalink from the DLD driver. */ -static int -i_dladm_info(int fd, const char *name, dladm_attr_t *dap) +static dladm_status_t +i_dladm_info(int fd, const datalink_id_t linkid, dladm_attr_t *dap) { dld_ioc_attr_t dia; - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - (void) strlcpy(dia.dia_name, name, IFNAMSIZ); + dia.dia_linkid = linkid; - if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) - return (-1); + if (i_dladm_ioctl(fd, DLDIOC_ATTR, &dia, sizeof (dia)) < 0) + return (dladm_errno2status(errno)); - (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); dap->da_max_sdu = dia.dia_max_sdu; - dap->da_vid = dia.dia_vid; - return (0); + return (DLADM_STATUS_OK); } -/* - * Adds a datalink to the array corresponding to arg. - */ -static void -i_dladm_nt_net_add(void *arg, char *name) -{ - dladm_walk_t *dwp = arg; - dladm_dev_t *ddp = dwp->dw_dev_list; - dladm_dev_t **lastp = &dwp->dw_dev_list; - - while (ddp) { - /* - * Skip duplicates. - */ - if (strcmp(ddp->dd_name, name) == 0) - return; - - lastp = &ddp->dd_next; - ddp = ddp->dd_next; - } - - if ((ddp = malloc(sizeof (*ddp))) == NULL) - return; - - (void) strlcpy(ddp->dd_name, name, IFNAMSIZ); - ddp->dd_next = NULL; - *lastp = ddp; -} - -/* - * Walker callback invoked for each DDI_NT_NET node. - */ -static int -i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) -{ - char linkname[DLPI_LINKNAME_MAX]; - dlpi_handle_t dh; - - if (dlpi_makelink(linkname, di_minor_name(minor), - di_instance(node)) != DLPI_SUCCESS) - return (DI_WALK_CONTINUE); - - if (dlpi_open(linkname, &dh, 0) == DLPI_SUCCESS) { - i_dladm_nt_net_add(arg, linkname); - dlpi_close(dh); - } - return (DI_WALK_CONTINUE); -} - -/* - * Hold a data-link. - */ -static int -i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) -{ - int fd; - dld_hold_vlan_t dhv; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } +struct i_dladm_walk_arg { + dladm_walkcb_t *fn; + void *arg; +}; - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); - dhv.dhv_zid = zoneid; - dhv.dhv_docheck = docheck; - - if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) { - int olderrno = errno; - - (void) close(fd); - errno = olderrno; - return (-1); - } - - (void) close(fd); - return (0); -} - -/* - * Release a data-link. - */ static int -i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) +i_dladm_walk(datalink_id_t linkid, void *arg) { - int fd; - dld_hold_vlan_t dhv; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); - dhv.dhv_zid = zoneid; - dhv.dhv_docheck = docheck; + struct i_dladm_walk_arg *walk_arg = arg; + char link[MAXLINKNAMELEN]; - if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) { - int olderrno = errno; - - (void) close(fd); - errno = olderrno; - return (-1); + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link)) == DLADM_STATUS_OK) { + return (walk_arg->fn(link, walk_arg->arg)); } - (void) close(fd); - return (0); + return (DLADM_WALK_CONTINUE); } /* - * Invoke the specified callback function for each active DDI_NT_NET - * node. + * Walk all datalinks. */ -int -dladm_walk(void (*fn)(void *, const char *), void *arg) +dladm_status_t +dladm_walk(dladm_walkcb_t *fn, void *arg, datalink_class_t class, + datalink_media_t dmedia, uint32_t flags) { - di_node_t root; - dladm_walk_t dw; - dladm_dev_t *ddp, *last_ddp; - - if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { - errno = EFAULT; - return (-1); - } - dw.dw_dev_list = NULL; - - (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw, - i_dladm_nt_net_walk); - - di_fini(root); + struct i_dladm_walk_arg walk_arg; - ddp = dw.dw_dev_list; - while (ddp) { - fn(arg, ddp->dd_name); - last_ddp = ddp; - ddp = ddp->dd_next; - free(last_ddp); - } - - return (0); + walk_arg.fn = fn; + walk_arg.arg = arg; + return (dladm_walk_datalink_id(i_dladm_walk, &walk_arg, + class, dmedia, flags)); } /* - * MAC Administration Library. - * - * This library is used by administration tools such as dladm(1M) to + * These routines are used by administration tools such as dladm(1M) to * iterate through the list of MAC interfaces - * */ typedef struct dladm_mac_dev { char dm_name[MAXNAMELEN]; - struct dladm_mac_dev *dm_next; + struct dladm_mac_dev *dm_next; } dladm_mac_dev_t; typedef struct macadm_walk { - dladm_mac_dev_t *dmd_dev_list; + dladm_mac_dev_t *dmd_dev_list; } dladm_mac_walk_t; /* @@ -259,6 +131,12 @@ i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) if (strcmp("aggr", di_driver_name(node)) == 0) return (DI_WALK_CONTINUE); + /* + * Skip softmacs. + */ + if (strcmp("softmac", di_driver_name(node)) == 0) + return (DI_WALK_CONTINUE); + while (dmdp) { /* * Skip duplicates. @@ -281,17 +159,18 @@ i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) } /* - * Invoke the specified callback for each DDI_NT_MAC node. + * Invoke the specified callback for each DDI_NT_NET node. */ -int -dladm_mac_walk(void (*fn)(void *, const char *), void *arg) +dladm_status_t +dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) { di_node_t root; dladm_mac_walk_t dmw; dladm_mac_dev_t *dmdp, *next; + boolean_t done = B_FALSE; if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) - return (-1); + return (dladm_errno2status(errno)); dmw.dmd_dev_list = NULL; @@ -303,33 +182,32 @@ dladm_mac_walk(void (*fn)(void *, const char *), void *arg) dmdp = dmw.dmd_dev_list; for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { next = dmdp->dm_next; - (*fn)(arg, dmdp->dm_name); + if (!done && + ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { + done = B_TRUE; + } free(dmdp); } - return (0); + return (DLADM_STATUS_OK); } /* - * Returns the current attributes of the specified datalink. + * Get the current attributes of the specified datalink. */ -int -dladm_info(const char *name, dladm_attr_t *dap) +dladm_status_t +dladm_info(datalink_id_t linkid, dladm_attr_t *dap) { int fd; + dladm_status_t status; if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - if (i_dladm_info(fd, name, dap) < 0) - goto failed; + return (dladm_errno2status(errno)); - (void) close(fd); - return (0); + status = i_dladm_info(fd, linkid, dap); -failed: (void) close(fd); - return (-1); + return (status); } const char * @@ -373,19 +251,678 @@ dladm_linkduplex2str(link_duplex_t duplex, char *buf) } /* - * Do a "hold" operation to a link. + * Set zoneid of a given link */ -int -dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) +dladm_status_t +dladm_setzid(const char *link, zoneid_t zoneid) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_setzid_t dis; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + bzero(&dis, sizeof (dld_ioc_setzid_t)); + (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN); + dis.dis_zid = zoneid; + + if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + return (status); +} + +/* + * Get zoneid of a given link + */ +dladm_status_t +dladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_getzid_t dig; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + bzero(&dig, sizeof (dld_ioc_getzid_t)); + dig.dig_linkid = linkid; + dig.dig_zid = -1; + + if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + + if (status == DLADM_STATUS_OK) + *zoneidp = dig.dig_zid; + + return (status); +} + +/* + * Case 1: rename an existing link1 to a link2 that does not exist. + * Result: <linkid1, link2> + */ +static dladm_status_t +i_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1, + const char *link2, uint32_t flags) { - return (i_dladm_hold_link(name, zoneid, docheck)); + dld_ioc_rename_t dir; + dladm_conf_t conf; + dladm_status_t status = DLADM_STATUS_OK; + int fd; + + /* + * Link is currently available. Check to see whether anything is + * holding this link to prevent a rename operation. + */ + if (flags & DLADM_OPT_ACTIVE) { + dir.dir_linkid1 = linkid1; + dir.dir_linkid2 = DATALINK_INVALID_LINKID; + (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) { + status = dladm_errno2status(errno); + (void) close(fd); + return (status); + } + } + + status = dladm_remap_datalink_id(linkid1, link2); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Flush the current mapping to persistent configuration. + */ + if ((flags & DLADM_OPT_PERSIST) && + (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) || + ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) { + (void) dladm_remap_datalink_id(linkid1, link1); + } +done: + if (flags & DLADM_OPT_ACTIVE) { + if (status != DLADM_STATUS_OK) { + (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); + (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, + sizeof (dir)); + } + (void) close(fd); + } + return (status); +} + +typedef struct link_hold_arg_s { + datalink_id_t linkid; + datalink_id_t holder; + uint32_t flags; +} link_hold_arg_t; + +static int +i_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg) +{ + link_hold_arg_t *hold_arg = arg; + dladm_aggr_grp_attr_t ginfo; + dladm_status_t status; + int i; + + status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + for (i = 0; i < ginfo.lg_nports; i++) { + if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { + hold_arg->holder = aggrid; + return (DLADM_WALK_TERMINATE); + } + } + return (DLADM_WALK_CONTINUE); +} + +static int +i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg) +{ + link_hold_arg_t *hold_arg = arg; + dladm_vlan_attr_t vinfo; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (vinfo.dv_linkid == hold_arg->linkid) { + hold_arg->holder = vlanid; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); } /* - * Do a "release" operation to a link. + * Case 2: rename an available physical link link1 to a REMOVED physical link + * link2. As a result, link1 directly inherits all datalinks configured + * over link2 (linkid2). + * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, + * link2_other_attr> */ +static dladm_status_t +i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2) +{ + rcm_handle_t *rcm_hdl = NULL; + nvlist_t *nvl = NULL; + link_hold_arg_t arg; + dld_ioc_rename_t dir; + int fd; + dladm_conf_t conf1, conf2; + char devname[MAXLINKNAMELEN]; + uint64_t phymaj, phyinst; + dladm_status_t status = DLADM_STATUS_OK; + + /* + * First check if linkid1 is associated with any persistent + * aggregations or VLANs. If yes, return BUSY. + */ + arg.linkid = linkid1; + arg.holder = DATALINK_INVALID_LINKID; + arg.flags = DLADM_OPT_PERSIST; + (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (arg.holder != DATALINK_INVALID_LINKID) + return (DLADM_STATUS_LINKBUSY); + + arg.flags = DLADM_OPT_PERSIST; + (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (arg.holder != DATALINK_INVALID_LINKID) + return (DLADM_STATUS_LINKBUSY); + + /* + * Send DLDIOC_RENAME to request to rename link1's linkid to + * be linkid2. This will check whether link1 is used by any + * aggregations or VLANs, or is held by any application. If yes, + * return failure. + */ + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dir.dir_linkid1 = linkid1; + dir.dir_linkid2 = linkid2; + if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) + status = dladm_errno2status(errno); + + if (status != DLADM_STATUS_OK) { + (void) close(fd); + return (status); + } + + /* + * Now change the phymaj, phyinst and devname associated with linkid1 + * to be associated with linkid2. Before doing that, the old active + * linkprop of linkid1 should be deleted. + */ + (void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE); + + if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FDEVNAME, devname, + MAXLINKNAMELEN)) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj, + sizeof (uint64_t))) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst, + sizeof (uint64_t))) != DLADM_STATUS_OK) || + ((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) { + dir.dir_linkid1 = linkid2; + dir.dir_linkid2 = linkid1; + (void) dladm_init_linkprop(linkid1); + (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)); + (void) close(fd); + return (status); + } + (void) close(fd); + + dladm_destroy_conf(conf1); + (void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname); + (void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj); + (void) dladm_set_conf_field(conf2, FPHYINST, + DLADM_TYPE_UINT64, &phyinst); + (void) dladm_write_conf(conf2); + dladm_destroy_conf(conf2); + + /* + * Delete link1 and mark link2 up. + */ + (void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE | + DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid1); + (void) dladm_up_datalink_id(linkid2); + + /* + * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be + * consumed by the RCM framework to restore all the datalink and + * IP configuration. + */ + status = DLADM_STATUS_FAILED; + if ((nvlist_alloc(&nvl, 0, 0) != 0) || + (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { + goto done; + } + + if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) + goto done; + + if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == + RCM_SUCCESS) { + status = DLADM_STATUS_OK; + } + +done: + if (rcm_hdl != NULL) + (void) rcm_free_handle(rcm_hdl); + if (nvl != NULL) + nvlist_free(nvl); + return (status); +} + +/* + * case 3: rename a non-existent link to a REMOVED physical link. + * Set the removed physical link's device name to link1, so that + * when link1 attaches, it inherits all the link configuration of + * the removed physical link. + */ +static dladm_status_t +i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2) +{ + dladm_conf_t conf; + dladm_status_t status; + + if (!dladm_valid_linkname(link1)) + return (DLADM_STATUS_LINKINVAL); + + status = dladm_read_conf(linkid2, &conf); + if (status != DLADM_STATUS_OK) + goto done; + + if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR, + link1)) == DLADM_STATUS_OK) { + status = dladm_write_conf(conf); + } + + dladm_destroy_conf(conf); + +done: + return (status); +} + +dladm_status_t +dladm_rename_link(const char *link1, const char *link2) +{ + datalink_id_t linkid1 = DATALINK_INVALID_LINKID; + datalink_id_t linkid2 = DATALINK_INVALID_LINKID; + uint32_t flags1, flags2; + datalink_class_t class1, class2; + uint32_t media1, media2; + boolean_t remphy2 = B_FALSE; + dladm_status_t status; + + (void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1); + if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) == + DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && + (flags2 == DLADM_OPT_PERSIST)) { + /* + * see whether link2 is a removed physical link. + */ + remphy2 = B_TRUE; + } + + if (linkid1 != DATALINK_INVALID_LINKID) { + if (linkid2 == DATALINK_INVALID_LINKID) { + /* + * case 1: rename an existing link to a link that + * does not exist. + */ + status = i_dladm_rename_link_c1(linkid1, link1, link2, + flags1); + } else if (remphy2) { + /* + * case 2: rename an available link to a REMOVED + * physical link. Return failure if link1 is not + * an active physical link. + */ + if ((class1 != class2) || (media1 != media2) || + !(flags1 & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + } else { + status = i_dladm_rename_link_c2(linkid1, + linkid2); + } + } else { + status = DLADM_STATUS_EXIST; + } + } else if (remphy2) { + status = i_dladm_rename_link_c3(link1, linkid2); + } else { + status = DLADM_STATUS_NOTFOUND; + } + return (status); +} + +typedef struct consumer_del_phys_arg_s { + datalink_id_t linkid; +} consumer_del_phys_arg_t; + +static int +i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg) +{ + consumer_del_phys_arg_t *del_arg = arg; + dladm_vlan_attr_t vinfo; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (vinfo.dv_linkid == del_arg->linkid) + (void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST); + return (DLADM_WALK_CONTINUE); +} + +static int +i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg) +{ + consumer_del_phys_arg_t *del_arg = arg; + dladm_aggr_grp_attr_t ginfo; + dladm_status_t status; + dladm_aggr_port_attr_db_t port[1]; + int i; + + status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + for (i = 0; i < ginfo.lg_nports; i++) + if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) + break; + + if (i != ginfo.lg_nports) { + if (ginfo.lg_nports == 1 && i == 0) { + consumer_del_phys_arg_t aggr_del_arg; + + /* + * First delete all the VLANs on this aggregation, then + * delete the aggregation itself. + */ + aggr_del_arg.linkid = aggrid; + (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, + &aggr_del_arg, DATALINK_CLASS_VLAN, + DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + (void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST); + } else { + port[0].lp_linkid = del_arg->linkid; + (void) dladm_aggr_remove(aggrid, 1, port, + DLADM_OPT_PERSIST); + } + } + return (DLADM_WALK_CONTINUE); +} + +typedef struct del_phys_arg_s { + dladm_status_t rval; +} del_phys_arg_t; + +static int +i_dladm_phys_delete(datalink_id_t linkid, void *arg) +{ + uint32_t flags; + datalink_class_t class; + uint32_t media; + dladm_status_t status = DLADM_STATUS_OK; + del_phys_arg_t *del_phys_arg = arg; + consumer_del_phys_arg_t del_arg; + + if ((status = dladm_datalink_id2info(linkid, &flags, &class, + &media, NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + + /* + * see whether this link is a removed physical link. + */ + if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || + (flags & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + goto done; + } + + if (media == DL_ETHER) { + del_arg.linkid = linkid; + (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + } + + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid); + +done: + del_phys_arg->rval = status; + return (DLADM_WALK_CONTINUE); +} + +dladm_status_t +dladm_phys_delete(datalink_id_t linkid) +{ + del_phys_arg_t arg = {DLADM_STATUS_OK}; + + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg, + DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_phys_delete(linkid, &arg); + return (arg.rval); + } +} + +dladm_status_t +dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags) +{ + dladm_status_t status; + + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + + switch (flags) { + case DLADM_OPT_PERSIST: { + dladm_conf_t conf; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev, + MAXLINKNAMELEN); + dladm_destroy_conf(conf); + return (status); + } + case DLADM_OPT_ACTIVE: { + dld_ioc_phys_attr_t dip; + int fd; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dip.dip_linkid = linkid; + if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip)) + < 0) { + status = dladm_errno2status(errno); + (void) close(fd); + return (status); + } + (void) close(fd); + dpap->dp_novanity = dip.dip_novanity; + (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); + return (DLADM_STATUS_OK); + } + default: + return (DLADM_STATUS_BADARG); + } +} + +typedef struct i_walk_dev_state_s { + const char *devname; + datalink_id_t linkid; + boolean_t found; +} i_walk_dev_state_t; + int -dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) +i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg) +{ + dladm_phys_attr_t dpa; + dladm_status_t status; + i_walk_dev_state_t *statep = arg; + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); + if ((status == DLADM_STATUS_OK) && + (strcmp(statep->devname, dpa.dp_dev) == 0)) { + statep->found = B_TRUE; + statep->linkid = linkid; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); +} + +/* + * Get the linkid from the physical device name. + */ +dladm_status_t +dladm_dev2linkid(const char *devname, datalink_id_t *linkidp) { - return (i_dladm_rele_link(name, zoneid, docheck)); + i_walk_dev_state_t state; + + state.found = B_FALSE; + state.devname = devname; + + (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state, + DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (state.found == B_TRUE) { + *linkidp = state.linkid; + return (DLADM_STATUS_OK); + } else { + return (dladm_errno2status(ENOENT)); + } +} + +static int +parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) +{ + char *cp, *tp; + int len; + + /* + * device name length must not be 0, and it must end with digit. + */ + if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) + return (EINVAL); + + (void) strlcpy(driver, devname, maxlen); + cp = (char *)&driver[len - 1]; + + for (tp = cp; isdigit(*tp); tp--) { + if (tp <= driver) + return (EINVAL); + } + + *ppa = atoi(tp + 1); + *(tp + 1) = '\0'; + return (0); +} + +dladm_status_t +dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) +{ + char devname[MAXLINKNAMELEN]; + uint16_t vid = VLAN_ID_NONE; + datalink_class_t class; + dladm_status_t status; + + status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * If this is a VLAN, we must first determine the class and linkid of + * the link the VLAN has been created over. + */ + if (class == DATALINK_CLASS_VLAN) { + dladm_vlan_attr_t dva; + + status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) + goto done; + linkid = dva.dv_linkid; + vid = dva.dv_vid; + + if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL, + NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + } + + switch (class) { + case DATALINK_CLASS_AGGR: { + dladm_aggr_grp_attr_t dga; + + status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) + goto done; + + if (dga.lg_key == 0) { + /* + * If the key was not specified when the aggregation + * is created, we cannot guess its /dev node name. + */ + status = DLADM_STATUS_BADARG; + goto done; + } + (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); + break; + } + case DATALINK_CLASS_PHYS: { + dladm_phys_attr_t dpa; + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + goto done; + + (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); + break; + } + default: + status = DLADM_STATUS_BADARG; + goto done; + } + + if (vid != VLAN_ID_NONE) { + char drv[MAXNAMELEN]; + uint_t ppa; + + if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { + status = DLADM_STATUS_BADARG; + goto done; + } + if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) + status = DLADM_STATUS_TOOSMALL; + } else { + if (strlcpy(dev, devname, len) >= len) + status = DLADM_STATUS_TOOSMALL; + } + +done: + return (status); } diff --git a/usr/src/lib/libdladm/common/libdllink.h b/usr/src/lib/libdladm/common/libdllink.h index 12327456a5..2b762ff6d8 100644 --- a/usr/src/lib/libdladm/common/libdllink.h +++ b/usr/src/lib/libdladm/common/libdllink.h @@ -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. */ @@ -29,14 +29,12 @@ #pragma ident "%Z%%M% %I% %E% SMI" /* - * This file includes strcutures, macros and routines used by general - * link administration, which applies not limited to one specific - * type of link. + * This file includes structures, macros and routines used by general + * link administration (i.e. not limited to one specific type of link). */ #include <sys/types.h> #include <sys/param.h> -#include <sys/mac.h> #include <libdladm.h> #ifdef __cplusplus @@ -44,11 +42,25 @@ extern "C" { #endif typedef struct dladm_attr { - char da_dev[MAXNAMELEN]; uint_t da_max_sdu; - uint16_t da_vid; } dladm_attr_t; +typedef struct dladm_phys_attr { + char dp_dev[MAXLINKNAMELEN]; + /* + * Whether this physical link supports vanity naming (links with media + * types not supported by GLDv3 don't have vanity naming support). + */ + boolean_t dp_novanity; +} dladm_phys_attr_t; + +typedef enum { + DLADM_PROP_VAL_CURRENT = 1, + DLADM_PROP_VAL_DEFAULT, + DLADM_PROP_VAL_MODIFIABLE, + DLADM_PROP_VAL_PERSISTENT +} dladm_prop_type_t; + /* * Maximum size of secobj value. Note that it should not be greater than * DLD_SECOBJ_VAL_MAX. @@ -61,26 +73,31 @@ typedef struct dladm_attr { */ #define DLADM_SECOBJ_NAME_MAX 32 -#define DLADM_PROP_VAL_MAX 25 +#define DLADM_MAX_PROP_VALCNT 32 +#define DLADM_PROP_VAL_MAX 128 #define DLADM_SECOBJ_CLASS_WEP 0 #define DLADM_SECOBJ_CLASS_WPA 1 typedef int dladm_secobj_class_t; -typedef void (dladm_walkcb_t)(void *, const char *); +typedef int (dladm_walkcb_t)(const char *, void *); + +extern dladm_status_t dladm_walk(dladm_walkcb_t *, void *, datalink_class_t, + datalink_media_t, uint32_t); +extern dladm_status_t dladm_mac_walk(dladm_walkcb_t *, void *); +extern dladm_status_t dladm_info(datalink_id_t, dladm_attr_t *); +extern dladm_status_t dladm_setzid(const char *, zoneid_t); +extern dladm_status_t dladm_getzid(datalink_id_t, zoneid_t *); -extern int dladm_walk(dladm_walkcb_t *, void *); -extern int dladm_mac_walk(void (*fn)(void *, const char *), void *); -extern int dladm_info(const char *, dladm_attr_t *); -extern int dladm_hold_link(const char *, zoneid_t, boolean_t); -extern int dladm_rele_link(const char *, zoneid_t, boolean_t); +extern dladm_status_t dladm_rename_link(const char *, const char *); -extern dladm_status_t dladm_set_prop(const char *, const char *, - char **, uint_t, uint_t, char **); -extern dladm_status_t dladm_get_prop(const char *, dladm_prop_type_t, +extern dladm_status_t dladm_set_linkprop(datalink_id_t, const char *, + char **, uint_t, uint_t); +extern dladm_status_t dladm_get_linkprop(datalink_id_t, dladm_prop_type_t, const char *, char **, uint_t *); -extern dladm_status_t dladm_walk_prop(const char *, void *, - boolean_t (*)(void *, const char *)); +extern dladm_status_t dladm_walk_linkprop(datalink_id_t, void *, + int (*)(datalink_id_t, const char *, void *)); + extern dladm_status_t dladm_set_secobj(const char *, dladm_secobj_class_t, uint8_t *, uint_t, uint_t); extern dladm_status_t dladm_get_secobj(const char *, dladm_secobj_class_t *, @@ -95,9 +112,40 @@ extern const char *dladm_secobjclass2str(dladm_secobj_class_t, char *); extern dladm_status_t dladm_str2secobjclass(const char *, dladm_secobj_class_t *); -extern dladm_status_t dladm_init_linkprop(void); +extern dladm_status_t dladm_init_linkprop(datalink_id_t); extern dladm_status_t dladm_init_secobj(void); +extern dladm_status_t dladm_create_datalink_id(const char *, datalink_class_t, + uint_t, uint32_t, datalink_id_t *); +extern dladm_status_t dladm_destroy_datalink_id(datalink_id_t, uint32_t); +extern dladm_status_t dladm_remap_datalink_id(datalink_id_t, const char *); +extern dladm_status_t dladm_up_datalink_id(datalink_id_t); +extern dladm_status_t dladm_name2info(const char *, datalink_id_t *, + uint32_t *, datalink_class_t *, uint32_t *); +extern dladm_status_t dladm_datalink_id2info(datalink_id_t, uint32_t *, + datalink_class_t *, uint32_t *, char *, size_t); +extern dladm_status_t dladm_walk_datalink_id(int (*)(datalink_id_t, void *), + void *, datalink_class_t, datalink_media_t, + uint32_t); +extern dladm_status_t dladm_create_conf(const char *, datalink_id_t, + datalink_class_t, uint32_t, dladm_conf_t *); +extern dladm_status_t dladm_read_conf(datalink_id_t, dladm_conf_t *); +extern dladm_status_t dladm_write_conf(dladm_conf_t); +extern dladm_status_t dladm_remove_conf(datalink_id_t); +extern void dladm_destroy_conf(dladm_conf_t); +extern dladm_status_t dladm_get_conf_field(dladm_conf_t, const char *, + void *, size_t); +extern dladm_status_t dladm_set_conf_field(dladm_conf_t, const char *, + dladm_datatype_t, const void *); +extern dladm_status_t dladm_unset_conf_field(dladm_conf_t, const char *); + +extern dladm_status_t dladm_dev2linkid(const char *, datalink_id_t *); +extern dladm_status_t dladm_linkid2legacyname(datalink_id_t, char *, size_t); +extern dladm_status_t dladm_phys_delete(datalink_id_t); + +extern dladm_status_t dladm_phys_info(datalink_id_t, dladm_phys_attr_t *, + uint32_t); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdlmgmt.c b/usr/src/lib/libdladm/common/libdlmgmt.c new file mode 100644 index 0000000000..1826edf810 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlmgmt.c @@ -0,0 +1,676 @@ +/* + * 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 <door.h> +#include <errno.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/aggr.h> +#include <fcntl.h> +#include <libdladm.h> +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdlmgmt.h> + +/* + * Table of data type sizes indexed by dladm_datatype_t. + */ +static size_t dladm_datatype_size[] = { + 0, /* DLADM_TYPE_STR, use strnlen() */ + sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */ + sizeof (uint64_t) /* DLADM_TYPE_UINT64 */ +}; + +static dladm_status_t +dladm_door_call(void *arg, size_t asize, void *rbuf, size_t *rsizep) +{ + door_arg_t darg; + dlmgmt_retval_t *retvalp = rbuf; + int fd; + dladm_status_t status = DLADM_STATUS_OK; + + if ((fd = open(DLMGMT_DOOR, O_RDONLY)) == -1) + return (dladm_errno2status(errno)); + + darg.data_ptr = arg; + darg.data_size = asize; + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = rbuf; + darg.rsize = *rsizep; + + if (door_call(fd, &darg) == -1) + status = dladm_errno2status(errno); + (void) close(fd); + + if (status != DLADM_STATUS_OK) + return (status); + + if (darg.rbuf != rbuf) { + /* + * The size of the input rbuf is not big enough so that + * the door allocate the rbuf itself. In this case, simply + * think something wrong with the door call. + */ + (void) munmap(darg.rbuf, darg.rsize); + return (DLADM_STATUS_TOOSMALL); + } + if (darg.rsize > *rsizep || darg.rsize < sizeof (uint_t)) + return (DLADM_STATUS_FAILED); + + if (retvalp->lr_err != 0) + status = dladm_errno2status(retvalp->lr_err); + else + *rsizep = darg.rsize; + return (status); +} + +/* + * Allocate a new linkid with the given name. Return the new linkid. + */ +dladm_status_t +dladm_create_datalink_id(const char *link, datalink_class_t class, + uint32_t media, uint32_t flags, datalink_id_t *linkidp) +{ + dlmgmt_door_createid_t createid; + dlmgmt_createid_retval_t retval; + uint32_t dlmgmt_flags; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || class == DATALINK_CLASS_ALL || + !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) || + linkidp == NULL) { + return (DLADM_STATUS_BADARG); + } + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0; + + (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN); + createid.ld_class = class; + createid.ld_media = media; + createid.ld_flags = dlmgmt_flags; + createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID; + createid.ld_prefix = (flags & DLADM_OPT_PREFIX); + rsize = sizeof (retval); + + status = dladm_door_call(&createid, sizeof (createid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *linkidp = retval.lr_linkid; + return (DLADM_STATUS_OK); +} + +/* + * Destroy the given link ID. + */ +dladm_status_t +dladm_destroy_datalink_id(datalink_id_t linkid, uint32_t flags) +{ + dlmgmt_door_destroyid_t destroyid; + dlmgmt_destroyid_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + dladm_status_t status; + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; + destroyid.ld_linkid = linkid; + destroyid.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + status = dladm_door_call(&destroyid, sizeof (destroyid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remap a given link ID to a new name. + */ +dladm_status_t +dladm_remap_datalink_id(datalink_id_t linkid, const char *link) +{ + dlmgmt_door_remapid_t remapid; + dlmgmt_remapid_retval_t retval; + size_t rsize; + dladm_status_t status; + + remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; + remapid.ld_linkid = linkid; + (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&remapid, sizeof (remapid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Make a given link ID active. + */ +dladm_status_t +dladm_up_datalink_id(datalink_id_t linkid) +{ + dlmgmt_door_upid_t upid; + dlmgmt_upid_retval_t retval; + size_t rsize; + dladm_status_t status; + + upid.ld_cmd = DLMGMT_CMD_UP_LINKID; + upid.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&upid, sizeof (upid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Create a new link with the given name. Return the new link's handle + */ +dladm_status_t +dladm_create_conf(const char *link, datalink_id_t linkid, + datalink_class_t class, uint32_t media, dladm_conf_t *confp) +{ + dlmgmt_door_createconf_t createconf; + dlmgmt_createconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || confp == NULL) + return (DLADM_STATUS_BADARG); + + (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); + createconf.ld_class = class; + createconf.ld_media = media; + createconf.ld_linkid = linkid; + createconf.ld_cmd = DLMGMT_CMD_CREATECONF; + rsize = sizeof (retval); + + status = dladm_door_call(&createconf, sizeof (createconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * An active physical link reported by the dlmgmtd daemon might not be active + * anymore as this link might be removed during system shutdown. Check its + * real status by calling dladm_phys_info(). + */ +dladm_status_t +i_dladm_phys_status(datalink_id_t linkid, uint32_t *flagsp) +{ + dladm_phys_attr_t dpa; + dladm_status_t status; + + assert((*flagsp) & DLMGMT_ACTIVE); + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE); + if (status == DLADM_STATUS_NOTFOUND) { + /* + * No active status, this link was removed. Update its status + * in the daemon and delete all active linkprops. + */ + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + + (*flagsp) &= ~DLMGMT_ACTIVE; + status = DLADM_STATUS_OK; + } + return (status); +} + +/* + * Walk each entry in the data link configuration repository and + * call fn on the linkid and arg. + */ +dladm_status_t +dladm_walk_datalink_id(int (*fn)(datalink_id_t, void *), void *argp, + datalink_class_t class, datalink_media_t dmedia, uint32_t flags) +{ + dlmgmt_door_getnext_t getnext; + dlmgmt_getnext_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + dladm_status_t status = DLADM_STATUS_OK; + + if (fn == NULL) + return (DLADM_STATUS_BADARG); + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + getnext.ld_cmd = DLMGMT_CMD_GETNEXT; + getnext.ld_class = class; + getnext.ld_dmedia = dmedia; + getnext.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + do { + getnext.ld_linkid = linkid; + status = dladm_door_call(&getnext, sizeof (getnext), + &retval, &rsize); + if (status != DLADM_STATUS_OK) { + /* + * done with walking + */ + break; + } + + if (rsize != sizeof (retval)) { + status = DLADM_STATUS_BADARG; + break; + } + + linkid = retval.lr_linkid; + if ((retval.lr_class == DATALINK_CLASS_PHYS) && + (retval.lr_flags & DLMGMT_ACTIVE)) { + /* + * An active physical link reported by the dlmgmtd + * daemon might not be active anymore. Check its + * real status. + */ + if (i_dladm_phys_status(linkid, &retval.lr_flags) != + DLADM_STATUS_OK) { + continue; + } + + if (!(dlmgmt_flags & retval.lr_flags)) + continue; + } + + if (fn(linkid, argp) == DLADM_WALK_TERMINATE) + break; + } while (linkid != DATALINK_INVALID_LINKID); + + return (status); +} + +/* + * Get the link properties structure for the given link. + */ +dladm_status_t +dladm_read_conf(datalink_id_t linkid, dladm_conf_t *confp) +{ + dlmgmt_door_readconf_t readconf; + dlmgmt_readconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (linkid == DATALINK_INVALID_LINKID || confp == NULL) + return (DLADM_STATUS_BADARG); + + readconf.ld_linkid = linkid; + readconf.ld_cmd = DLMGMT_CMD_READCONF; + rsize = sizeof (retval); + + status = dladm_door_call(&readconf, sizeof (readconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * Commit the given link to the data link configuration repository so + * that it will persist across reboots. + */ +dladm_status_t +dladm_write_conf(dladm_conf_t conf) +{ + dlmgmt_door_writeconf_t writeconf; + dlmgmt_writeconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return (DLADM_STATUS_BADARG); + + writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; + writeconf.ld_conf = conf; + rsize = sizeof (retval); + + status = dladm_door_call(&writeconf, sizeof (writeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Given a link ID and a key, get the matching information from + * data link configuration repository. + */ +dladm_status_t +dladm_get_conf_field(dladm_conf_t conf, const char *attr, void *attrval, + size_t attrsz) +{ + dlmgmt_door_getattr_t getattr; + dlmgmt_getattr_retval_t *retvalp; + dladm_status_t status = DLADM_STATUS_OK; + size_t oldsize, size; + + if (conf == DLADM_INVALID_CONF || attrval == NULL || + attrsz == 0 || attr == NULL || *attr == '\0') { + return (DLADM_STATUS_BADARG); + } + + getattr.ld_cmd = DLMGMT_CMD_GETATTR; + getattr.ld_conf = conf; + (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); + + oldsize = size = attrsz + sizeof (dlmgmt_getattr_retval_t) - 1; + if ((retvalp = calloc(1, oldsize)) == NULL) + return (DLADM_STATUS_NOMEM); + + status = dladm_door_call(&getattr, sizeof (getattr), retvalp, &size); + if (status != DLADM_STATUS_OK) + goto done; + + assert(size <= oldsize); + size = size + 1 - sizeof (dlmgmt_getattr_retval_t); + bcopy(retvalp->lr_attr, attrval, size); +done: + free(retvalp); + return (status); +} + +/* + * Get the link ID that is associated with the given name. + */ +dladm_status_t +dladm_name2info(const char *link, datalink_id_t *linkidp, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap) +{ + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_getlinkid_retval_t retval; + datalink_id_t linkid; + size_t rsize; + dladm_status_t status; + + getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; + (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&getlinkid, sizeof (getlinkid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + linkid = retval.lr_linkid; + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (linkidp != NULL) + *linkidp = linkid; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + + return (DLADM_STATUS_OK); +} + +/* + * Get the link name that is associated with the given id. + */ +dladm_status_t +dladm_datalink_id2info(datalink_id_t linkid, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap, char *link, size_t len) +{ + dlmgmt_door_getname_t getname; + dlmgmt_getname_retval_t retval; + size_t rsize; + dladm_status_t status; + + if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || + (link == NULL && len != 0)) { + return (DLADM_STATUS_BADARG); + } + + getname.ld_cmd = DLMGMT_CMD_GETNAME; + getname.ld_linkid = linkid; + rsize = sizeof (retval); + status = dladm_door_call(&getname, sizeof (getname), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if ((rsize != sizeof (retval)) || + (len != 0 && (strlen(retval.lr_link) + 1 > len))) { + return (DLADM_STATUS_TOOSMALL); + } + + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (link != NULL) + (void) strlcpy(link, retval.lr_link, len); + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? + DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + return (DLADM_STATUS_OK); +} + +/* + * Set the given attr with the given attrval for the given link. + */ +dladm_status_t +dladm_set_conf_field(dladm_conf_t conf, const char *attr, + dladm_datatype_t type, const void *attrval) +{ + dlmgmt_door_setattr_t *setattrp; + dlmgmt_setattr_retval_t retval; + dladm_status_t status; + size_t asize, attrsz, rsize; + + if (attr == NULL || attr == '\0' || attrval == NULL) + return (DLADM_STATUS_BADARG); + + if (type == DLADM_TYPE_STR) + attrsz = strlen(attrval) + 1; + else + attrsz = dladm_datatype_size[type]; + + asize = sizeof (dlmgmt_door_setattr_t) + attrsz - 1; + if ((setattrp = calloc(1, asize)) == NULL) + return (DLADM_STATUS_NOMEM); + + setattrp->ld_cmd = DLMGMT_CMD_SETATTR; + setattrp->ld_conf = conf; + (void) strlcpy(setattrp->ld_attr, attr, MAXLINKATTRLEN); + setattrp->ld_attrsz = attrsz; + setattrp->ld_type = type; + bcopy(attrval, &setattrp->ld_attrval, attrsz); + rsize = sizeof (retval); + + status = dladm_door_call(setattrp, asize, &retval, &rsize); + if (status != DLADM_STATUS_OK) + goto done; + + if (rsize != sizeof (retval)) + status = DLADM_STATUS_BADARG; + +done: + free(setattrp); + return (status); +} + +/* + * Unset the given attr the given link. + */ +dladm_status_t +dladm_unset_conf_field(dladm_conf_t conf, const char *attr) +{ + dlmgmt_door_unsetattr_t unsetattr; + dlmgmt_unsetattr_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (attr == NULL || attr == '\0') + return (DLADM_STATUS_BADARG); + + unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; + unsetattr.ld_conf = conf; + (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); + rsize = sizeof (retval); + + status = dladm_door_call(&unsetattr, sizeof (unsetattr), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remove the given link ID and its entry from the data link configuration + * repository. + */ +dladm_status_t +dladm_remove_conf(datalink_id_t linkid) +{ + dlmgmt_door_removeconf_t removeconf; + dlmgmt_removeconf_retval_t retval; + size_t rsize; + dladm_status_t status; + + removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; + removeconf.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&removeconf, sizeof (removeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Free the contents of the link structure. + */ +void +dladm_destroy_conf(dladm_conf_t conf) +{ + dlmgmt_door_destroyconf_t destroyconf; + dlmgmt_destroyconf_retval_t retval; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return; + + destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; + destroyconf.ld_conf = conf; + rsize = sizeof (retval); + + (void) dladm_door_call(&destroyconf, sizeof (destroyconf), &retval, + &rsize); +} diff --git a/usr/src/lib/libdladm/common/libdlmgmt.h b/usr/src/lib/libdladm/common/libdlmgmt.h new file mode 100644 index 0000000000..0459d7360b --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlmgmt.h @@ -0,0 +1,199 @@ +/* + * 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. + */ + +/* + * This file includes structures, macros used to communicate with linkmgmt + * daemon. + */ + +#ifndef _LIBDLMGMT_H +#define _LIBDLMGMT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <libdladm.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * datalink management related macros, structures. + */ + +/* + * Door call commands. + */ +#define DLMGMT_CMD_CREATE_LINKID (DLMGMT_CMD_BASE + 0) +#define DLMGMT_CMD_DESTROY_LINKID (DLMGMT_CMD_BASE + 1) +#define DLMGMT_CMD_REMAP_LINKID (DLMGMT_CMD_BASE + 2) +#define DLMGMT_CMD_CREATECONF (DLMGMT_CMD_BASE + 3) +#define DLMGMT_CMD_READCONF (DLMGMT_CMD_BASE + 4) +#define DLMGMT_CMD_WRITECONF (DLMGMT_CMD_BASE + 5) +#define DLMGMT_CMD_UP_LINKID (DLMGMT_CMD_BASE + 6) +#define DLMGMT_CMD_SETATTR (DLMGMT_CMD_BASE + 7) +#define DLMGMT_CMD_UNSETATTR (DLMGMT_CMD_BASE + 8) +#define DLMGMT_CMD_REMOVECONF (DLMGMT_CMD_BASE + 9) +#define DLMGMT_CMD_DESTROYCONF (DLMGMT_CMD_BASE + 10) +#define DLMGMT_CMD_GETATTR (DLMGMT_CMD_BASE + 11) + +typedef struct dlmgmt_door_createid_s { + int ld_cmd; + char ld_link[MAXLINKNAMELEN]; + datalink_class_t ld_class; + uint32_t ld_media; + boolean_t ld_prefix; + uint32_t ld_flags; +} dlmgmt_door_createid_t; + +typedef struct dlmgmt_door_destroyid_s { + int ld_cmd; + datalink_id_t ld_linkid; + uint32_t ld_flags; +} dlmgmt_door_destroyid_t; + +typedef struct dlmgmt_door_remapid_s { + int ld_cmd; + datalink_id_t ld_linkid; + char ld_link[MAXLINKNAMELEN]; +} dlmgmt_door_remapid_t; + +typedef struct dlmgmt_door_upid_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_upid_t; + +typedef struct dlmgmt_door_createconf_s { + int ld_cmd; + char ld_link[MAXLINKNAMELEN]; + datalink_id_t ld_linkid; + datalink_class_t ld_class; + uint32_t ld_media; +} dlmgmt_door_createconf_t; + +typedef struct dlmgmt_door_setattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; + size_t ld_attrsz; + dladm_datatype_t ld_type; + char ld_attrval[1]; +} dlmgmt_door_setattr_t; + +typedef struct dlmgmt_door_unsetattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; +} dlmgmt_door_unsetattr_t; + +typedef struct dlmgmt_door_writeconf_s { + int ld_cmd; + dladm_conf_t ld_conf; +} dlmgmt_door_writeconf_t; + +typedef struct dlmgmt_door_removeconf_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_removeconf_t; + +typedef struct dlmgmt_door_destroyconf_s { + int ld_cmd; + dladm_conf_t ld_conf; +} dlmgmt_door_destroyconf_t; + +typedef struct dlmgmt_door_readconf_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_readconf_t; + +typedef struct dlmgmt_door_getattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; +} dlmgmt_door_getattr_t; + +typedef union dlmgmt_door_arg_s { + int ld_cmd; + dlmgmt_upcall_arg_create_t kcreate; + dlmgmt_upcall_arg_destroy_t kdestroy; + dlmgmt_upcall_arg_getattr_t kgetattr; + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_door_getnext_t getnext; + dlmgmt_door_createid_t createid; + dlmgmt_door_destroyid_t destroyid; + dlmgmt_door_remapid_t remapid; + dlmgmt_door_upid_t upid; + dlmgmt_door_createconf_t createconf; + dlmgmt_door_getname_t getname; + dlmgmt_door_getattr_t getattr; + dlmgmt_door_setattr_t setattr; + dlmgmt_door_writeconf_t writeconf; + dlmgmt_door_removeconf_t removeconf; + dlmgmt_door_destroyconf_t destroyconf; + dlmgmt_door_readconf_t readconf; +} dlmgmt_door_arg_t; + +typedef struct dlmgmt_handle_retval_s { + uint_t lr_err; + dladm_conf_t lr_conf; +} dlmgmt_createconf_retval_t, dlmgmt_readconf_retval_t; + +typedef struct dlmgmt_null_retval_s dlmgmt_remapid_retval_t, + dlmgmt_upid_retval_t, + dlmgmt_destroyid_retval_t, + dlmgmt_setattr_retval_t, + dlmgmt_unsetattr_retval_t, + dlmgmt_writeconf_retval_t, + dlmgmt_removeconf_retval_t, + dlmgmt_destroyconf_retval_t; + +typedef struct dlmgmt_linkid_retval_s dlmgmt_createid_retval_t; + +typedef union dlmgmt_retval { + uint_t lr_err; /* return error code */ + dlmgmt_create_retval_t kcreate; + dlmgmt_destroy_retval_t kdestroy; + dlmgmt_getattr_retval_t getattr; + dlmgmt_getname_retval_t getname; + dlmgmt_getlinkid_retval_t getlinkid; + dlmgmt_getnext_retval_t getnext; + dlmgmt_createid_retval_t createid; + dlmgmt_destroyid_retval_t destroyid; + dlmgmt_remapid_retval_t remapid; + dlmgmt_upid_retval_t upid; + dlmgmt_createconf_retval_t createconf; + dlmgmt_readconf_retval_t readconf; + dlmgmt_setattr_retval_t setattr; + dlmgmt_writeconf_retval_t writeconf; + dlmgmt_removeconf_retval_t removeconf; + dlmgmt_destroyconf_retval_t destroyconf; +} dlmgmt_retval_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDLMGMT_H */ diff --git a/usr/src/lib/libdladm/common/libdlvlan.c b/usr/src/lib/libdladm/common/libdlvlan.c new file mode 100644 index 0000000000..fb84ad92f6 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlvlan.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" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <sys/dld.h> +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdlvlan.h> + +/* + * VLAN Administration Library. + * + * This library is used by administration tools such as dladm(1M) to + * configure VLANs. + */ + +/* + * Returns the current attributes of the specified VLAN. + */ +static dladm_status_t +i_dladm_vlan_info_active(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) +{ + int fd; + dld_ioc_vlan_attr_t div; + dladm_status_t status = DLADM_STATUS_OK; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + div.div_vlanid = vlanid; + + if (i_dladm_ioctl(fd, DLDIOC_VLAN_ATTR, &div, sizeof (div)) < 0) + status = dladm_errno2status(errno); + + dvap->dv_vid = div.div_vid; + dvap->dv_linkid = div.div_linkid; + dvap->dv_force = div.div_force; + dvap->dv_implicit = div.div_implicit; +done: + (void) close(fd); + return (status); +} + +/* + * Returns the persistent attributes of the specified VLAN. + */ +static dladm_status_t +i_dladm_vlan_info_persist(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) +{ + dladm_conf_t conf = DLADM_INVALID_CONF; + dladm_status_t status; + uint64_t u64; + + if ((status = dladm_read_conf(vlanid, &conf)) != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + dvap->dv_linkid = (datalink_id_t)u64; + + status = dladm_get_conf_field(conf, FFORCE, &dvap->dv_force, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; + + dvap->dv_implicit = B_FALSE; + + status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + dvap->dv_vid = (uint16_t)u64; + +done: + dladm_destroy_conf(conf); + return (status); +} + +dladm_status_t +dladm_vlan_info(datalink_id_t vlanid, dladm_vlan_attr_t *dvap, uint32_t flags) +{ + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + if (flags == DLADM_OPT_ACTIVE) + return (i_dladm_vlan_info_active(vlanid, dvap)); + else + return (i_dladm_vlan_info_persist(vlanid, dvap)); +} + +static dladm_status_t +dladm_persist_vlan_conf(const char *vlan, datalink_id_t vlanid, + boolean_t force, datalink_id_t linkid, uint16_t vid) +{ + dladm_conf_t conf = DLADM_INVALID_CONF; + dladm_status_t status; + uint64_t u64; + + if ((status = dladm_create_conf(vlan, vlanid, DATALINK_CLASS_VLAN, + DL_ETHER, &conf)) != DLADM_STATUS_OK) { + return (status); + } + + u64 = linkid; + status = dladm_set_conf_field(conf, FLINKOVER, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); + if (status != DLADM_STATUS_OK) + goto done; + + u64 = vid; + status = dladm_set_conf_field(conf, FVLANID, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_write_conf(conf); + +done: + dladm_destroy_conf(conf); + return (status); +} + +/* + * Create a VLAN on given link. + */ +dladm_status_t +dladm_vlan_create(const char *vlan, datalink_id_t linkid, uint16_t vid, + uint32_t flags) +{ + dld_ioc_create_vlan_t dic; + int fd; + datalink_id_t vlanid = DATALINK_INVALID_LINKID; + uint_t media; + datalink_class_t class; + dladm_status_t status; + + if (vid < 1 || vid > 4094) + return (DLADM_STATUS_VIDINVAL); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK || media != DL_ETHER || + class == DATALINK_CLASS_VLAN) { + return (DLADM_STATUS_BADARG); + } + + status = dladm_create_datalink_id(vlan, DATALINK_CLASS_VLAN, DL_ETHER, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &vlanid); + if (status != DLADM_STATUS_OK) + goto fail; + + if (flags & DLADM_OPT_PERSIST) { + status = dladm_persist_vlan_conf(vlan, vlanid, + (flags & DLADM_OPT_FORCE) != 0, linkid, vid); + if (status != DLADM_STATUS_OK) + goto fail; + } + + if (flags & DLADM_OPT_ACTIVE) { + dic.dic_vlanid = vlanid; + dic.dic_linkid = linkid; + dic.dic_vid = vid; + dic.dic_force = (flags & DLADM_OPT_FORCE) != 0; + + if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, + sizeof (dic)) < 0) { + status = dladm_errno2status(errno); + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(vlanid); + goto fail; + } + } + + (void) close(fd); + return (DLADM_STATUS_OK); + +fail: + if (vlanid != DATALINK_INVALID_LINKID) { + (void) dladm_destroy_datalink_id(vlanid, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); + } + (void) close(fd); + return (status); +} + +/* + * Delete a given VLAN. + */ +dladm_status_t +dladm_vlan_delete(datalink_id_t vlanid, uint32_t flags) +{ + dld_ioc_delete_vlan_t did; + int fd; + datalink_class_t class; + dladm_status_t status = DLADM_STATUS_OK; + + if ((dladm_datalink_id2info(vlanid, NULL, &class, NULL, NULL, 0) != + DLADM_STATUS_OK) || (class != DATALINK_CLASS_VLAN)) { + return (DLADM_STATUS_BADARG); + } + + if (flags & DLADM_OPT_ACTIVE) { + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + did.did_linkid = vlanid; + if ((i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, + sizeof (did)) < 0) && + ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { + (void) close(fd); + return (dladm_errno2status(errno)); + } + (void) close(fd); + + /* + * Delete active linkprop before this active link is deleted. + */ + (void) dladm_set_linkprop(vlanid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + } + + (void) dladm_destroy_datalink_id(vlanid, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); + + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(vlanid); + + return (status); +} + +/* + * Callback used by dladm_vlan_up() + */ +static int +i_dladm_vlan_up(datalink_id_t vlanid, void *arg) +{ + dladm_vlan_attr_t dva; + dld_ioc_create_vlan_t dic; + dladm_status_t *statusp = arg; + uint32_t flags; + int fd; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &dva, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Validate (and delete) the link associated with this VLAN, see if + * the specific hardware has been removed during system shutdown. + */ + if ((status = dladm_datalink_id2info(dva.dv_linkid, &flags, NULL, + NULL, NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + + if (!(flags & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + goto done; + } + + dic.dic_linkid = dva.dv_linkid; + dic.dic_force = dva.dv_force; + dic.dic_vid = dva.dv_vid; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + + dic.dic_vlanid = vlanid; + if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, sizeof (dic)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + + if ((status = dladm_up_datalink_id(vlanid)) != DLADM_STATUS_OK) { + dld_ioc_delete_vlan_t did; + + did.did_linkid = vlanid; + (void) i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, + sizeof (did)); + } else { + /* + * Reset the active linkprop of this specific link. + */ + (void) dladm_init_linkprop(vlanid); + } + + (void) close(fd); +done: + *statusp = status; + return (DLADM_WALK_CONTINUE); +} + +/* + * Bring up one VLAN, or all persistent VLANs. In the latter case, the + * walk may terminate early if bringup of a VLAN fails. + */ +dladm_status_t +dladm_vlan_up(datalink_id_t linkid) +{ + dladm_status_t status; + + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_vlan_up, &status, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_vlan_up(linkid, &status); + return (status); + } +} diff --git a/usr/src/lib/libdladm/common/libdlvlan.h b/usr/src/lib/libdladm/common/libdlvlan.h new file mode 100644 index 0000000000..7a305443df --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlvlan.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef _LIBDLVLAN_H +#define _LIBDLVLAN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file includes structures, macros and routines used by VLAN link + * administration. + */ + +#include <libdladm.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dladm_vlan_attr { + uint16_t dv_vid; + datalink_id_t dv_linkid; + boolean_t dv_force; + boolean_t dv_implicit; +} dladm_vlan_attr_t; + +extern dladm_status_t dladm_vlan_info(datalink_id_t, dladm_vlan_attr_t *, + uint32_t); +extern dladm_status_t dladm_vlan_create(const char *, datalink_id_t, + uint16_t, uint32_t); +extern dladm_status_t dladm_vlan_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_vlan_up(datalink_id_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDLVLAN_H */ diff --git a/usr/src/lib/libdladm/common/libdlvnic.c b/usr/src/lib/libdladm/common/libdlvnic.c index da9d57cd1b..272763b61d 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.c +++ b/usr/src/lib/libdladm/common/libdlvnic.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. */ @@ -39,6 +39,7 @@ #include <net/if_types.h> #include <net/if_dl.h> #include <libdladm_impl.h> +#include <libdllink.h> #include <libdlvnic.h> /* @@ -47,51 +48,19 @@ #define VNIC_DEV "/devices/pseudo/vnic@0:" VNIC_CTL_NODE_NAME -/* - * Because by default the id is used as the DLPI device PPA and default - * VLAN PPA's are calculated as ((1000 * vid) + PPA), the largest id - * can't be > 999. We reserve the last 100 VNIC ids for automatic - * VNIC id assignment. - */ -#define DLADM_VNIC_MIN_VNIC_ID 1 /* total range */ -#define DLADM_VNIC_MAX_VNIC_ID 999 -#define DLADM_VNIC_MIN_VNIC_SPEC_ID 1 /* specified by user */ -#define DLADM_VNIC_MAX_VNIC_SPEC_ID 899 -#define DLADM_VNIC_MIN_VNIC_AUTO_ID 900 /* picked automatically */ -#define DLADM_VNIC_MAX_VNIC_AUTO_ID 999 - -#define DLADM_VNIC_NUM_VNIC_AUTO_ID (DLADM_VNIC_MAX_VNIC_AUTO_ID - \ - DLADM_VNIC_MIN_VNIC_AUTO_ID + 1) - /* Limits on buffer size for VNIC_IOC_INFO request */ #define MIN_INFO_SIZE (4*1024) #define MAX_INFO_SIZE (128*1024) /* configuration database entry */ typedef struct dladm_vnic_attr_db { - uint_t vt_vnic_id; - char vt_dev_name[MAXNAMELEN]; + datalink_id_t vt_vnic_id; + datalink_id_t vt_link_id; vnic_mac_addr_type_t vt_mac_addr_type; uint_t vt_mac_len; uchar_t vt_mac_addr[MAXMACADDRLEN]; } dladm_vnic_attr_db_t; -typedef struct dladm_vnic_up { - uint_t vu_vnic_id; - boolean_t vu_found; - int vu_fd; -} dladm_vnic_up_t; - -typedef struct dladm_vnic_down { - uint32_t vd_vnic_id; - boolean_t vd_found; -} dladm_vnic_down_t; - -typedef struct dladm_vnic_modify { - uint32_t vm_vnic_id; - boolean_t vm_found; -} dladm_vnic_modify_t; - typedef struct dladm_vnic_modify_attr { vnic_mac_addr_type_t vm_mac_addr_type; int vm_mac_len; @@ -108,7 +77,7 @@ i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) vnic_ioc_create_t ioc; ioc.vc_vnic_id = attr->vt_vnic_id; - bcopy(attr->vt_dev_name, ioc.vc_dev_name, MAXNAMELEN); + ioc.vc_link_id = attr->vt_link_id; ioc.vc_mac_addr_type = attr->vt_mac_addr_type; ioc.vc_mac_len = attr->vt_mac_len; bcopy(attr->vt_mac_addr, ioc.vc_mac_addr, attr->vt_mac_len); @@ -122,31 +91,10 @@ i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) } /* - * Invoked to bring up a VNIC. - */ -static dladm_status_t -i_dladm_vnic_up(void *arg, dladm_vnic_attr_db_t *attr) -{ - dladm_vnic_up_t *up = (dladm_vnic_up_t *)arg; - dladm_status_t status; - - if (up->vu_vnic_id != 0 && up->vu_vnic_id != attr->vt_vnic_id) - return (DLADM_STATUS_OK); - - up->vu_found = B_TRUE; - - status = i_dladm_vnic_create_sys(up->vu_fd, attr); - if ((status != DLADM_STATUS_OK) && (up->vu_vnic_id != 0)) - return (status); - - return (DLADM_STATUS_OK); -} - -/* * Send a modify command to the VNIC driver. */ static dladm_status_t -i_dladm_vnic_modify_sys(uint_t vnic_id, uint32_t modify_mask, +i_dladm_vnic_modify_sys(datalink_id_t vnic_id, uint32_t modify_mask, dladm_vnic_modify_attr_t *attr) { int rc; @@ -177,75 +125,49 @@ i_dladm_vnic_modify_sys(uint_t vnic_id, uint32_t modify_mask, } /* - * Walk through the vnics defined on the system and for each vnic <vnic>, - * invoke <fn>(<arg>, <vnic>); + * Get the configuration information of the given VNIC. */ dladm_status_t -dladm_vnic_walk_sys(dladm_status_t (*fn)(void *, dladm_vnic_attr_sys_t *), - void *arg) +dladm_vnic_info(datalink_id_t vnic_id, dladm_vnic_attr_sys_t *attrp, + uint32_t flags) { vnic_ioc_info_t *ioc; vnic_ioc_info_vnic_t *vnic; - dladm_vnic_attr_sys_t attr; - int rc, i, bufsize, fd; - char *where; + int rc, bufsize, fd; dladm_status_t status = DLADM_STATUS_OK; + /* for now, only temporary creations are supported */ + if (flags & DLADM_OPT_PERSIST) + return (dladm_errno2status(ENOTSUP)); + if ((fd = open(VNIC_DEV, O_RDWR)) == -1) return (dladm_errno2status(errno)); - bufsize = MIN_INFO_SIZE; + bufsize = sizeof (vnic_ioc_info_t) + sizeof (vnic_ioc_info_vnic_t); ioc = (vnic_ioc_info_t *)calloc(1, bufsize); if (ioc == NULL) { (void) close(fd); return (dladm_errno2status(ENOMEM)); } -tryagain: - + ioc->vi_vnic_id = vnic_id; rc = i_dladm_ioctl(fd, VNIC_IOC_INFO, ioc, bufsize); - if (rc != 0) { - if (errno == ENOSPC) { - bufsize *= 2; - if (bufsize <= MAX_INFO_SIZE) { - ioc = (vnic_ioc_info_t *)realloc(ioc, bufsize); - if (ioc != NULL) { - bzero(ioc, bufsize); - goto tryagain; - } - } - } status = dladm_errno2status(errno); goto bail; } - /* - * Go through each vnic returned by the vnic driver - */ - where = (char *)(ioc + 1); - - for (i = 0; i < ioc->vi_nvnics; i++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - vnic = (vnic_ioc_info_vnic_t *)where; - - attr.va_vnic_id = vnic->vn_vnic_id; - bcopy(vnic->vn_dev_name, attr.va_dev_name, - MAXNAMELEN); - attr.va_mac_addr_type = vnic->vn_mac_addr_type; - bcopy(vnic->vn_mac_addr, attr.va_mac_addr, ETHERADDRL); - attr.va_mac_len = vnic->vn_mac_len; - where = (char *)(vnic + 1); - - status = fn(arg, &attr); - if (status != DLADM_STATUS_OK) - goto bail; - } + vnic = (vnic_ioc_info_vnic_t *)(ioc + 1); + + attrp->va_vnic_id = vnic->vn_vnic_id; + attrp->va_link_id = vnic->vn_link_id; + attrp->va_mac_addr_type = vnic->vn_mac_addr_type; + bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, ETHERADDRL); + attrp->va_mac_len = vnic->vn_mac_len; bail: free(ioc); (void) close(fd); - return (status); } @@ -269,34 +191,6 @@ i_dladm_vnic_delete_sys(int fd, dladm_vnic_attr_sys_t *attr) } /* - * Invoked to bring down a VNIC. - */ -static dladm_status_t -i_dladm_vnic_down(void *arg, dladm_vnic_attr_sys_t *attr) -{ - dladm_vnic_down_t *down = (dladm_vnic_down_t *)arg; - int fd; - dladm_status_t status; - - if (down->vd_vnic_id != 0 && down->vd_vnic_id != attr->va_vnic_id) - return (DLADM_STATUS_OK); - - down->vd_found = B_TRUE; - - if ((fd = open(VNIC_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - status = i_dladm_vnic_delete_sys(fd, attr); - if ((status != DLADM_STATUS_OK) && (down->vd_vnic_id != 0)) { - (void) close(fd); - return (status); - } - - (void) close(fd); - return (DLADM_STATUS_OK); -} - -/* * Convert between MAC address types and their string representations. */ @@ -311,9 +205,12 @@ static dladm_vnic_addr_type_t addr_types[] = { #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) -/* returns B_TRUE if a matching type was found, B_FALSE otherwise */ -boolean_t -dladm_vnic_mac_addr_str_to_type(const char *str, vnic_mac_addr_type_t *val) +/* + * Return DLADM_STATUS_OK if a matching type was found, + * DLADM_STATUS_BADARG otherwise + */ +dladm_status_t +dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) { int i; dladm_vnic_addr_type_t *type; @@ -322,127 +219,34 @@ dladm_vnic_mac_addr_str_to_type(const char *str, vnic_mac_addr_type_t *val) type = &addr_types[i]; if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { *val = type->va_type; - return (B_TRUE); + return (DLADM_STATUS_OK); } } - return (B_FALSE); -} - -/* - * Select a VNIC id automatically. - */ - -typedef struct dladm_vnic_auto_state_s { - uint_t as_nslots; - uint_t *as_slots; -} dladm_vnic_auto_state_t; - -static dladm_status_t -i_dladm_vnic_create_auto_walker(void *arg, dladm_vnic_attr_sys_t *attr) -{ - dladm_vnic_auto_state_t *state = arg; - - if (attr->va_vnic_id < DLADM_VNIC_MIN_VNIC_AUTO_ID || - attr->va_vnic_id > DLADM_VNIC_MAX_VNIC_AUTO_ID) - return (DLADM_STATUS_OK); - - state->as_slots[state->as_nslots++] = attr->va_vnic_id; - - return (DLADM_STATUS_OK); -} - -static int -i_dladm_vnic_compare(const void *p1, const void *p2) -{ - uint_t i = *((uint_t *)p1); - uint_t j = *((uint_t *)p2); - - if (i > j) - return (1); - if (i < j) - return (-1); - return (0); -} - -/*ARGSUSED*/ -static dladm_status_t -i_dladm_vnic_get_auto_id(dladm_vnic_attr_db_t *attr, uint32_t *vnic_id_out) -{ - dladm_vnic_auto_state_t state; - uint_t vnic_ids[DLADM_VNIC_NUM_VNIC_AUTO_ID]; - int i; - uint_t last_id, vnic_id; - dladm_status_t status; - - /* - * Build a sorted array containing the existing VNIC ids in the range - * allocated for automatic allocation. - */ - state.as_nslots = 0; - state.as_slots = vnic_ids; - - status = dladm_vnic_walk_sys(i_dladm_vnic_create_auto_walker, &state); - if (status != DLADM_STATUS_OK) - return (status); - - qsort(vnic_ids, state.as_nslots, sizeof (uint_t), - i_dladm_vnic_compare); - - /* - * Find a gap in the sequence of existing VNIC ids. - */ - last_id = DLADM_VNIC_MIN_VNIC_AUTO_ID - 1; - vnic_id = 0; - for (i = 0; i < state.as_nslots; i++) { - if (vnic_ids[i] > (last_id + 1)) { - vnic_id = last_id + 1; - break; - } - last_id = vnic_ids[i]; - } - - if (vnic_id == 0) { - /* - * Did not find a gap between existing entries, see if we - * can add one. - */ - if (last_id + 1 > DLADM_VNIC_MAX_VNIC_AUTO_ID) - return (DLADM_STATUS_AUTOIDNOAVAILABLEID); - - /* still have room for one more VNIC */ - vnic_id = last_id + 1; - } - - *vnic_id_out = vnic_id; - - return (DLADM_STATUS_OK); + return (DLADM_STATUS_BADARG); } /* * Create a new VNIC. Update the configuration file and bring it up. */ dladm_status_t -dladm_vnic_create(uint_t vnic_id, char *dev_name, +dladm_vnic_create(const char *vnic, datalink_id_t linkid, vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, - uint_t *vnic_id_out, uint32_t flags) + datalink_id_t *vnic_id_out, uint32_t flags) { dladm_vnic_attr_db_t attr; - int i; - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - boolean_t autoid = ((flags & DLADM_VNIC_OPT_AUTOID) != 0); - dladm_vnic_up_t up; + int i, fd; + datalink_id_t vnic_id; + datalink_class_t class; + uint32_t media; + char *name = (char *)vnic; dladm_status_t status; /* * Sanity test arguments. */ - if (autoid && !tempop) - return (DLADM_STATUS_AUTOIDNOTEMP); - - if (!autoid && ((vnic_id < DLADM_VNIC_MIN_VNIC_SPEC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_SPEC_ID))) - return (DLADM_STATUS_INVALIDID); + if (flags & DLADM_OPT_PERSIST) + return (dladm_errno2status(ENOTSUP)); if (mac_len > MAXMACADDRLEN) return (DLADM_STATUS_INVALIDMACADDRLEN); @@ -454,40 +258,46 @@ dladm_vnic_create(uint_t vnic_id, char *dev_name, if (i == NADDR_TYPES) return (DLADM_STATUS_INVALIDMACADDRTYPE); - /* for now, only temporary creations are supported */ - if (!tempop) - return (dladm_errno2status(ENOTSUP)); + if ((status = dladm_datalink_id2info(linkid, NULL, &class, &media, + NULL, 0)) != DLADM_STATUS_OK) { + return (status); + } -auto_again: - if (autoid) { - /* - * Find an unused VNIC id. - */ - status = i_dladm_vnic_get_auto_id(&attr, vnic_id_out); - if (status != DLADM_STATUS_OK) - return (status); - vnic_id = *vnic_id_out; + if (class == DATALINK_CLASS_VNIC) + return (DLADM_STATUS_BADARG); + + if (vnic == NULL) { + flags |= DLADM_OPT_PREFIX; + name = "vnic"; + } + + if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_VNIC, + media, flags, &vnic_id)) != DLADM_STATUS_OK) { + return (status); } bzero(&attr, sizeof (attr)); attr.vt_vnic_id = vnic_id; - (void) strncpy(attr.vt_dev_name, dev_name, - sizeof (attr.vt_dev_name) - 1); + attr.vt_link_id = linkid; attr.vt_mac_addr_type = mac_addr_type; attr.vt_mac_len = mac_len; bcopy(mac_addr, attr.vt_mac_addr, mac_len); - up.vu_vnic_id = vnic_id; - up.vu_found = B_FALSE; - up.vu_fd = open(VNIC_DEV, O_RDWR); - if (up.vu_fd < 0) - return (dladm_errno2status(errno)); + if ((fd = open(VNIC_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } - status = i_dladm_vnic_up((void *)&up, &attr); - (void) close(up.vu_fd); + status = i_dladm_vnic_create_sys(fd, &attr); + (void) close(fd); - if ((status == DLADM_STATUS_EXIST) && autoid) - goto auto_again; +done: + if (status != DLADM_STATUS_OK) { + (void) dladm_destroy_datalink_id(vnic_id, + flags & ~DLADM_OPT_PREFIX); + } else { + *vnic_id_out = vnic_id; + } return (status); } @@ -496,19 +306,14 @@ auto_again: * Modify the properties of a VNIC. */ dladm_status_t -dladm_vnic_modify(uint_t vnic_id, uint32_t modify_mask, +dladm_vnic_modify(datalink_id_t vnic_id, uint32_t modify_mask, vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, uint32_t flags) { dladm_vnic_modify_attr_t new_attr; - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - - if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) - return (DLADM_STATUS_INVALIDID); /* for now, only temporary creations are supported */ - if (!tempop) + if (flags & DLADM_OPT_PERSIST) return (dladm_errno2status(ENOTSUP)); bzero(&new_attr, sizeof (new_attr)); @@ -523,27 +328,30 @@ dladm_vnic_modify(uint_t vnic_id, uint32_t modify_mask, return (i_dladm_vnic_modify_sys(vnic_id, modify_mask, &new_attr)); } - /* * Delete a VNIC. */ dladm_status_t -dladm_vnic_delete(uint_t vnic_id, uint32_t flags) +dladm_vnic_delete(datalink_id_t vnic_id, uint32_t flags) { - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - dladm_vnic_down_t down; + dladm_status_t status; dladm_vnic_attr_sys_t sys_attr; - - if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) - return (DLADM_STATUS_INVALIDID); + int fd; /* for now, only temporary deletes are supported */ - if (!tempop) + if (flags & DLADM_OPT_PERSIST) return (dladm_errno2status(ENOTSUP)); - down.vd_vnic_id = vnic_id; - down.vd_found = B_FALSE; + if ((fd = open(VNIC_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + sys_attr.va_vnic_id = vnic_id; - return (i_dladm_vnic_down((void *)&down, &sys_attr)); + status = i_dladm_vnic_delete_sys(fd, &sys_attr); + (void) close(fd); + + if (status != DLADM_STATUS_OK) + return (status); + + (void) dladm_destroy_datalink_id(vnic_id, flags); + return (status); } diff --git a/usr/src/lib/libdladm/common/libdlvnic.h b/usr/src/lib/libdladm/common/libdlvnic.h index 4f0726746c..79b4b01ba2 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.h +++ b/usr/src/lib/libdladm/common/libdlvnic.h @@ -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. */ @@ -38,32 +38,26 @@ extern "C" { #endif typedef struct dladm_vnic_attr_sys { - uint_t va_vnic_id; - char va_dev_name[MAXNAMELEN + 1]; + datalink_id_t va_vnic_id; + datalink_id_t va_link_id; vnic_mac_addr_type_t va_mac_addr_type; uchar_t va_mac_addr[ETHERADDRL]; uint_t va_mac_len; } dladm_vnic_attr_sys_t; /* - * General operations flags. - */ -#define DLADM_VNIC_OPT_TEMP 0x00000001 -#define DLADM_VNIC_OPT_AUTOID 0x00000002 - -/* * Modification flags for dladm_vnic_modify(). */ #define DLADM_VNIC_MODIFY_ADDR 0x01 -extern dladm_status_t dladm_vnic_create(uint_t, char *, vnic_mac_addr_type_t, - uchar_t *, int, uint_t *, uint32_t); -extern dladm_status_t dladm_vnic_modify(uint_t, uint32_t, vnic_mac_addr_type_t, - uint_t, uchar_t *, uint32_t); -extern dladm_status_t dladm_vnic_delete(uint_t, uint32_t); -extern dladm_status_t dladm_vnic_walk_sys( - dladm_status_t (*)(void *, dladm_vnic_attr_sys_t *), void *); -extern boolean_t dladm_vnic_mac_addr_str_to_type(const char *, +extern dladm_status_t dladm_vnic_create(const char *, datalink_id_t, + vnic_mac_addr_type_t, uchar_t *, int, uint_t *, uint32_t); +extern dladm_status_t dladm_vnic_modify(datalink_id_t, uint32_t, + vnic_mac_addr_type_t, uint_t, uchar_t *, uint32_t); +extern dladm_status_t dladm_vnic_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_vnic_info(datalink_id_t, dladm_vnic_attr_sys_t *, + uint32_t); +extern dladm_status_t dladm_vnic_str2macaddrtype(const char *, vnic_mac_addr_type_t *); #ifdef __cplusplus diff --git a/usr/src/lib/libdladm/common/libdlwlan.c b/usr/src/lib/libdladm/common/libdlwlan.c index 3819dd5050..6597b84ce0 100644 --- a/usr/src/lib/libdladm/common/libdlwlan.c +++ b/usr/src/lib/libdladm/common/libdlwlan.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. */ @@ -28,163 +28,96 @@ #include <libintl.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> #include <unistd.h> #include <fcntl.h> +#include <stddef.h> #include <string.h> #include <stropts.h> #include <libdevinfo.h> #include <net/if.h> #include <net/if_dl.h> #include <net/if_types.h> +#include <libdlpi.h> +#include <libdllink.h> #include <libscf.h> #include <libdlwlan.h> +#include <libdladm_impl.h> #include <libdlwlan_impl.h> #include <net/wpa.h> -typedef struct val_desc { - char *vd_name; - uint_t vd_val; -} val_desc_t; - -struct prop_desc; - -typedef dladm_status_t wl_pd_getf_t(int, wldp_t *, char **, uint_t *); -typedef dladm_status_t wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t); -typedef dladm_status_t wl_pd_checkf_t(int, wldp_t *, struct prop_desc *, - char **, uint_t, val_desc_t **); -typedef struct prop_desc { - char *pd_name; - val_desc_t pd_defval; - val_desc_t *pd_modval; - uint_t pd_nmodval; - wl_pd_setf_t *pd_set; - wl_pd_getf_t *pd_getmod; - wl_pd_getf_t *pd_get; - wl_pd_checkf_t *pd_check; -} prop_desc_t; - -static int wpa_instance_create(const char *, void *); -static int wpa_instance_delete(const char *); - -static int do_get_bsstype(int, wldp_t *); -static int do_get_essid(int, wldp_t *); -static int do_get_bssid(int, wldp_t *); -static int do_get_signal(int, wldp_t *); -static int do_get_encryption(int, wldp_t *); -static int do_get_authmode(int, wldp_t *); -static int do_get_linkstatus(int, wldp_t *); -static int do_get_esslist(int, wldp_t *); -static int do_get_rate(int, wldp_t *); -static int do_get_phyconf(int, wldp_t *); -static int do_get_powermode(int, wldp_t *); -static int do_get_radio(int, wldp_t *); -static int do_get_mode(int, wldp_t *); -static int do_get_capability(int, wldp_t *); -static int do_get_wpamode(int, wldp_t *); - -static int do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *); -static int do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *); -static int do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *); -static int do_set_essid(int, wldp_t *, dladm_wlan_essid_t *); -static int do_set_createibss(int, wldp_t *, boolean_t *); -static int do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t); -static int do_set_rate(int, wldp_t *, dladm_wlan_rates_t *); -static int do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *); -static int do_set_radio(int, wldp_t *, dladm_wlan_radio_t *); -static int do_set_channel(int, wldp_t *, dladm_wlan_channel_t *); - -static int open_link(const char *); -static int do_scan(int, wldp_t *); -static int do_disconnect(const char *, int, wldp_t *); -static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *); -static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); -static void generate_essid(dladm_wlan_essid_t *); +static dladm_status_t wpa_instance_create(datalink_id_t, void *); +static dladm_status_t wpa_instance_delete(datalink_id_t); + +static dladm_status_t do_get_bsstype(datalink_id_t, wldp_t *); +static dladm_status_t do_get_essid(datalink_id_t, wldp_t *); +static dladm_status_t do_get_bssid(datalink_id_t, wldp_t *); +static dladm_status_t do_get_signal(datalink_id_t, wldp_t *); +static dladm_status_t do_get_encryption(datalink_id_t, wldp_t *); +static dladm_status_t do_get_authmode(datalink_id_t, wldp_t *); +static dladm_status_t do_get_linkstatus(datalink_id_t, wldp_t *); +static dladm_status_t do_get_esslist(datalink_id_t, wldp_t *); +static dladm_status_t do_get_rate(datalink_id_t, wldp_t *); +static dladm_status_t do_get_mode(datalink_id_t, wldp_t *); +static dladm_status_t do_get_capability(datalink_id_t, wldp_t *); +static dladm_status_t do_get_wpamode(datalink_id_t, wldp_t *); + +static dladm_status_t do_set_bsstype(datalink_id_t, dladm_wlan_bsstype_t *); +static dladm_status_t do_set_authmode(datalink_id_t, dladm_wlan_auth_t *); +static dladm_status_t do_set_encryption(datalink_id_t, + dladm_wlan_secmode_t *); +static dladm_status_t do_set_essid(datalink_id_t, dladm_wlan_essid_t *); +static dladm_status_t do_set_createibss(datalink_id_t, boolean_t *); +static dladm_status_t do_set_key(datalink_id_t, dladm_wlan_key_t *, uint_t); +static dladm_status_t do_set_channel(datalink_id_t, dladm_wlan_channel_t *); + +static dladm_status_t do_scan(datalink_id_t, wldp_t *); +static dladm_status_t do_connect(datalink_id_t, wldp_t *, dladm_wlan_attr_t *, + boolean_t, void *, uint_t, int); +static dladm_status_t do_disconnect(datalink_id_t, wldp_t *); +static boolean_t find_val_by_name(const char *, val_desc_t *, + uint_t, uint_t *); +static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); +static void generate_essid(dladm_wlan_essid_t *); static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); - -static wl_pd_getf_t do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, - do_get_powermode_prop, do_get_radio_prop; -static wl_pd_setf_t do_set_rate_prop, do_set_powermode_prop, - do_set_radio_prop; -static wl_pd_checkf_t do_check_prop, do_check_rate; +static dladm_status_t dladm_wlan_validate(datalink_id_t); static val_desc_t linkstatus_vals[] = { - { "disconnected", DLADM_WLAN_LINKSTATUS_DISCONNECTED }, - { "connected", DLADM_WLAN_LINKSTATUS_CONNECTED } + { "disconnected", DLADM_WLAN_LINK_DISCONNECTED }, + { "connected", DLADM_WLAN_LINK_CONNECTED } }; static val_desc_t secmode_vals[] = { - { "none", DLADM_WLAN_SECMODE_NONE }, - { "wep", DLADM_WLAN_SECMODE_WEP }, - { "wpa", DLADM_WLAN_SECMODE_WPA } + { "none", DLADM_WLAN_SECMODE_NONE }, + { "wep", DLADM_WLAN_SECMODE_WEP }, + { "wpa", DLADM_WLAN_SECMODE_WPA } }; static val_desc_t strength_vals[] = { - { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, - { "weak", DLADM_WLAN_STRENGTH_WEAK }, - { "good", DLADM_WLAN_STRENGTH_GOOD }, - { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, - { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } + { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, + { "weak", DLADM_WLAN_STRENGTH_WEAK }, + { "good", DLADM_WLAN_STRENGTH_GOOD }, + { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD}, + { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT} }; static val_desc_t mode_vals[] = { - { "a", DLADM_WLAN_MODE_80211A }, - { "b", DLADM_WLAN_MODE_80211B }, - { "g", DLADM_WLAN_MODE_80211G }, + { "a", DLADM_WLAN_MODE_80211A }, + { "b", DLADM_WLAN_MODE_80211B }, + { "g", DLADM_WLAN_MODE_80211G }, }; static val_desc_t auth_vals[] = { - { "open", DLADM_WLAN_AUTH_OPEN }, - { "shared", DLADM_WLAN_AUTH_SHARED } + { "open", DLADM_WLAN_AUTH_OPEN }, + { "shared", DLADM_WLAN_AUTH_SHARED } }; static val_desc_t bsstype_vals[] = { - { "bss", DLADM_WLAN_BSSTYPE_BSS }, - { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, - { "any", DLADM_WLAN_BSSTYPE_ANY } -}; - -static val_desc_t radio_vals[] = { - { "on", DLADM_WLAN_RADIO_ON }, - { "off", DLADM_WLAN_RADIO_OFF } -}; - -static val_desc_t powermode_vals[] = { - { "off", DLADM_WLAN_PM_OFF }, - { "fast", DLADM_WLAN_PM_FAST }, - { "max", DLADM_WLAN_PM_MAX } + { "bss", DLADM_WLAN_BSSTYPE_BSS }, + { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, + { "any", DLADM_WLAN_BSSTYPE_ANY } }; -#define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) -static prop_desc_t prop_table[] = { - - { "channel", { NULL, 0 }, NULL, 0, - NULL, NULL, do_get_channel_prop, do_check_prop}, - - { "powermode", { "off", DLADM_WLAN_PM_OFF }, powermode_vals, - VALCNT(powermode_vals), - do_set_powermode_prop, NULL, - do_get_powermode_prop, do_check_prop}, - - { "radio", { "on", DLADM_WLAN_RADIO_ON }, radio_vals, - VALCNT(radio_vals), - do_set_radio_prop, NULL, - do_get_radio_prop, do_check_prop}, - - { "speed", { "", 0 }, NULL, 0, - do_set_rate_prop, do_get_rate_mod, - do_get_rate_prop, do_check_rate} -}; -/* - * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all - * rates to be retrieved. However, we cannot increase it at this - * time because it will break binary comatibility with unbundled - * WiFi drivers and utilities. So for now we define an additional - * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. - */ -#define MAX_SUPPORT_RATES 64 -#define DLADM_WLAN_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) #define IS_CONNECTED(gbuf) \ ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED)) @@ -209,38 +142,6 @@ dladm_wlan_wlresult2status(wldp_t *gbuf) return (DLADM_STATUS_FAILED); } -static int -open_link(const char *link) -{ - char linkname[MAXPATHLEN]; - wldp_t *gbuf; - int fd; - - if (link == NULL) - return (-1); - - (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); - if ((fd = open(linkname, O_RDWR)) < 0) - return (-1); - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { - (void) close(fd); - return (-1); - } - - /* - * Check to see if the link is wireless. - */ - if (do_get_bsstype(fd, gbuf) < 0) { - free(gbuf); - (void) close(fd); - return (-1); - } - - free(gbuf); - return (fd); -} - static dladm_wlan_mode_t do_convert_mode(wl_phy_conf_t *phyp) { @@ -259,8 +160,8 @@ do_convert_mode(wl_phy_conf_t *phyp) return (DLADM_WLAN_MODE_NONE); } -static boolean_t -do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) +boolean_t +i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) { wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; @@ -326,16 +227,16 @@ fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) if (attrp->wa_speed > 0) attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; - if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, + if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, &attrp->wa_channel)) attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; } dladm_status_t -dladm_wlan_scan(const char *link, void *arg, +dladm_wlan_scan(datalink_id_t linkid, void *arg, boolean_t (*func)(void *, dladm_wlan_attr_t *)) { - int fd, i; + int i; uint32_t count; wl_ess_conf_t *wlp; wldp_t *gbuf; @@ -343,34 +244,28 @@ dladm_wlan_scan(const char *link, void *arg, dladm_status_t status; boolean_t connected; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } connected = IS_CONNECTED(gbuf); - if (do_scan(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_scan(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (func == NULL) { status = DLADM_STATUS_OK; goto done; } - if (do_get_esslist(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_esslist(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess; count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num; @@ -382,18 +277,16 @@ dladm_wlan_scan(const char *link, void *arg, } if (!connected) { - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + status = do_get_linkstatus(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) - (void) do_disconnect(link, fd, gbuf); + (void) do_disconnect(linkid, gbuf); } status = DLADM_STATUS_OK; done: free(gbuf); - (void) close(fd); return (status); } @@ -507,51 +400,61 @@ append: #define IEEE80211_C_WPA 0x01800000 static dladm_status_t -do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, +do_connect(datalink_id_t linkid, wldp_t *gbuf, dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys, uint_t key_count, int timeout) { - dladm_wlan_secmode_t secmode; - dladm_wlan_auth_t authmode; - dladm_wlan_bsstype_t bsstype; - dladm_wlan_essid_t essid; - boolean_t essid_valid = B_FALSE; - dladm_wlan_channel_t channel; - hrtime_t start; - wl_capability_t *caps; + dladm_wlan_secmode_t secmode; + dladm_wlan_auth_t authmode; + dladm_wlan_bsstype_t bsstype; + dladm_wlan_essid_t essid; + boolean_t essid_valid = B_FALSE; + dladm_status_t status; + dladm_wlan_channel_t channel; + hrtime_t start; + wl_capability_t *caps; if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { channel = attrp->wa_channel; - if (do_set_channel(fd, gbuf, &channel) < 0) + status = do_set_channel(linkid, &channel); + if (status != DLADM_STATUS_OK) goto fail; } secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; - if (do_set_encryption(fd, gbuf, &secmode) < 0) + if ((status = do_set_encryption(linkid, &secmode)) != DLADM_STATUS_OK) goto fail; authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; - if (do_set_authmode(fd, gbuf, &authmode) < 0) + if ((status = do_set_authmode(linkid, &authmode)) != DLADM_STATUS_OK) goto fail; bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; - if (do_set_bsstype(fd, gbuf, &bsstype) < 0) + if ((status = do_set_bsstype(linkid, &bsstype)) != DLADM_STATUS_OK) goto fail; if (secmode == DLADM_WLAN_SECMODE_WEP) { - if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) - return (DLADM_STATUS_BADARG); - if (do_set_key(fd, gbuf, keys, key_count) < 0) + if (keys == NULL || key_count == 0 || + key_count > MAX_NWEPKEYS) { + status = DLADM_STATUS_BADARG; + goto fail; + } + status = do_set_key(linkid, keys, key_count); + if (status != DLADM_STATUS_OK) goto fail; } else if (secmode == DLADM_WLAN_SECMODE_WPA) { - if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) - return (DLADM_STATUS_BADARG); - if (do_get_capability(fd, gbuf) < 0) + if (keys == NULL || key_count == 0 || + key_count > MAX_NWEPKEYS) { + status = DLADM_STATUS_BADARG; + goto fail; + } + status = do_get_capability(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto fail; caps = (wl_capability_t *)(gbuf->wldp_buf); if ((caps->caps & IEEE80211_C_WPA) == 0) @@ -559,10 +462,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, } if (create_ibss) { - if (do_set_channel(fd, gbuf, &channel) < 0) + status = do_set_channel(linkid, &channel); + if (status != DLADM_STATUS_OK) goto fail; - if (do_set_createibss(fd, gbuf, &create_ibss) < 0) + status = do_set_createibss(linkid, &create_ibss); + if (status != DLADM_STATUS_OK) goto fail; if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { @@ -576,9 +481,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, essid_valid = B_TRUE; } - if (!essid_valid) - return (DLADM_STATUS_FAILED); - if (do_set_essid(fd, gbuf, &essid) < 0) + if (!essid_valid) { + status = DLADM_STATUS_FAILED; + goto fail; + } + + if ((status = do_set_essid(linkid, &essid)) != DLADM_STATUS_OK) goto fail; /* @@ -586,11 +494,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, * we need call do_set_essid() first, then call wpa_instance_create(). */ if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) - (void) wpa_instance_create(link, keys); + (void) wpa_instance_create(linkid, keys); start = gethrtime(); for (;;) { - if (do_get_linkstatus(fd, gbuf) < 0) + status = do_get_linkstatus(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto fail; if (IS_CONNECTED(gbuf)) @@ -598,38 +507,38 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); if ((timeout >= 0) && (gethrtime() - start) / - NANOSEC >= timeout) - return (DLADM_STATUS_TIMEDOUT); + NANOSEC >= timeout) { + status = DLADM_STATUS_TIMEDOUT; + goto fail; + } } - return (DLADM_STATUS_OK); + status = DLADM_STATUS_OK; fail: - return (dladm_wlan_wlresult2status(gbuf)); + return (status); } dladm_status_t -dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, +dladm_wlan_connect(datalink_id_t linkid, dladm_wlan_attr_t *attrp, int timeout, void *keys, uint_t key_count, uint_t flags) { - int fd, i; + int i; wldp_t *gbuf = NULL; connect_state_t state = {0, NULL, NULL}; attr_node_t *nodep = NULL; boolean_t create_ibss, set_authmode; dladm_wlan_attr_t **wl_list = NULL; - dladm_status_t status = DLADM_STATUS_FAILED; + dladm_status_t status; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) { status = DLADM_STATUS_ISCONN; @@ -646,8 +555,8 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || (create_ibss && attrp != NULL && (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { - status = do_connect(link, fd, gbuf, attrp, - create_ibss, keys, key_count, timeout); + status = do_connect(linkid, gbuf, attrp, create_ibss, keys, + key_count, timeout); goto done; } @@ -655,7 +564,7 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, state.cs_list = NULL; state.cs_count = 0; - status = dladm_wlan_scan(link, &state, connect_cb); + status = dladm_wlan_scan(linkid, &state, connect_cb); if (status != DLADM_STATUS_OK) goto done; @@ -664,8 +573,8 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, status = DLADM_STATUS_NOTFOUND; goto done; } - status = do_connect(link, fd, gbuf, attrp, create_ibss, - keys, key_count, timeout); + status = do_connect(linkid, gbuf, attrp, create_ibss, keys, + key_count, timeout); goto done; } @@ -686,7 +595,7 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, for (i = 0; i < state.cs_count; i++) { dladm_wlan_attr_t *ap = wl_list[i]; - status = do_connect(link, fd, gbuf, ap, create_ibss, keys, + status = do_connect(linkid, gbuf, ap, create_ibss, keys, key_count, timeout); if (status == DLADM_STATUS_OK) break; @@ -694,15 +603,15 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, if (!set_authmode) { ap->wa_auth = DLADM_WLAN_AUTH_SHARED; ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; - status = do_connect(link, fd, gbuf, ap, create_ibss, - keys, key_count, timeout); + status = do_connect(linkid, gbuf, ap, create_ibss, keys, + key_count, timeout); if (status == DLADM_STATUS_OK) break; } } done: if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) - (void) do_disconnect(link, fd, gbuf); + (void) do_disconnect(linkid, gbuf); while (state.cs_list != NULL) { nodep = state.cs_list; @@ -711,44 +620,36 @@ done: } free(gbuf); free(wl_list); - (void) close(fd); return (status); } dladm_status_t -dladm_wlan_disconnect(const char *link) +dladm_wlan_disconnect(datalink_id_t linkid) { - int fd; wldp_t *gbuf; dladm_status_t status; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_BADARG); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + return (status); if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (!IS_CONNECTED(gbuf)) { status = DLADM_STATUS_NOTCONN; goto done; } - if (do_disconnect(link, fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_disconnect(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) { status = DLADM_STATUS_FAILED; @@ -758,85 +659,12 @@ dladm_wlan_disconnect(const char *link) status = DLADM_STATUS_OK; done: free(gbuf); - (void) close(fd); return (status); } -typedef struct dladm_wlan_linkname { - char wl_name[MAXNAMELEN]; - struct dladm_wlan_linkname *wl_next; -} dladm_wlan_linkname_t; - -typedef struct dladm_wlan_walk { - dladm_wlan_linkname_t *ww_list; - dladm_status_t ww_status; -} dladm_wlan_walk_t; - -/* ARGSUSED */ -static int -append_linkname(di_node_t node, di_minor_t minor, void *arg) -{ - dladm_wlan_walk_t *statep = arg; - dladm_wlan_linkname_t **lastp = &statep->ww_list; - dladm_wlan_linkname_t *wlp = *lastp; - char name[MAXNAMELEN]; - - (void) snprintf(name, MAXNAMELEN, "%s%d", - di_driver_name(node), di_instance(node)); - - while (wlp != NULL) { - if (strcmp(wlp->wl_name, name) == 0) - return (DI_WALK_CONTINUE); - - lastp = &wlp->wl_next; - wlp = wlp->wl_next; - } - if ((wlp = malloc(sizeof (*wlp))) == NULL) { - statep->ww_status = DLADM_STATUS_NOMEM; - return (DI_WALK_CONTINUE); - } - - (void) strlcpy(wlp->wl_name, name, MAXNAMELEN); - wlp->wl_next = NULL; - *lastp = wlp; - - return (DI_WALK_CONTINUE); -} - -dladm_status_t -dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *)) -{ - di_node_t root; - dladm_wlan_walk_t state; - dladm_wlan_linkname_t *wlp, *wlp_next; - boolean_t cont = B_TRUE; - - if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) - return (DLADM_STATUS_FAILED); - - state.ww_list = NULL; - state.ww_status = DLADM_STATUS_OK; - (void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS, - &state, append_linkname); - di_fini(root); - - for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) { - /* - * NOTE: even if (*func)() returns B_FALSE, the loop continues - * since all memory must be freed. - */ - if (cont) - cont = (*func)(arg, wlp->wl_name); - wlp_next = wlp->wl_next; - free(wlp); - } - return (state.ww_status); -} - dladm_status_t -dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) +dladm_wlan_get_linkattr(datalink_id_t linkid, dladm_wlan_linkattr_t *attrp) { - int fd; wldp_t *gbuf; wl_rssi_t signal; wl_bss_type_t bsstype; @@ -844,13 +672,13 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_encryption_t encryption; wl_rates_t *ratesp; dladm_wlan_attr_t *wl_attrp; - dladm_status_t status = DLADM_STATUS_FAILED; + dladm_status_t status; if (attrp == NULL) return (DLADM_STATUS_BADARG); - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; @@ -860,17 +688,16 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) (void) memset(attrp, 0, sizeof (*attrp)); wl_attrp = &attrp->la_wlan_attr; - if (do_get_linkstatus(fd, gbuf) < 0) + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; - if (!IS_CONNECTED(gbuf)) { - attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED; - } else { - attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED; - } + if (!IS_CONNECTED(gbuf)) + attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED; + else + attrp->la_status = DLADM_WLAN_LINK_CONNECTED; - if (do_get_essid(fd, gbuf) < 0) + if ((status = do_get_essid(linkid, gbuf)) != DLADM_STATUS_OK) goto done; (void) strlcpy(wl_attrp->wa_essid.we_bytes, @@ -879,7 +706,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; - if (do_get_bssid(fd, gbuf) < 0) + if ((status = do_get_bssid(linkid, gbuf)) != DLADM_STATUS_OK) goto done; (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf, @@ -887,13 +714,13 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; - if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { + if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) { attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; status = DLADM_STATUS_OK; goto done; } - if (do_get_encryption(fd, gbuf) < 0) + if ((status = do_get_encryption(linkid, gbuf)) != DLADM_STATUS_OK) goto done; encryption = *(wl_encryption_t *)(gbuf->wldp_buf); @@ -914,14 +741,14 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_signal(fd, gbuf) < 0) + if ((status = do_get_signal(linkid, gbuf)) != DLADM_STATUS_OK) goto done; signal = *(wl_rssi_t *)(gbuf->wldp_buf); wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); - if (do_get_rate(fd, gbuf) < 0) + if ((status = do_get_rate(linkid, gbuf)) != DLADM_STATUS_OK) goto done; ratesp = (wl_rates_t *)(gbuf->wldp_buf); @@ -936,7 +763,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; } - if (do_get_authmode(fd, gbuf) < 0) + if ((status = do_get_authmode(linkid, gbuf)) != DLADM_STATUS_OK) goto done; authmode = *(wl_authmode_t *)(gbuf->wldp_buf); @@ -954,7 +781,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_bsstype(fd, gbuf) < 0) + if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK) goto done; bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf); @@ -975,7 +802,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_mode(fd, gbuf) < 0) + if ((status = do_get_mode(linkid, gbuf)) != DLADM_STATUS_OK) goto done; wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf)); @@ -988,231 +815,30 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) done: free(gbuf); - (void) close(fd); return (status); } -boolean_t -dladm_wlan_is_valid(const char *link) -{ - int fd = open_link(link); - - if (fd < 0) - return (B_FALSE); - - (void) close(fd); - return (B_TRUE); -} - -/* ARGSUSED */ -static dladm_status_t -do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, val_desc_t **vdpp) -{ - int i; - val_desc_t *vdp; - - if (pdp->pd_nmodval == 0) - return (DLADM_STATUS_PROPRDONLY); - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - for (i = 0; i < pdp->pd_nmodval; i++) - if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0) - break; - - if (i == pdp->pd_nmodval) - return (DLADM_STATUS_BADVAL); - - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) - return (DLADM_STATUS_NOMEM); - - (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t)); - *vdpp = vdp; - return (DLADM_STATUS_OK); -} - static dladm_status_t -do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp, - char **prop_val, uint_t val_cnt) +dladm_wlan_validate(datalink_id_t linkid) { + wldp_t *gbuf; dladm_status_t status; - val_desc_t *vdp = NULL; - uint_t cnt; - - if (pdp->pd_set == NULL) - return (DLADM_STATUS_PROPRDONLY); - - if (prop_val != NULL) { - status = pdp->pd_check(fd, gbuf, pdp, prop_val, - val_cnt, &vdp); - - if (status != DLADM_STATUS_OK) - return (status); - - cnt = val_cnt; - } else { - if (pdp->pd_defval.vd_name == NULL) - return (DLADM_STATUS_NOTSUP); - - if ((vdp = malloc(sizeof (val_desc_t))) == NULL) - return (DLADM_STATUS_NOMEM); - - *vdp = pdp->pd_defval; - cnt = 1; - } - status = pdp->pd_set(fd, gbuf, vdp, cnt); - if (status == DLADM_STATUS_OK) { - /* - * Some ioctls return 0 but store error code in - * wldp_result. Need to fix them. - */ - if (gbuf->wldp_result != WL_SUCCESS) - status = dladm_wlan_wlresult2status(gbuf); - } - free(vdp); - return (status); -} - -dladm_status_t -dladm_wlan_set_prop(const char *link, const char *prop_name, - char **prop_val, uint_t val_cnt, char **errprop) -{ - int fd, i; - wldp_t *gbuf = NULL; - boolean_t found = B_FALSE; - dladm_status_t status = DLADM_STATUS_OK; - - if ((prop_name == NULL && prop_val != NULL) || - (prop_val != NULL && val_cnt == 0)) - return (DLADM_STATUS_BADARG); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; - dladm_status_t s; - - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; - - found = B_TRUE; - s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt); - - if (prop_name != NULL) { - status = s; - break; - } else { - if (s != DLADM_STATUS_OK && - s != DLADM_STATUS_NOTSUP) { - if (errprop != NULL) - *errprop = pdp->pd_name; - status = s; - break; - } - } - } - if (!found) - status = DLADM_STATUS_NOTFOUND; -done: - free(gbuf); - (void) close(fd); - return (status); -} - -/* ARGSUSED */ -dladm_status_t -dladm_wlan_walk_prop(const char *link, void *arg, - boolean_t (*func)(void *, const char *)) -{ - int i; - - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { - if (!func(arg, prop_table[i].pd_name)) - break; - } - return (DLADM_STATUS_OK); -} - -dladm_status_t -dladm_wlan_get_prop(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cnt) -{ - int fd; - int i; - wldp_t *gbuf; - dladm_status_t status; - uint_t cnt; - prop_desc_t *pdp; - - if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0) - return (DLADM_STATUS_BADARG); - - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) - if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) - break; - - if (i == DLADM_WLAN_MAX_PROPS) - return (DLADM_STATUS_NOTFOUND); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { - status = DLADM_STATUS_NOMEM; + /* + * Check to see if the link is wireless. + */ + if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK) { + status = DLADM_STATUS_LINKINVAL; goto done; } - pdp = &prop_table[i]; - status = DLADM_STATUS_OK; - switch (type) { - case DLADM_PROP_VAL_CURRENT: - status = pdp->pd_get(fd, gbuf, prop_val, val_cnt); - break; - - case DLADM_PROP_VAL_DEFAULT: - if (pdp->pd_defval.vd_name == NULL) { - status = DLADM_STATUS_NOTSUP; - break; - } - (void) strcpy(*prop_val, pdp->pd_defval.vd_name); - *val_cnt = 1; - break; - - case DLADM_PROP_VAL_MODIFIABLE: - if (pdp->pd_getmod != NULL) { - status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt); - break; - } - cnt = pdp->pd_nmodval; - if (cnt == 0) { - status = DLADM_STATUS_NOTSUP; - } else if (cnt > *val_cnt) { - status = DLADM_STATUS_TOOSMALL; - } else { - for (i = 0; i < cnt; i++) { - (void) strcpy(prop_val[i], - pdp->pd_modval[i].vd_name); - } - *val_cnt = cnt; - } - break; - default: - status = DLADM_STATUS_BADARG; - break; - } done: free(gbuf); - (void) close(fd); return (status); } @@ -1422,19 +1048,45 @@ dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) { uint_t val; - if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals), - &val)) + if (!find_val_by_name(str, linkstatus_vals, + VALCNT(linkstatus_vals), &val)) { return (DLADM_STATUS_BADARG); + } *linkstatus = (dladm_wlan_linkstatus_t)val; return (DLADM_STATUS_OK); } -static int -do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) +dladm_status_t +i_dladm_wlan_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id, size_t len, + uint_t cmd, size_t cmdlen) { - int rc; + char linkname[MAXPATHLEN]; + int fd, rc; struct strioctl stri; + uint32_t flags; + dladm_status_t status; + uint32_t media; + char link[MAXLINKNAMELEN]; + + if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { + return (status); + } + + if (media != DL_WIFI) + return (DLADM_STATUS_BADARG); + + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_TEMPONLY); + + /* + * dlpi_open() is not used here because libdlpi depends on libdladm, + * and we do not want to introduce recursive dependencies. + */ + (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link); + if ((fd = open(linkname, O_RDWR)) < 0) + return (DLADM_STATUS_LINKINVAL); gbuf->wldp_type = NET_802_11; gbuf->wldp_id = id; @@ -1446,250 +1098,140 @@ do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) stri.ic_len = cmdlen; if ((rc = ioctl(fd, I_STR, &stri)) != 0) { - if (rc > 0) - errno = rc; - return (-1); + if (rc > 0) { + /* + * Non-negative return value indicates the specific + * operation failed and the reason for the failure + * was stored in gbuf->wldp_result. + */ + status = dladm_wlan_wlresult2status(gbuf); + } else { + /* + * Negative return value indicates the ioctl failed. + */ + status = dladm_errno2status(errno); + } } - return (0); + (void) close(fd); + return (status); } -static int -do_get_ioctl(int fd, wldp_t *gbuf, uint_t id) +dladm_status_t +i_dladm_wlan_get_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM, - MAX_BUF_LEN)); + return (i_dladm_wlan_ioctl(linkid, gbuf, id, MAX_BUF_LEN, + WLAN_GET_PARAM, MAX_BUF_LEN)); } -static int -do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen) +dladm_status_t +i_dladm_wlan_set_ioctl(datalink_id_t linkid, uint_t id, void *buf, + uint_t buflen) { + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + (void) memset(gbuf, 0, MAX_BUF_LEN); (void) memcpy(gbuf->wldp_buf, buf, buflen); buflen += WIFI_BUF_OFFSET; - return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen)); + status = i_dladm_wlan_ioctl(linkid, gbuf, id, buflen, + WLAN_SET_PARAM, buflen); + + free(gbuf); + return (status); } -static int -do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd) +static dladm_status_t +do_cmd_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t cmd) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND, - sizeof (wldp_t))); + return (i_dladm_wlan_ioctl(linkid, gbuf, cmd, sizeof (wldp_t), + WLAN_COMMAND, sizeof (wldp_t))); } -static int -do_scan(int fd, wldp_t *gbuf) +static dladm_status_t +do_scan(datalink_id_t linkid, wldp_t *gbuf) { - return (do_cmd_ioctl(fd, gbuf, WL_SCAN)); + return (do_cmd_ioctl(linkid, gbuf, WL_SCAN)); } -static int -do_disconnect(const char *link, int fd, wldp_t *gbuf) +static dladm_status_t +do_disconnect(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> - wldp_buf))->wpa_flag > 0) - (void) wpa_instance_delete(link); + if (do_get_wpamode(linkid, gbuf) == 0 && + ((wl_wpa_t *)(gbuf->wldp_buf))->wpa_flag > 0) + (void) wpa_instance_delete(linkid); - return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE)); + return (do_cmd_ioctl(linkid, gbuf, WL_DISASSOCIATE)); } -static int -do_get_esslist(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_esslist(datalink_id_t linkid, wldp_t *gbuf) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN, + return (i_dladm_wlan_ioctl(linkid, gbuf, WL_ESS_LIST, MAX_BUF_LEN, WLAN_GET_PARAM, sizeof (wldp_t))); } -static int -do_get_bssid(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_BSSID)); -} - -static int -do_get_essid(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_ESSID)); -} - -static int -do_get_bsstype(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE)); -} - -static int -do_get_linkstatus(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS)); -} - -static int -do_get_rate(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES)); -} - -static int -do_get_phyconf(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); -} - -static int -do_get_powermode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_POWER_MODE)); -} - -static int -do_get_radio(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_RADIO)); -} - -static int -do_get_authmode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE)); -} - -static int -do_get_encryption(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_bssid(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSSID)); } -static int -do_get_signal(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_essid(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_RSSI)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ESSID)); } -static int -do_get_mode(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_bsstype(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSS_TYPE)); } static dladm_status_t -do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_linkstatus(datalink_id_t linkid, wldp_t *gbuf) { - wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; - uint_t cnt = wrp->wl_rates_num; - uint_t i; - - if (cnt > *val_cnt) - return (DLADM_STATUS_TOOSMALL); - if (wrp->wl_rates_rates[0] == 0) { - prop_val[0][0] = '\0'; - *val_cnt = 1; - return (DLADM_STATUS_OK); - } - - for (i = 0; i < cnt; i++) { - (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", - wrp->wl_rates_rates[i] % 2, - (float)wrp->wl_rates_rates[i] / 2); - } - *val_cnt = cnt; - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_LINKSTATUS)); } static dladm_status_t -do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_rate(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_rate(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (do_get_rate_common(gbuf, prop_val, val_cnt)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_DESIRED_RATES)); } static dladm_status_t -do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_authmode(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0) - return (DLADM_STATUS_FAILED); - - return (do_get_rate_common(gbuf, prop_val, val_cnt)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_AUTH_MODE)); } static dladm_status_t -do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_encryption(datalink_id_t linkid, wldp_t *gbuf) { - uint32_t channel; - - if (do_get_phyconf(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel)) - return (DLADM_STATUS_NOTFOUND); - - (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ENCRYPTION)); } static dladm_status_t -do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_signal(datalink_id_t linkid, wldp_t *gbuf) { - wl_ps_mode_t *mode; - const char *s; - - if (do_get_powermode(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - mode = (wl_ps_mode_t *)(gbuf->wldp_buf); - switch (mode->wl_ps_mode) { - case WL_PM_AM: - s = "off"; - break; - case WL_PM_MPS: - s = "max"; - break; - case WL_PM_FAST: - s = "fast"; - break; - default: - return (DLADM_STATUS_NOTFOUND); - } - (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RSSI)); } static dladm_status_t -do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_mode(datalink_id_t linkid, wldp_t *gbuf) { - wl_radio_t radio; - const char *s; - - if (do_get_radio(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - radio = *(wl_radio_t *)(gbuf->wldp_buf); - switch (radio) { - case B_TRUE: - s = "on"; - break; - case B_FALSE: - s = "off"; - break; - default: - return (DLADM_STATUS_NOTFOUND); - } - (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); } -static int -do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) +static dladm_status_t +do_set_bsstype(datalink_id_t linkid, dladm_wlan_bsstype_t *bsstype) { wl_bss_type_t ibsstype; @@ -1704,12 +1246,12 @@ do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) ibsstype = WL_BSS_ANY; break; } - return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype, + return (i_dladm_wlan_set_ioctl(linkid, WL_BSS_TYPE, &ibsstype, sizeof (ibsstype))); } -static int -do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) +static dladm_status_t +do_set_authmode(datalink_id_t linkid, dladm_wlan_auth_t *auth) { wl_authmode_t auth_mode; @@ -1721,14 +1263,14 @@ do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) auth_mode = WL_SHAREDKEY; break; default: - return (-1); + return (DLADM_STATUS_NOTSUP); } - return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode, + return (i_dladm_wlan_set_ioctl(linkid, WL_AUTH_MODE, &auth_mode, sizeof (auth_mode))); } -static int -do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) +static dladm_status_t +do_set_encryption(datalink_id_t linkid, dladm_wlan_secmode_t *secmode) { wl_encryption_t encryption; @@ -1742,14 +1284,14 @@ do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) case DLADM_WLAN_SECMODE_WPA: return (0); default: - return (-1); + return (DLADM_STATUS_NOTSUP); } - return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption, + return (i_dladm_wlan_set_ioctl(linkid, WL_ENCRYPTION, &encryption, sizeof (encryption))); } -static int -do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, +static dladm_status_t +do_set_key(datalink_id_t linkid, dladm_wlan_key_t *keys, uint_t key_count) { int i; @@ -1758,7 +1300,7 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, dladm_wlan_key_t *kp; if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) - return (-1); + return (DLADM_STATUS_BADARG); (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); for (i = 0; i < MAX_NWEPKEYS; i++) @@ -1767,10 +1309,10 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, for (i = 0; i < key_count; i++) { kp = &keys[i]; if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) - return (-1); + return (DLADM_STATUS_BADARG); if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) - return (-1); + return (DLADM_STATUS_BADARG); wkp = &wepkey_tab[kp->wk_idx - 1]; wkp->wl_wep_operation = WL_ADD; @@ -1778,12 +1320,12 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); } - return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab, + return (i_dladm_wlan_set_ioctl(linkid, WL_WEP_KEY_TAB, &wepkey_tab, sizeof (wepkey_tab))); } -static int -do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) +static dladm_status_t +do_set_essid(datalink_id_t linkid, dladm_wlan_essid_t *essid) { wl_essid_t iessid; @@ -1794,186 +1336,34 @@ do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, sizeof (iessid.wl_essid_essid)); } else { - return (-1); - } - return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid))); -} - -/* ARGSUSED */ -static dladm_status_t -do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, val_desc_t **vdpp) -{ - int i; - uint_t modval_cnt = MAX_SUPPORT_RATES; - char *buf, **modval; - dladm_status_t status; - val_desc_t *vdp = NULL; - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES); - if (buf == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } - - modval = (char **)(void *)buf; - for (i = 0; i < MAX_SUPPORT_RATES; i++) { - modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + - i * DLADM_STRSIZE; - } - - status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); - if (status != DLADM_STATUS_OK) - goto done; - - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } - - for (i = 0; i < modval_cnt; i++) { - if (strcasecmp(*prop_val, modval[i]) == 0) { - vdp->vd_val = (uint_t)(atof(*prop_val) * 2); - status = DLADM_STATUS_OK; - *vdpp = vdp; - vdp = NULL; - break; - } - } - if (i == modval_cnt) - status = DLADM_STATUS_BADVAL; -done: - free(buf); - free(vdp); - return (status); -} - -static dladm_status_t -do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_rates_t rates; - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - rates.wr_cnt = 1; - rates.wr_rates[0] = vdp[0].vd_val; - - if (do_set_rate(fd, gbuf, &rates) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) -{ - int i; - uint_t len; - wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; - - (void) memset(gbuf, 0, MAX_BUF_LEN); - - for (i = 0; i < rates->wr_cnt; i++) - wrp->wl_rates_rates[i] = rates->wr_rates[i]; - wrp->wl_rates_num = rates->wr_cnt; - - len = offsetof(wl_rates_t, wl_rates_rates) + - (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; - return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); -} - -/* ARGSUSED */ -static dladm_status_t -do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; - - if (do_set_powermode(fd, gbuf, &powermode) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) -{ - wl_ps_mode_t ps_mode; - - (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); - - switch (*pm) { - case DLADM_WLAN_PM_OFF: - ps_mode.wl_ps_mode = WL_PM_AM; - break; - case DLADM_WLAN_PM_MAX: - ps_mode.wl_ps_mode = WL_PM_MPS; - break; - case DLADM_WLAN_PM_FAST: - ps_mode.wl_ps_mode = WL_PM_FAST; - break; - default: - return (-1); + return (DLADM_STATUS_BADARG); } - return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, - sizeof (ps_mode))); + return (i_dladm_wlan_set_ioctl(linkid, WL_ESSID, &iessid, + sizeof (iessid))); } -/* ARGSUSED */ static dladm_status_t -do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; - - if (do_set_radio(fd, gbuf, &radio) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) -{ - wl_radio_t r; - - switch (*radio) { - case DLADM_WLAN_RADIO_ON: - r = B_TRUE; - break; - case DLADM_WLAN_RADIO_OFF: - r = B_FALSE; - break; - default: - return (-1); - } - return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); -} - -static int -do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) +do_set_channel(datalink_id_t linkid, dladm_wlan_channel_t *channel) { wl_phy_conf_t phy_conf; if (*channel > MAX_CHANNEL_NUM) - return (-1); + return (DLADM_STATUS_BADVAL); (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; - return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, + return (i_dladm_wlan_set_ioctl(linkid, WL_PHY_CONFIG, &phy_conf, sizeof (phy_conf))); } -static int -do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) +static dladm_status_t +do_set_createibss(datalink_id_t linkid, boolean_t *create_ibss) { wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); - return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); + return (i_dladm_wlan_set_ioctl(linkid, WL_CREATE_IBSS, + &cr, sizeof (cr))); } static void @@ -1984,55 +1374,21 @@ generate_essid(dladm_wlan_essid_t *essid) random()); } -static int -do_get_capability(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); -} - -static int -do_get_wpamode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_WPA)); -} - static dladm_status_t -ioctl_get(const char *link, int id, void *gbuf) +do_get_capability(datalink_id_t linkid, wldp_t *gbuf) { - int fd; - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - (void) do_get_ioctl(fd, gbuf, id); - - (void) close(fd); - return (dladm_wlan_wlresult2status(gbuf)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_CAPABILITY)); } static dladm_status_t -ioctl_set(const char *link, int id, void *buf, uint_t buflen) +do_get_wpamode(datalink_id_t linkid, wldp_t *gbuf) { - int fd; - wldp_t *gbuf; - dladm_status_t status; - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) - return (DLADM_STATUS_NOMEM); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - (void) do_set_ioctl(fd, gbuf, id, buf, buflen); - - (void) close(fd); - status = dladm_wlan_wlresult2status(gbuf); - free(gbuf); - - return (status); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_WPA)); } dladm_status_t -dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, - uint_t *estot) +dladm_wlan_wpa_get_sr(datalink_id_t linkid, dladm_wlan_ess_t *sr, + uint_t escnt, uint_t *estot) { int i, n; wldp_t *gbuf; @@ -2042,7 +1398,7 @@ dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) return (DLADM_STATUS_NOMEM); - status = ioctl_get(link, WL_SCANRESULTS, gbuf); + status = i_dladm_wlan_get_ioctl(linkid, gbuf, WL_SCANRESULTS); if (status == DLADM_STATUS_OK) { es = (wl_wpa_ess_t *)(gbuf->wldp_buf); @@ -2066,8 +1422,7 @@ dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, } dladm_status_t -dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, - uint_t wpa_ie_len) +dladm_wlan_wpa_set_ie(datalink_id_t linkid, uint8_t *wpa_ie, uint_t wpa_ie_len) { wl_wpa_ie_t *ie; uint_t len; @@ -2084,41 +1439,43 @@ dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, ie->wpa_ie_len = wpa_ie_len; (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); - status = ioctl_set(link, WL_SETOPTIE, ie, len); + status = i_dladm_wlan_set_ioctl(linkid, WL_SETOPTIE, ie, len); free(ie); return (status); } dladm_status_t -dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) +dladm_wlan_wpa_set_wpa(datalink_id_t linkid, boolean_t flag) { - wl_wpa_t wpa; + wl_wpa_t wpa; wpa.wpa_flag = flag; - return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_WPA, &wpa, + sizeof (wl_wpa_t))); } dladm_status_t -dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, +dladm_wlan_wpa_del_key(datalink_id_t linkid, uint_t key_idx, const dladm_wlan_bssid_t *addr) { - wl_del_key_t wk; + wl_del_key_t wk; wk.idk_keyix = key_idx; if (addr != NULL) (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, DLADM_WLAN_BSSID_LEN); - return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_DELKEY, &wk, + sizeof (wl_del_key_t))); } dladm_status_t -dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, +dladm_wlan_wpa_set_key(datalink_id_t linkid, dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key, uint_t key_len) { - wl_key_t wk; + wl_key_t wk; (void) memset(&wk, 0, sizeof (wl_key_t)); switch (cipher) { @@ -2155,11 +1512,11 @@ dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ (void) memcpy(wk.ik_keydata, key, key_len); - return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_KEY, &wk, sizeof (wl_key_t))); } dladm_status_t -dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, +dladm_wlan_wpa_set_mlme(datalink_id_t linkid, dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) { wl_mlme_t mlme; @@ -2180,7 +1537,8 @@ dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, DLADM_WLAN_BSSID_LEN); - return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_MLME, &mlme, + sizeof (wl_mlme_t))); } /* @@ -2204,7 +1562,7 @@ add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, return (pg); } -static int +static dladm_status_t add_new_property(scf_handle_t *handle, const char *prop_name, scf_type_t type, const char *val, scf_transaction_t *tx) { @@ -2228,7 +1586,7 @@ add_new_property(scf_handle_t *handle, const char *prop_name, if (scf_entry_add_value(entry, value) != 0) goto out; - return (DLADM_WLAN_SVC_SUCCESS); + return (DLADM_STATUS_OK); out: if (value != NULL) @@ -2236,18 +1594,15 @@ out: if (entry != NULL) scf_entry_destroy(entry); - return (DLADM_WLAN_SVC_FAILURE); + return (DLADM_STATUS_FAILED); } -/* - * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. - */ -static int +static dladm_status_t add_pg_method(scf_handle_t *handle, scf_instance_t *instance, const char *pg_name, const char *flags) { int rv, size; - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *command = NULL; scf_transaction_t *tran = NULL; scf_propertygroup_t *pg; @@ -2264,7 +1619,7 @@ add_pg_method(scf_handle_t *handle, scf_instance_t *instance, size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; command = malloc(size); if (command == NULL) { - status = DLADM_WLAN_SVC_APP_FAILURE; + status = DLADM_STATUS_NOMEM; goto out; } (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); @@ -2274,15 +1629,14 @@ add_pg_method(scf_handle_t *handle, scf_instance_t *instance, goto out; if (add_new_property(handle, SCF_PROPERTY_EXEC, - SCF_TYPE_ASTRING, command, tran) != - DLADM_WLAN_SVC_SUCCESS) { + SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) { goto out; } rv = scf_transaction_commit(tran); switch (rv) { case 1: - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; goto out; case 0: scf_transaction_destroy_children(tran); @@ -2311,11 +1665,11 @@ out: return (status); } -static int +static dladm_status_t do_create_instance(scf_handle_t *handle, scf_service_t *svc, const char *instance_name, const char *command) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *buf; ssize_t max_fmri_len; scf_instance_t *instance; @@ -2327,12 +1681,12 @@ do_create_instance(scf_handle_t *handle, scf_service_t *svc, if (scf_service_add_instance(svc, instance_name, instance) != 0) { if (scf_error() == SCF_ERROR_EXISTS) /* Let the caller deal with the duplicate instance */ - status = DLADM_WLAN_SVC_INSTANCE_EXISTS; + status = DLADM_STATUS_EXIST; goto out; } if (add_pg_method(handle, instance, "start", - command) != DLADM_WLAN_SVC_SUCCESS) { + command) != DLADM_STATUS_OK) { goto out; } @@ -2346,7 +1700,7 @@ do_create_instance(scf_handle_t *handle, scf_service_t *svc, (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { goto out; } - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; } out: @@ -2355,10 +1709,10 @@ out: return (status); } -static int +static dladm_status_t create_instance(const char *instance_name, const char *command) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; scf_service_t *svc = NULL; scf_handle_t *handle = NULL; @@ -2430,10 +1784,10 @@ wait_until_disabled(scf_handle_t *handle, char *fmri) } } -static int +static dladm_status_t delete_instance(const char *instance_name) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *buf; ssize_t max_fmri_len; scf_scope_t *scope = NULL; @@ -2468,7 +1822,7 @@ delete_instance(const char *instance_name) scf_error_t scf_errnum = scf_error(); if (scf_errnum == SCF_ERROR_NOT_FOUND) - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; scf_instance_destroy(instance); goto out; @@ -2503,7 +1857,7 @@ delete_instance(const char *instance_name) scf_instance_destroy(instance); - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; out: if (svc != NULL) @@ -2520,33 +1874,39 @@ out: return (status); } -/* - * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. - */ -static int -wpa_instance_create(const char *instance_name, void *key) +static dladm_status_t +wpa_instance_create(datalink_id_t linkid, void *key) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *command = NULL; char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; int size; + char instance_name[MAXLINKNAMELEN]; + + /* + * Use the link name as the instance name of the network/wpad service. + */ + status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, + sizeof (instance_name)); + if (status != DLADM_STATUS_OK) + goto out; size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; command = malloc(size); if (command == NULL) { - status = DLADM_WLAN_SVC_APP_FAILURE; + status = DLADM_STATUS_NOMEM; goto out; } (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); status = create_instance(instance_name, command); - if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { + if (status == DLADM_STATUS_EXIST) { /* * Delete the existing instance and create a new instance * with the supplied arguments. */ if ((status = delete_instance(instance_name)) == - DLADM_WLAN_SVC_SUCCESS) { + DLADM_STATUS_OK) { status = create_instance(instance_name, command); } } @@ -2558,12 +1918,18 @@ out: return (status); } -static int -wpa_instance_delete(const char *instance_name) +static dladm_status_t +wpa_instance_delete(datalink_id_t linkid) { - int status; + char instance_name[MAXLINKNAMELEN]; - status = delete_instance(instance_name); + /* + * Get the instance name of the network/wpad service (the same as + * the link name). + */ + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, + sizeof (instance_name)) != DLADM_STATUS_OK) + return (DLADM_STATUS_FAILED); - return (status); + return (delete_instance(instance_name)); } diff --git a/usr/src/lib/libdladm/common/libdlwlan.h b/usr/src/lib/libdladm/common/libdlwlan.h index b1729ae658..b784ad73ba 100644 --- a/usr/src/lib/libdladm/common/libdlwlan.h +++ b/usr/src/lib/libdladm/common/libdlwlan.h @@ -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. */ @@ -125,20 +125,13 @@ typedef enum { } dladm_wlan_bsstype_t; typedef enum { - DLADM_WLAN_LINKSTATUS_DISCONNECTED = 1, - DLADM_WLAN_LINKSTATUS_CONNECTED + DLADM_WLAN_LINK_DISCONNECTED = 1, + DLADM_WLAN_LINK_CONNECTED } dladm_wlan_linkstatus_t; typedef uint32_t dladm_wlan_speed_t; typedef uint32_t dladm_wlan_channel_t; -typedef enum { - DLADM_WLAN_SVC_SUCCESS, - DLADM_WLAN_SVC_FAILURE, - DLADM_WLAN_SVC_APP_FAILURE, - DLADM_WLAN_SVC_INSTANCE_EXISTS -} dladm_wlan_svc_status_t; - enum { DLADM_WLAN_ATTR_ESSID = 0x00000001, DLADM_WLAN_ATTR_BSSID = 0x00000002, @@ -186,33 +179,24 @@ typedef struct dladm_wlan_key { uint_t wk_class; } dladm_wlan_key_t; -extern dladm_status_t dladm_wlan_scan(const char *, void *, +extern dladm_status_t dladm_wlan_scan(datalink_id_t, void *, boolean_t (*)(void *, dladm_wlan_attr_t *)); -extern dladm_status_t dladm_wlan_connect(const char *, dladm_wlan_attr_t *, +extern dladm_status_t dladm_wlan_connect(datalink_id_t, dladm_wlan_attr_t *, int, void *, uint_t, uint_t); -extern dladm_status_t dladm_wlan_disconnect(const char *); -extern dladm_status_t dladm_wlan_get_linkattr(const char *, +extern dladm_status_t dladm_wlan_disconnect(datalink_id_t); +extern dladm_status_t dladm_wlan_get_linkattr(datalink_id_t, dladm_wlan_linkattr_t *); -extern dladm_status_t dladm_wlan_walk(void *, - boolean_t (*)(void *, const char *)); -extern boolean_t dladm_wlan_is_valid(const char *); -extern dladm_status_t dladm_wlan_set_prop(const char *, const char *, - char **, uint_t, char **); -extern dladm_status_t dladm_wlan_walk_prop(const char *, void *, - boolean_t (*)(void *, const char *)); -extern dladm_status_t dladm_wlan_get_prop(const char *, dladm_prop_type_t, - const char *, char **, uint_t *); /* WPA support routines */ -extern dladm_status_t dladm_wlan_wpa_get_sr(const char *, - dladm_wlan_ess_t *, uint_t, uint_t *); -extern dladm_status_t dladm_wlan_wpa_set_ie(const char *, uint8_t *, uint_t); -extern dladm_status_t dladm_wlan_wpa_set_wpa(const char *, boolean_t); -extern dladm_status_t dladm_wlan_wpa_del_key(const char *, - uint_t, const dladm_wlan_bssid_t *); -extern dladm_status_t dladm_wlan_wpa_set_key(const char *, +extern dladm_status_t dladm_wlan_wpa_get_sr(datalink_id_t, dladm_wlan_ess_t *, + uint_t, uint_t *); +extern dladm_status_t dladm_wlan_wpa_set_ie(datalink_id_t, uint8_t *, uint_t); +extern dladm_status_t dladm_wlan_wpa_set_wpa(datalink_id_t, boolean_t); +extern dladm_status_t dladm_wlan_wpa_del_key(datalink_id_t, uint_t, + const dladm_wlan_bssid_t *); +extern dladm_status_t dladm_wlan_wpa_set_key(datalink_id_t, dladm_wlan_cipher_t, const dladm_wlan_bssid_t *, boolean_t, uint64_t, uint_t, uint8_t *, uint_t); -extern dladm_status_t dladm_wlan_wpa_set_mlme(const char *, +extern dladm_status_t dladm_wlan_wpa_set_mlme(datalink_id_t, dladm_wlan_mlme_op_t, dladm_wlan_reason_t, dladm_wlan_bssid_t *); diff --git a/usr/src/lib/libdladm/common/libdlwlan_impl.h b/usr/src/lib/libdladm/common/libdlwlan_impl.h index 764a951bed..9611b5319b 100644 --- a/usr/src/lib/libdladm/common/libdlwlan_impl.h +++ b/usr/src/lib/libdladm/common/libdlwlan_impl.h @@ -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. */ @@ -57,10 +57,9 @@ extern "C" { #define DLADM_WLAN_OFDM2CHAN(mhz) (((mhz) - 5000) / 5) #define DLADM_WLAN_CONNECT_POLLRATE 200 /* milliseconds */ -#define DLADM_WLAN_CONNECT_DEFAULT_CHANNEL 1 #define DLADM_WLAN_MAX_RATES 4 -typedef struct dladm_wlan_rates { +typedef struct dladm_wlan_rates { uint8_t wr_rates[DLADM_WLAN_MAX_RATES]; int wr_cnt; } dladm_wlan_rates_t; @@ -70,12 +69,20 @@ typedef enum { DLADM_WLAN_RADIO_OFF } dladm_wlan_radio_t; -typedef enum { +typedef enum { DLADM_WLAN_PM_OFF = 1, DLADM_WLAN_PM_MAX, DLADM_WLAN_PM_FAST } dladm_wlan_powermode_t; +extern dladm_status_t i_dladm_wlan_get_ioctl(datalink_id_t, wldp_t *, + uint_t); +extern dladm_status_t i_dladm_wlan_set_ioctl(datalink_id_t, uint_t, + void *, uint_t); +extern dladm_status_t i_dladm_wlan_ioctl(datalink_id_t, wldp_t *, uint_t, + size_t, uint_t, size_t); +extern boolean_t i_dladm_wlan_convert_chan(wl_phy_conf_t *, uint32_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index e624cec0ec..a05f6ce877 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.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. */ @@ -29,6 +29,7 @@ #include <strings.h> #include <errno.h> #include <ctype.h> +#include <stddef.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dld.h> @@ -39,721 +40,533 @@ #include <zone.h> #include <libdllink.h> #include <libdladm_impl.h> +#include <libdlwlan_impl.h> #include <libdlwlan.h> +#include <libdlvlan.h> #include <dlfcn.h> #include <link.h> +#include <inet/wifi_ioctl.h> -static dladm_status_t i_dladm_set_prop_db(const char *, const char *, - char **, uint_t); -static dladm_status_t i_dladm_get_prop_db(const char *, const char *, - char **, uint_t *); -static dladm_status_t i_dladm_get_prop_temp(const char *, dladm_prop_type_t, - const char *, char **, uint_t *); -static dladm_status_t i_dladm_set_prop_temp(const char *, const char *, - char **, uint_t, uint_t, char **); -static boolean_t i_dladm_is_prop_temponly(const char *prop_name, - char **); +/* + * The linkprop get() callback. + * - propstrp: a property string array to keep the returned property. + * Caller allocated. + * - cntp: number of returned properties. + * Caller also uses it to indicate how many it expects. + */ +typedef dladm_status_t pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp); -typedef struct val_desc { - char *vd_name; - void *vd_val; -} val_desc_t; +/* + * The linkprop set() callback. + * - propval: a val_desc_t array which keeps the property values to be set. + * - cnt: number of properties to be set. + */ +typedef dladm_status_t pd_setf_t(datalink_id_t, val_desc_t *propval, + uint_t cnt); -struct prop_desc; +#define PD_TEMPONLY 0x1 -typedef dladm_status_t pd_getf_t(const char *, char **, uint_t *); -typedef dladm_status_t pd_setf_t(const char *, val_desc_t *, uint_t); -typedef dladm_status_t pd_checkf_t(struct prop_desc *, char **, - uint_t, val_desc_t **); +/* + * The linkprop check() callback. + * - propstrp: property string array which keeps the property to be checked. + * - cnt: number of properties. + * - propval: return value; the property values of the given property strings. + * - dofree: indicates whether the caller needs to free propvalp->vd_val. + */ +typedef dladm_status_t pd_checkf_t(datalink_id_t, char **propstrp, + uint_t cnt, val_desc_t *propval, boolean_t *dofree); -static pd_getf_t do_get_zone; -static pd_setf_t do_set_zone; -static pd_checkf_t do_check_zone; +static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, + do_get_rate_prop, do_get_channel_prop, + do_get_powermode_prop, do_get_radio_prop; +static pd_setf_t do_set_zone, do_set_autopush, do_set_rate_prop, + do_set_powermode_prop, do_set_radio_prop; +static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate; typedef struct prop_desc { - char *pd_name; - val_desc_t pd_defval; - val_desc_t *pd_modval; - uint_t pd_nmodval; - boolean_t pd_temponly; - pd_setf_t *pd_set; - pd_getf_t *pd_getmod; - pd_getf_t *pd_get; - pd_checkf_t *pd_check; + /* + * link property name + */ + char *pd_name; + + /* + * default property value, can be set to { "", NULL } + */ + val_desc_t pd_defval; + + /* + * list of optional property values, can be NULL. + * + * This is set to non-NULL if there is a list of possible property + * values. pd_optval would point to the array of possible values. + */ + val_desc_t *pd_optval; + + /* + * count of the above optional property values. 0 if pd_optval is NULL. + */ + uint_t pd_noptval; + + /* + * callback to set link property; + * set to NULL if this property is read-only + */ + pd_setf_t *pd_set; + + /* + * callback to get modifiable link property + */ + pd_getf_t *pd_getmod; + + /* + * callback to get current link property + */ + pd_getf_t *pd_get; + + /* + * callback to validate link property value, set to NULL if pd_optval + * is not NULL. In that case, validate the value by comparing it with + * the pd_optval. Return a val_desc_t array pointer if the value is + * valid. + */ + pd_checkf_t *pd_check; + + /* + * currently only PD_TEMPONLY is valid, which indicates the property + * is temporary only. + */ + uint_t pd_flags; + + /* + * indicate link classes this property applies to. + */ + datalink_class_t pd_class; + + /* + * indicate link media type this property applies to. + */ + datalink_media_t pd_dmedia; } prop_desc_t; +static val_desc_t dladm_wlan_radio_vals[] = { + { "on", DLADM_WLAN_RADIO_ON }, + { "off", DLADM_WLAN_RADIO_OFF } +}; + +static val_desc_t dladm_wlan_powermode_vals[] = { + { "off", DLADM_WLAN_PM_OFF }, + { "fast", DLADM_WLAN_PM_FAST }, + { "max", DLADM_WLAN_PM_MAX } +}; + static prop_desc_t prop_table[] = { - { "zone", { "", NULL }, NULL, 0, B_TRUE, + + { "channel", { NULL, 0 }, NULL, 0, NULL, NULL, + do_get_channel_prop, NULL, 0, + DATALINK_CLASS_PHYS, DL_WIFI}, + + { "powermode", { "off", DLADM_WLAN_PM_OFF }, + dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), + do_set_powermode_prop, NULL, + do_get_powermode_prop, NULL, 0, + DATALINK_CLASS_PHYS, DL_WIFI}, + + { "radio", { "on", DLADM_WLAN_RADIO_ON }, + dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), + do_set_radio_prop, NULL, + do_get_radio_prop, NULL, 0, + DATALINK_CLASS_PHYS, DL_WIFI}, + + { "speed", { "", 0 }, NULL, 0, + do_set_rate_prop, do_get_rate_mod, + do_get_rate_prop, do_check_rate, 0, + DATALINK_CLASS_PHYS, DL_WIFI}, + + { "autopush", { "", NULL }, NULL, 0, + do_set_autopush, NULL, + do_get_autopush, do_check_autopush, 0, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}, + + { "zone", { "", NULL }, NULL, 0, do_set_zone, NULL, - do_get_zone, do_check_zone} + do_get_zone, do_check_zone, PD_TEMPONLY, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE} }; -#define MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) +#define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) -dladm_status_t -dladm_set_prop(const char *link, const char *prop_name, char **prop_val, - uint_t val_cnt, uint_t flags, char **errprop) -{ - dladm_status_t status = DLADM_STATUS_BADARG; +static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, + char **, uint_t); +static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, + char **, uint_t *); +static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, + uint32_t, prop_desc_t *, char **, uint_t, uint_t); +static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, + char **, uint_t, uint_t); - if (link == NULL || (prop_val == NULL && val_cnt > 0) || - (prop_val != NULL && val_cnt == 0) || flags == 0) - return (DLADM_STATUS_BADARG); +/* + * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all + * rates to be retrieved. However, we cannot increase it at this + * time because it will break binary compatibility with unbundled + * WiFi drivers and utilities. So for now we define an additional + * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. + */ +#define MAX_SUPPORT_RATES 64 - if ((flags & DLADM_OPT_TEMP) != 0) { - status = i_dladm_set_prop_temp(link, prop_name, prop_val, - val_cnt, flags, errprop); - if (status == DLADM_STATUS_TEMPONLY && - (flags & DLADM_OPT_PERSIST) != 0) - return (DLADM_STATUS_TEMPONLY); +#define AP_ANCHOR "[anchor]" +#define AP_DELIMITER '.' - if (status == DLADM_STATUS_NOTFOUND) { - status = DLADM_STATUS_BADARG; - if (dladm_wlan_is_valid(link)) { - status = dladm_wlan_set_prop(link, prop_name, - prop_val, val_cnt, errprop); +static dladm_status_t +do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, + val_desc_t *vdp) +{ + int i, j; + dladm_status_t status = DLADM_STATUS_OK; + + for (j = 0; j < val_cnt; j++) { + for (i = 0; i < pdp->pd_noptval; i++) { + if (strcasecmp(*prop_val, + pdp->pd_optval[i].vd_name) == 0) { + break; } } - if (status != DLADM_STATUS_OK) - return (status); + if (i == pdp->pd_noptval) { + status = DLADM_STATUS_BADVAL; + goto done; + } + (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); } - if ((flags & DLADM_OPT_PERSIST) != 0) { - if (i_dladm_is_prop_temponly(prop_name, errprop)) - return (DLADM_STATUS_TEMPONLY); - status = i_dladm_set_prop_db(link, prop_name, - prop_val, val_cnt); - } +done: return (status); } -dladm_status_t -dladm_walk_prop(const char *link, void *arg, - boolean_t (*func)(void *, const char *)) +static dladm_status_t +i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, + uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, + uint_t flags) { - int i; + dladm_status_t status = DLADM_STATUS_OK; + val_desc_t *vdp = NULL; + boolean_t needfree = B_FALSE; + uint_t cnt, i; - if (link == NULL || func == NULL) + if (!(pdp->pd_class & class)) return (DLADM_STATUS_BADARG); - /* For wifi links, show wifi properties first */ - if (dladm_wlan_is_valid(link)) { - dladm_status_t status; - - status = dladm_wlan_walk_prop(link, arg, func); - if (status != DLADM_STATUS_OK) - return (status); - } - - /* Then show data-link properties if there are any */ - for (i = 0; i < MAX_PROPS; i++) { - if (!func(arg, prop_table[i].pd_name)) - break; - } - return (DLADM_STATUS_OK); -} - -dladm_status_t -dladm_get_prop(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cntp) -{ - dladm_status_t status; - - if (link == NULL || prop_name == NULL || prop_val == NULL || - val_cntp == NULL || *val_cntp == 0) + if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) return (DLADM_STATUS_BADARG); - if (type == DLADM_PROP_VAL_PERSISTENT) { - if (i_dladm_is_prop_temponly(prop_name, NULL)) - return (DLADM_STATUS_TEMPONLY); - return (i_dladm_get_prop_db(link, prop_name, - prop_val, val_cntp)); - } + if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) + return (DLADM_STATUS_TEMPONLY); - status = i_dladm_get_prop_temp(link, type, prop_name, - prop_val, val_cntp); - if (status != DLADM_STATUS_NOTFOUND) - return (status); + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); - if (dladm_wlan_is_valid(link)) { - return (dladm_wlan_get_prop(link, type, prop_name, - prop_val, val_cntp)); - } - return (DLADM_STATUS_BADARG); -} + if (pdp->pd_set == NULL) + return (DLADM_STATUS_PROPRDONLY); -/* - * Data structures used for implementing persistent link properties - */ -typedef struct linkprop_val { - const char *lv_name; - struct linkprop_val *lv_nextval; -} linkprop_val_t; - -typedef struct linkprop_info { - const char *li_name; - struct linkprop_info *li_nextprop; - struct linkprop_val *li_val; -} linkprop_info_t; - -typedef struct linkprop_db_state linkprop_db_state_t; - -typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *, - char *, linkprop_info_t *, dladm_status_t *); - -struct linkprop_db_state { - linkprop_db_op_t ls_op; - const char *ls_link; - const char *ls_propname; - char **ls_propval; - uint_t *ls_valcntp; -}; + if (prop_val != NULL) { + vdp = malloc(sizeof (val_desc_t) * val_cnt); + if (vdp == NULL) + return (DLADM_STATUS_NOMEM); -static void -free_linkprops(linkprop_info_t *lip) -{ - linkprop_info_t *lip_next; - linkprop_val_t *lvp, *lvp_next; - - for (; lip != NULL; lip = lip_next) { - lip_next = lip->li_nextprop; - for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { - lvp_next = lvp->lv_nextval; - free(lvp); + if (pdp->pd_check != NULL) { + status = pdp->pd_check(linkid, prop_val, val_cnt, vdp, + &needfree); + } else if (pdp->pd_optval != NULL) { + status = do_check_prop(pdp, prop_val, val_cnt, vdp); + } else { + status = DLADM_STATUS_BADARG; } - free(lip); - } -} -/* - * Generate an entry in the link property database. - * Each entry has this format: - * <linkname> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>; - */ -static void -generate_linkprop_line(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) -{ - char tmpbuf[MAXLINELEN]; - char *ptr, *lim = tmpbuf + MAXLINELEN; - linkprop_info_t *lip = listp; - linkprop_val_t *lvp = NULL; + if (status != DLADM_STATUS_OK) + goto done; - /* - * Delete line if there are no properties left. - */ - if (lip == NULL || - (lip->li_val == NULL && lip->li_nextprop == NULL)) { - buf[0] = '\0'; - return; - } - ptr = tmpbuf; - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link); - for (; lip != NULL; lip = lip->li_nextprop) { - /* - * Skip properties without values. - */ - if (lip->li_val == NULL) - continue; + cnt = val_cnt; + } else { + if (pdp->pd_defval.vd_name == NULL) + return (DLADM_STATUS_NOTSUP); - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name); - for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c", - lvp->lv_name, - ((lvp->lv_nextval == NULL) ? ';' : ',')); - } + if ((vdp = malloc(sizeof (val_desc_t))) == NULL) + return (DLADM_STATUS_NOMEM); + + (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); + cnt = 1; } - if (ptr > lim) { - *statusp = DLADM_STATUS_TOOSMALL; - return; + status = pdp->pd_set(linkid, vdp, cnt); + if (needfree) { + for (i = 0; i < cnt; i++) + free((void *)(((val_desc_t *)vdp + i)->vd_val)); } - (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); +done: + free(vdp); + return (status); } -/* - * This function is used to update or create an entry in the persistent db. - * process_linkprop_db() will first scan the db for an entry matching the - * specified link. If a match is found, this function is invoked with the - * entry's contents (buf) and its linked-list representation (listp). lsp - * holds the name and values of the property to be added or updated; this - * information will be merged with listp. Subsequently, an updated entry - * will be written to buf, which will in turn be written to disk by - * process_linkprop_db(). If no entry matches the specified link, listp - * will be NULL; a new entry will be generated in this case and it will - * contain only the property information in lsp. - */ -static boolean_t -process_linkprop_set(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +static dladm_status_t +i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t val_cnt, uint_t flags) { - dladm_status_t status; - linkprop_info_t *lastp = NULL, *lip = listp, *nlip = NULL; - linkprop_val_t **lvpp; - int i; - - if (lsp->ls_propname == NULL) { - buf[0] = '\0'; - return (B_FALSE); - } + int i; + boolean_t found = B_FALSE; + datalink_class_t class; + uint32_t media; + dladm_status_t status = DLADM_STATUS_OK; - /* - * Find the linkprop we want to change. - */ - for (; lip != NULL; lip = lip->li_nextprop) { - if (strcmp(lip->li_name, lsp->ls_propname) == 0) - break; + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); - lastp = lip; - } + for (i = 0; i < DLADM_MAX_PROPS; i++) { + prop_desc_t *pdp = &prop_table[i]; + dladm_status_t s; - if (lip == NULL) { - /* - * If the linkprop is not found, append it to the list. - */ - if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) { - status = DLADM_STATUS_NOMEM; - goto fail; - } - /* - * nlip will need to be freed later if there is no list to - * append to. - */ - if (lastp != NULL) - lastp->li_nextprop = nlip; - nlip->li_name = lsp->ls_propname; - nlip->li_nextprop = NULL; - nlip->li_val = NULL; - lvpp = &nlip->li_val; - } else { - linkprop_val_t *lvp, *lvp_next; + if (prop_name != NULL && + (strcasecmp(prop_name, pdp->pd_name) != 0)) + continue; - /* - * If the linkprop is found, delete the existing values from it. - */ - for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { - lvp_next = lvp->lv_nextval; - free(lvp); - } - lip->li_val = NULL; - lvpp = &lip->li_val; - } + found = B_TRUE; + s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, + val_cnt, flags); - /* - * Fill our linkprop with the specified values. - */ - for (i = 0; i < *lsp->ls_valcntp; i++) { - if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) { - status = DLADM_STATUS_NOMEM; - goto fail; + if (prop_name != NULL) { + status = s; + break; + } else { + if (s != DLADM_STATUS_OK && + s != DLADM_STATUS_NOTSUP) + status = s; } - (*lvpp)->lv_name = lsp->ls_propval[i]; - (*lvpp)->lv_nextval = NULL; - lvpp = &(*lvpp)->lv_nextval; } + if (!found) + status = DLADM_STATUS_NOTFOUND; - if (listp != NULL) { - generate_linkprop_line(lsp, buf, listp, statusp); - } else { - generate_linkprop_line(lsp, buf, nlip, statusp); - free_linkprops(nlip); - } - return (B_FALSE); - -fail: - *statusp = status; - if (listp == NULL) - free_linkprops(nlip); - - return (B_FALSE); + return (status); } /* - * This function is used for retrieving the values for a specific property. - * It gets called if an entry matching the specified link exists in the db. - * The entry is converted into a linked-list listp. This list is then scanned - * for the specified property name; if a matching property exists, its - * associated values are copied to the array lsp->ls_propval. + * Set/reset link property for specific link */ -/* ARGSUSED */ -static boolean_t -process_linkprop_get(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +dladm_status_t +dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, + uint_t val_cnt, uint_t flags) { - linkprop_info_t *lip = listp; - linkprop_val_t *lvp; - uint_t valcnt = 0; + dladm_status_t status = DLADM_STATUS_OK; - /* - * Find the linkprop we want to get. - */ - for (; lip != NULL; lip = lip->li_nextprop) { - if (strcmp(lip->li_name, lsp->ls_propname) == 0) - break; - } - if (lip == NULL) { - *statusp = DLADM_STATUS_NOTFOUND; - return (B_FALSE); + if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || + (prop_val == NULL && val_cnt > 0) || + (prop_val != NULL && val_cnt == 0) || + (prop_name == NULL && prop_val != NULL)) { + return (DLADM_STATUS_BADARG); } - for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { - (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name, - DLADM_PROP_VAL_MAX); + status = i_dladm_set_linkprop(linkid, prop_name, prop_val, + val_cnt, flags); + if (status != DLADM_STATUS_OK) + return (status); - if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) { - *statusp = DLADM_STATUS_TOOSMALL; - return (B_FALSE); - } + if (flags & DLADM_OPT_PERSIST) { + status = i_dladm_set_linkprop_db(linkid, prop_name, + prop_val, val_cnt); } - /* - * This function is meant to be called at most once for each call - * to process_linkprop_db(). For this reason, it's ok to overwrite - * the caller's valcnt array size with the actual number of values - * returned. - */ - *lsp->ls_valcntp = valcnt; - return (B_FALSE); + return (status); } /* - * This is used for initializing link properties. - * Unlike the other routines, this gets called for every entry in the - * database. lsp->ls_link is not user-specified but instead is set to - * the current link being processed. + * Walk link properties of the given specific link. */ -/* ARGSUSED */ -static boolean_t -process_linkprop_init(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +dladm_status_t +dladm_walk_linkprop(datalink_id_t linkid, void *arg, + int (*func)(datalink_id_t, const char *, void *)) { - dladm_status_t status = DLADM_STATUS_OK; - linkprop_info_t *lip = listp; - linkprop_val_t *lvp; - uint_t valcnt, i; - char **propval; - - for (; lip != NULL; lip = lip->li_nextprop) { - /* - * Construct the propval array and fill it with - * values from listp. - */ - for (lvp = lip->li_val, valcnt = 0; - lvp != NULL; lvp = lvp->lv_nextval, valcnt++) - ; + dladm_status_t status; + datalink_class_t class; + uint_t media; + int i; - propval = malloc(sizeof (char *) * valcnt); - if (propval == NULL) { - *statusp = DLADM_STATUS_NOMEM; - break; - } - lvp = lip->li_val; - for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval) - propval[i] = (char *)lvp->lv_name; - - status = dladm_set_prop(lsp->ls_link, lip->li_name, - propval, valcnt, DLADM_OPT_TEMP, NULL); - - /* - * We continue with initializing other properties even - * after encountering an error. This error will be - * propagated to the caller via 'statusp'. - */ - if (status != DLADM_STATUS_OK) - *statusp = status; - - free(propval); - } - return (B_TRUE); -} + if (linkid == DATALINK_INVALID_LINKID || func == NULL) + return (DLADM_STATUS_BADARG); -static int -parse_linkprops(char *buf, linkprop_info_t **lipp) -{ - int i, len; - char *curr; - linkprop_info_t *lip = NULL; - linkprop_info_t **tailp = lipp; - linkprop_val_t *lvp = NULL; - linkprop_val_t **vtailp = NULL; - - curr = buf; - len = strlen(buf); - for (i = 0; i < len; i++) { - char c = buf[i]; - boolean_t match = (c == '=' || c == ',' || c == ';'); + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); - /* - * Move to the next character if there is no match and - * if we have not reached the last character. - */ - if (!match && i != len - 1) + for (i = 0; i < DLADM_MAX_PROPS; i++) { + if (!(prop_table[i].pd_class & class)) continue; - if (match) { - /* - * Nul-terminate the string pointed to by 'curr'. - */ - buf[i] = '\0'; - if (*curr == '\0') - goto fail; - } + if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) + continue; - if (lip != NULL) { - /* - * We get here after we have processed the "<prop>=" - * pattern. The pattern we are now interested in is - * "<val0>,<val1>,...,<valn>;". For each value we - * find, a linkprop_val_t will be allocated and - * added to the current 'lip'. - */ - if (c == '=') - goto fail; - - lvp = malloc(sizeof (*lvp)); - if (lvp == NULL) - goto fail; - - lvp->lv_name = curr; - lvp->lv_nextval = NULL; - *vtailp = lvp; - vtailp = &lvp->lv_nextval; - - if (c == ';') { - tailp = &lip->li_nextprop; - vtailp = NULL; - lip = NULL; - } - } else { - /* - * lip == NULL indicates that 'curr' must be refering - * to a property name. We allocate a new linkprop_info_t - * append it to the list given by the caller. - */ - if (c != '=') - goto fail; - - lip = malloc(sizeof (*lip)); - if (lip == NULL) - goto fail; - - lip->li_name = curr; - lip->li_val = NULL; - lip->li_nextprop = NULL; - *tailp = lip; - vtailp = &lip->li_val; + if (func(linkid, prop_table[i].pd_name, arg) == + DLADM_WALK_TERMINATE) { + break; } - curr = buf + i + 1; } - /* - * The list must be non-empty and the last character must be ';'. - */ - if (*lipp == NULL || lip != NULL) - goto fail; - - return (0); -fail: - free_linkprops(*lipp); - *lipp = NULL; - return (-1); + return (DLADM_STATUS_OK); } -static boolean_t -process_linkprop_line(linkprop_db_state_t *lsp, char *buf, - dladm_status_t *statusp) +/* + * Get linkprop of the given specific link. + */ +dladm_status_t +dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, + const char *prop_name, char **prop_val, uint_t *val_cntp) { - linkprop_info_t *lip = NULL; - int i, len, llen; - char *str, *lasts; - boolean_t cont, nolink = B_FALSE; + dladm_status_t status = DLADM_STATUS_OK; + datalink_class_t class; + uint_t media; + prop_desc_t *pdp; + uint_t cnt; + int i; + + if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || + prop_val == NULL || val_cntp == NULL || *val_cntp == 0) + return (DLADM_STATUS_BADARG); - /* - * Skip leading spaces, blank lines, and comments. - */ - len = strlen(buf); - for (i = 0; i < len; i++) { - if (!isspace(buf[i])) + for (i = 0; i < DLADM_MAX_PROPS; i++) + if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) break; - } - if (i == len || buf[i] == '#') - return (B_TRUE); - str = buf + i; - if (lsp->ls_link != NULL) { - /* - * Skip links we're not interested in. - * Note that strncmp() and isspace() are used here - * instead of strtok() and strcmp() because we don't - * want to modify buf in case it does not contain the - * specified link. - */ - llen = strlen(lsp->ls_link); - if (strncmp(str, lsp->ls_link, llen) != 0 || - !isspace(str[llen])) - return (B_TRUE); - } else { - /* - * If a link is not specified, find the link name - * and assign it to lsp->ls_link. - */ - if (strtok_r(str, " \n\t", &lasts) == NULL) - goto fail; - - llen = strlen(str); - lsp->ls_link = str; - nolink = B_TRUE; - } - str += llen + 1; - if (str >= buf + len) - goto fail; - - /* - * Now find the list of link properties. - */ - if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) - goto fail; + if (i == DLADM_MAX_PROPS) + return (DLADM_STATUS_NOTFOUND); - if (parse_linkprops(str, &lip) < 0) - goto fail; + pdp = &prop_table[i]; - cont = (*lsp->ls_op)(lsp, buf, lip, statusp); - free_linkprops(lip); - if (nolink) - lsp->ls_link = NULL; - return (cont); + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); -fail: - free_linkprops(lip); - if (nolink) - lsp->ls_link = NULL; + if (!(pdp->pd_class & class)) + return (DLADM_STATUS_BADARG); - /* - * Delete corrupted line. - */ - buf[0] = '\0'; - return (B_TRUE); -} + if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) + return (DLADM_STATUS_BADARG); -static dladm_status_t -process_linkprop_db(void *arg, FILE *fp, FILE *nfp) -{ - linkprop_db_state_t *lsp = arg; - dladm_status_t status = DLADM_STATUS_OK; - char buf[MAXLINELEN]; - boolean_t cont = B_TRUE; + switch (type) { + case DLADM_PROP_VAL_CURRENT: + status = pdp->pd_get(linkid, prop_val, val_cntp); + break; - /* - * This loop processes each line of the configuration file. - * buf can potentially be modified by process_linkprop_line(). - * If this is a write operation and buf is not truncated, buf will - * be written to disk. process_linkprop_line() will no longer be - * called after it returns B_FALSE; at which point the remainder - * of the file will continue to be read and, if necessary, written - * to disk as well. - */ - while (fgets(buf, MAXLINELEN, fp) != NULL) { - if (cont) - cont = process_linkprop_line(lsp, buf, &status); + case DLADM_PROP_VAL_DEFAULT: + if (pdp->pd_defval.vd_name == NULL) { + status = DLADM_STATUS_NOTSUP; + break; + } + (void) strcpy(*prop_val, pdp->pd_defval.vd_name); + *val_cntp = 1; + break; - if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) { - status = dladm_errno2status(errno); + case DLADM_PROP_VAL_MODIFIABLE: + if (pdp->pd_getmod != NULL) { + status = pdp->pd_getmod(linkid, prop_val, val_cntp); break; } + cnt = pdp->pd_noptval; + if (cnt == 0) { + status = DLADM_STATUS_NOTSUP; + } else if (cnt > *val_cntp) { + status = DLADM_STATUS_TOOSMALL; + } else { + for (i = 0; i < cnt; i++) { + (void) strcpy(prop_val[i], + pdp->pd_optval[i].vd_name); + } + *val_cntp = cnt; + } + break; + case DLADM_PROP_VAL_PERSISTENT: + if (pdp->pd_flags & PD_TEMPONLY) + return (DLADM_STATUS_TEMPONLY); + status = i_dladm_get_linkprop_db(linkid, prop_name, + prop_val, val_cntp); + break; + default: + status = DLADM_STATUS_BADARG; + break; } - if (status != DLADM_STATUS_OK || !cont) - return (status); + return (status); +} - if (lsp->ls_op == process_linkprop_set) { - /* - * If the specified link is not found above, we add the - * link and its properties to the configuration file. - */ - (void) (*lsp->ls_op)(lsp, buf, NULL, &status); - if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF) - status = dladm_errno2status(errno); - } +/*ARGSUSED*/ +static int +i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) +{ + char *buf, **propvals; + uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; - if (lsp->ls_op == process_linkprop_get) - status = DLADM_STATUS_NOTFOUND; + if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * + DLADM_MAX_PROP_VALCNT)) == NULL) { + return (DLADM_WALK_CONTINUE); + } - return (status); -} + propvals = (char **)(void *)buf; + for (i = 0; i < valcnt; i++) { + propvals[i] = buf + + sizeof (char *) * DLADM_MAX_PROP_VALCNT + + i * DLADM_PROP_VAL_MAX; + } -#define LINKPROP_RW_DB(statep, writeop) \ - (i_dladm_rw_db("/etc/dladm/linkprop.conf", \ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \ - (statep), (writeop))) + if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, + propvals, &valcnt) != DLADM_STATUS_OK) { + goto done; + } -static dladm_status_t -i_dladm_set_prop_db(const char *link, const char *prop_name, - char **prop_val, uint_t val_cnt) -{ - linkprop_db_state_t state; + (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, + DLADM_OPT_ACTIVE); - state.ls_op = process_linkprop_set; - state.ls_link = link; - state.ls_propname = prop_name; - state.ls_propval = prop_val; - state.ls_valcntp = &val_cnt; +done: + if (buf != NULL) + free(buf); - return (LINKPROP_RW_DB(&state, B_TRUE)); + return (DLADM_WALK_CONTINUE); } -static dladm_status_t -i_dladm_get_prop_db(const char *link, const char *prop_name, - char **prop_val, uint_t *val_cntp) +/*ARGSUSED*/ +static int +i_dladm_init_linkprop(datalink_id_t linkid, void *arg) { - linkprop_db_state_t state; - - state.ls_op = process_linkprop_get; - state.ls_link = link; - state.ls_propname = prop_name; - state.ls_propval = prop_val; - state.ls_valcntp = val_cntp; - - return (LINKPROP_RW_DB(&state, B_FALSE)); + (void) dladm_init_linkprop(linkid); + return (DLADM_WALK_CONTINUE); } dladm_status_t -dladm_init_linkprop(void) +dladm_init_linkprop(datalink_id_t linkid) { - linkprop_db_state_t state; - - state.ls_op = process_linkprop_init; - state.ls_link = NULL; - state.ls_propname = NULL; - state.ls_propval = NULL; - state.ls_valcntp = NULL; - - return (LINKPROP_RW_DB(&state, B_FALSE)); + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + } else { + (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); + } + return (DLADM_STATUS_OK); } static dladm_status_t -i_dladm_get_zoneid(const char *link, zoneid_t *zidp) +do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) { - int fd; - dld_hold_vlan_t dhv; + char zone_name[ZONENAME_MAX]; + zoneid_t zid; + dladm_status_t status; - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); + status = dladm_getzid(linkid, &zid); + if (status != DLADM_STATUS_OK) + return (status); - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, link, IFNAMSIZ); - dhv.dhv_zid = -1; + *val_cnt = 1; + if (zid != GLOBAL_ZONEID) { + if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) + return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0) { - if (errno == ENOENT) { - *zidp = GLOBAL_ZONEID; - } else { - dladm_status_t status = dladm_errno2status(errno); - (void) close(fd); - return (status); - } + (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); } else { - *zidp = dhv.dhv_zid; + *prop_val[0] = '\0'; } - (void) close(fd); return (DLADM_STATUS_OK); } @@ -785,12 +598,14 @@ i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) } static dladm_status_t -i_dladm_add_deventry(zoneid_t zid, const char *link) +i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) { char path[MAXPATHLEN]; + char name[MAXLINKNAMELEN]; di_prof_t prof = NULL; char zone_name[ZONENAME_MAX]; dladm_status_t status; + int ret; if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) return (dladm_errno2status(errno)); @@ -799,40 +614,20 @@ i_dladm_add_deventry(zoneid_t zid, const char *link) if (di_prof_init(path, &prof) != 0) return (dladm_errno2status(errno)); - status = DLADM_STATUS_OK; - if (di_prof_add_dev(prof, link) != 0) { - status = dladm_errno2status(errno); + status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); + if (status != DLADM_STATUS_OK) goto cleanup; - } - if (di_prof_commit(prof) != 0) - status = dladm_errno2status(errno); -cleanup: - if (prof) - di_prof_fini(prof); - - return (status); -} - -static dladm_status_t -i_dladm_remove_deventry(zoneid_t zid, const char *link) -{ - char path[MAXPATHLEN]; - di_prof_t prof = NULL; - char zone_name[ZONENAME_MAX]; - dladm_status_t status; - if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) - return (dladm_errno2status(errno)); - if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) - return (dladm_errno2status(errno)); - if (di_prof_init(path, &prof) != 0) - return (dladm_errno2status(errno)); + if (add) + ret = di_prof_add_dev(prof, name); + else + ret = di_prof_add_exclude(prof, name); - status = DLADM_STATUS_OK; - if (di_prof_add_exclude(prof, link) != 0) { + if (ret != 0) { status = dladm_errno2status(errno); goto cleanup; } + if (di_prof_commit(prof) != 0) status = dladm_errno2status(errno); cleanup: @@ -843,102 +638,93 @@ cleanup: } static dladm_status_t -do_get_zone(const char *link, char **prop_val, uint_t *val_cnt) -{ - char zone_name[ZONENAME_MAX]; - zoneid_t zid; - dladm_status_t status; - - status = i_dladm_get_zoneid(link, &zid); - if (status != DLADM_STATUS_OK) - return (status); - - *val_cnt = 1; - if (zid != GLOBAL_ZONEID) { - if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) - return (dladm_errno2status(errno)); - - (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); - } else { - *prop_val[0] = '\0'; - } - - return (DLADM_STATUS_OK); -} - -static dladm_status_t -do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt) +do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) { dladm_status_t status; zoneid_t zid_old, zid_new; + char link[MAXLINKNAMELEN]; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); - status = i_dladm_get_zoneid(link, &zid_old); + status = dladm_getzid(linkid, &zid_old); if (status != DLADM_STATUS_OK) return (status); /* Do nothing if setting to current value */ - zid_new = (intptr_t)(void *)vdp->vd_val; + zid_new = vdp->vd_val; if (zid_new == zid_old) return (DLADM_STATUS_OK); - if (zid_old != GLOBAL_ZONEID) { - if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0) - return (dladm_errno2status(errno)); + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { + return (status); + } - if (zone_remove_datalink(zid_old, (char *)link) != 0 && + if (zid_new != GLOBAL_ZONEID) { + /* + * If the new zoneid is the global zone, we could destroy + * the link (in the case of an implicitly-created VLAN) as a + * result of the dladm_setzid() operation. In that case, + * we defer the operation to the end of this function to avoid + * recreating the VLAN and getting a different linkid during + * the rollback if other operation fails. + * + * Otherwise, dladm_setzid() will hold a reference to the + * link and prevent a link renaming, so we need to do it + * before other operations. + */ + status = dladm_setzid(link, zid_new); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (zid_old != GLOBAL_ZONEID) { + if (zone_remove_datalink(zid_old, link) != 0 && errno != ENXIO) { status = dladm_errno2status(errno); goto rollback1; } - status = i_dladm_remove_deventry(zid_old, link); - if (status != DLADM_STATUS_OK) - goto rollback2; + /* + * It is okay to fail to update the /dev entry (some + * vanity-named links do not have a /dev entry). + */ + (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); } if (zid_new != GLOBAL_ZONEID) { - if (zone_add_datalink(zid_new, (char *)link) != 0) { - status = dladm_errno2status(errno); - goto rollback3; - } - - if (dladm_hold_link(link, zid_new, B_TRUE) < 0) { - (void) zone_remove_datalink(zid_new, (char *)link); + if (zone_add_datalink(zid_new, link) != 0) { status = dladm_errno2status(errno); - goto rollback3; + goto rollback2; } - status = i_dladm_add_deventry(zid_new, link); - if (status != DLADM_STATUS_OK) { - (void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE); - (void) zone_remove_datalink(zid_new, (char *)link); - goto rollback3; - } + (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); + } else { + status = dladm_setzid(link, zid_new); + if (status != DLADM_STATUS_OK) + goto rollback2; } + return (DLADM_STATUS_OK); -rollback3: - if (zid_old != GLOBAL_ZONEID) - (void) i_dladm_add_deventry(zid_old, link); rollback2: if (zid_old != GLOBAL_ZONEID) - (void) zone_add_datalink(zid_old, (char *)link); + (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); + if (zid_old != GLOBAL_ZONEID) + (void) zone_add_datalink(zid_old, link); rollback1: - (void) dladm_hold_link(link, zid_old, B_FALSE); -cleanexit: + if (zid_new != GLOBAL_ZONEID) + (void) dladm_setzid(link, zid_old); return (status); } /* ARGSUSED */ static dladm_status_t -do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, - val_desc_t **vdpp) +do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt, + val_desc_t *vdp, boolean_t *needfreep) { - zoneid_t zid; - val_desc_t *vdp = NULL; + zoneid_t zid; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); @@ -959,176 +745,563 @@ do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, } } - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) - return (DLADM_STATUS_NOMEM); - - vdp->vd_val = (void *)(uintptr_t)zid; - *vdpp = vdp; + vdp->vd_val = zid; + *needfreep = B_FALSE; return (DLADM_STATUS_OK); } static dladm_status_t -i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cntp) +do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) { - int i; - dladm_status_t status; - uint_t cnt; - prop_desc_t *pdp; + dld_ioc_ap_t dia; + int fd, i, len; - if (link == NULL || prop_name == NULL || prop_val == NULL || - val_cntp == NULL || *val_cntp == 0) - return (DLADM_STATUS_BADARG); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); - for (i = 0; i < MAX_PROPS; i++) - if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) - break; + *val_cnt = 1; + dia.dia_linkid = linkid; + if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) { + (*prop_val)[0] = '\0'; + goto done; + } - if (i == MAX_PROPS) - return (DLADM_STATUS_NOTFOUND); + for (i = 0, len = 0; i < dia.dia_npush; i++) { + if (i != 0) { + (void) snprintf(*prop_val + len, + DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); + len += 1; + } + (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, + "%s", dia.dia_aplist[i]); + len += strlen(dia.dia_aplist[i]); + if (dia.dia_anchor - 1 == i) { + (void) snprintf(*prop_val + len, + DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, + AP_ANCHOR); + len += (strlen(AP_ANCHOR) + 1); + } + } - pdp = &prop_table[i]; - status = DLADM_STATUS_OK; +done: + (void) close(fd); + return (DLADM_STATUS_OK); +} - switch (type) { - case DLADM_PROP_VAL_CURRENT: - status = pdp->pd_get(link, prop_val, val_cntp); - break; - case DLADM_PROP_VAL_DEFAULT: - if (pdp->pd_defval.vd_name == NULL) { - status = DLADM_STATUS_NOTSUP; - break; - } - (void) strcpy(*prop_val, pdp->pd_defval.vd_name); - *val_cntp = 1; - break; +static dladm_status_t +do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dld_ioc_ap_t dia; + struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val; + dladm_status_t status = DLADM_STATUS_OK; + int fd, i; + int ic_cmd; - case DLADM_PROP_VAL_MODIFIABLE: - if (pdp->pd_getmod != NULL) { - status = pdp->pd_getmod(link, prop_val, val_cntp); - break; - } - cnt = pdp->pd_nmodval; - if (cnt == 0) { - status = DLADM_STATUS_NOTSUP; - } else if (cnt > *val_cntp) { - status = DLADM_STATUS_TOOSMALL; - } else { - for (i = 0; i < cnt; i++) { - (void) strcpy(prop_val[i], - pdp->pd_modval[i].vd_name); - } - *val_cntp = cnt; + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dia.dia_linkid = linkid; + if (dlap != NULL) { + dia.dia_anchor = dlap->dap_anchor; + dia.dia_npush = dlap->dap_npush; + for (i = 0; i < dia.dia_npush; i++) { + (void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i], + FMNAMESZ+1); } - break; - default: - status = DLADM_STATUS_BADARG; - break; + ic_cmd = DLDIOC_SETAUTOPUSH; + } else { + ic_cmd = DLDIOC_CLRAUTOPUSH; } + if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); return (status); } -static dladm_status_t -i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, uint_t flags) +/* + * Add the specified module to the dlautopush structure; returns a + * DLADM_STATUS_* code. + */ +dladm_status_t +i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) { - dladm_status_t status; - val_desc_t *vdp = NULL; - uint_t cnt; + if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) + return (DLADM_STATUS_BADVAL); - if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0) - return (DLADM_STATUS_TEMPONLY); + if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { + /* + * We don't allow multiple anchors, and the anchor must + * be after at least one module. + */ + if (dlap->dap_anchor != 0) + return (DLADM_STATUS_BADVAL); + if (dlap->dap_npush == 0) + return (DLADM_STATUS_BADVAL); - if (pdp->pd_set == NULL) - return (DLADM_STATUS_PROPRDONLY); + dlap->dap_anchor = dlap->dap_npush; + return (DLADM_STATUS_OK); + } + if (dlap->dap_npush > MAXAPUSH) + return (DLADM_STATUS_BADVALCNT); - if (prop_val != NULL) { - if (pdp->pd_check != NULL) - status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp); - else - status = DLADM_STATUS_BADARG; + (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, + FMNAMESZ + 1); + + return (DLADM_STATUS_OK); +} + +/* + * Currently, both '.' and ' '(space) can be used as the delimiters between + * autopush modules. The former is used in dladm set-linkprop, and the + * latter is used in the autopush(1M) file. + */ +/* ARGSUSED */ +static dladm_status_t +do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt, + val_desc_t *vdp, boolean_t *needfreep) +{ + char *module; + struct dlautopush *dlap; + dladm_status_t status; + char val[DLADM_PROP_VAL_MAX]; + char delimiters[4]; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + dlap = malloc(sizeof (struct dlautopush)); + if (dlap == NULL) + return (DLADM_STATUS_NOMEM); + (void) memset(dlap, 0, sizeof (struct dlautopush)); + (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); + bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); + module = strtok(val, delimiters); + while (module != NULL) { + status = i_dladm_add_ap_module(module, dlap); if (status != DLADM_STATUS_OK) return (status); + module = strtok(NULL, delimiters); + } - cnt = val_cnt; - } else { - if (pdp->pd_defval.vd_name == NULL) - return (DLADM_STATUS_NOTSUP); + vdp->vd_val = (uintptr_t)dlap; + *needfreep = B_TRUE; + return (DLADM_STATUS_OK); +} - if ((vdp = malloc(sizeof (val_desc_t))) == NULL) - return (DLADM_STATUS_NOMEM); +static dladm_status_t +do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt, + uint_t id) +{ + wl_rates_t *wrp; + uint_t i; + wldp_t *gbuf = NULL; + dladm_status_t status = DLADM_STATUS_OK; - (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); - cnt = 1; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - status = pdp->pd_set(link, vdp, cnt); + status = i_dladm_wlan_get_ioctl(linkid, gbuf, id); + if (status != DLADM_STATUS_OK) + goto done; - free(vdp); + wrp = (wl_rates_t *)gbuf->wldp_buf; + if (wrp->wl_rates_num > *val_cnt) { + status = DLADM_STATUS_TOOSMALL; + goto done; + } + + if (wrp->wl_rates_rates[0] == 0) { + prop_val[0][0] = '\0'; + *val_cnt = 1; + goto done; + } + + for (i = 0; i < wrp->wl_rates_num; i++) { + (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", + wrp->wl_rates_rates[i] % 2, + (float)wrp->wl_rates_rates[i] / 2); + } + *val_cnt = wrp->wl_rates_num; + +done: + free(gbuf); return (status); } static dladm_status_t -i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val, - uint_t val_cnt, uint_t flags, char **errprop) +do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + return (do_get_rate_common(linkid, prop_val, val_cnt, + WL_DESIRED_RATES)); +} + +static dladm_status_t +do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + return (do_get_rate_common(linkid, prop_val, val_cnt, + WL_SUPPORTED_RATES)); +} + +static dladm_status_t +do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) { - int i; + int i; + uint_t len; + wldp_t *gbuf; + wl_rates_t *wrp; dladm_status_t status = DLADM_STATUS_OK; - boolean_t found = B_FALSE; - for (i = 0; i < MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; - dladm_status_t s; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; + (void) memset(gbuf, 0, MAX_BUF_LEN); - found = B_TRUE; - s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt, - flags); + wrp = (wl_rates_t *)gbuf->wldp_buf; + for (i = 0; i < rates->wr_cnt; i++) + wrp->wl_rates_rates[i] = rates->wr_rates[i]; + wrp->wl_rates_num = rates->wr_cnt; - if (prop_name != NULL) { - status = s; + len = offsetof(wl_rates_t, wl_rates_rates) + + (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; + status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len, + WLAN_SET_PARAM, len); + + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_rates_t rates; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + rates.wr_cnt = 1; + rates.wr_rates[0] = vdp[0].vd_val; + + status = do_set_rate(linkid, &rates); + +done: + return (status); +} + +/* ARGSUSED */ +static dladm_status_t +do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt, + val_desc_t *vdp, boolean_t *needfreep) +{ + int i; + uint_t modval_cnt = MAX_SUPPORT_RATES; + char *buf, **modval; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + buf = malloc((sizeof (char *) + DLADM_STRSIZE) * + MAX_SUPPORT_RATES); + if (buf == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; + } + + modval = (char **)(void *)buf; + for (i = 0; i < MAX_SUPPORT_RATES; i++) { + modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + + i * DLADM_STRSIZE; + } + + status = do_get_rate_mod(linkid, modval, &modval_cnt); + if (status != DLADM_STATUS_OK) + goto done; + + for (i = 0; i < modval_cnt; i++) { + if (strcasecmp(*prop_val, modval[i]) == 0) { + vdp->vd_val = (uint_t)(atof(*prop_val) * 2); + status = DLADM_STATUS_OK; + + /* + * Does not need the caller to free the vdp->vd_val + */ + *needfreep = B_FALSE; break; - } else { - if (s != DLADM_STATUS_OK && - s != DLADM_STATUS_NOTSUP) { - if (errprop != NULL) - *errprop = pdp->pd_name; - status = s; - break; - } } } + if (i == modval_cnt) + status = DLADM_STATUS_BADVAL; +done: + free(buf); + return (status); +} - if (!found) +static dladm_status_t +do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) +{ + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); +} + +static dladm_status_t +do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + uint32_t channel; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, + &channel)) { status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); + *val_cnt = 1; + +done: + free(gbuf); return (status); } -static boolean_t -i_dladm_is_prop_temponly(const char *prop_name, char **errprop) +static dladm_status_t +do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) { - int i; + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); +} - for (i = 0; i < MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; +static dladm_status_t +do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + wl_ps_mode_t *mode; + const char *s; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + mode = (wl_ps_mode_t *)(gbuf->wldp_buf); + switch (mode->wl_ps_mode) { + case WL_PM_AM: + s = "off"; + break; + case WL_PM_MPS: + s = "max"; + break; + case WL_PM_FAST: + s = "fast"; + break; + default: + status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); + *val_cnt = 1; + +done: + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) +{ + wl_ps_mode_t ps_mode; - if (errprop != NULL) - *errprop = pdp->pd_name; + (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); - if (pdp->pd_temponly) - return (B_TRUE); + switch (*pm) { + case DLADM_WLAN_PM_OFF: + ps_mode.wl_ps_mode = WL_PM_AM; + break; + case DLADM_WLAN_PM_MAX: + ps_mode.wl_ps_mode = WL_PM_MPS; + break; + case DLADM_WLAN_PM_FAST: + ps_mode.wl_ps_mode = WL_PM_FAST; + break; + default: + return (DLADM_STATUS_NOTSUP); } + return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode, + sizeof (ps_mode))); +} - return (B_FALSE); +/* ARGSUSED */ +static dladm_status_t +do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + status = do_set_powermode(linkid, &powermode); + + return (status); +} + +static dladm_status_t +do_get_radio(datalink_id_t linkid, wldp_t *gbuf) +{ + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); +} + +static dladm_status_t +do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + wl_radio_t radio; + const char *s; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + radio = *(wl_radio_t *)(gbuf->wldp_buf); + switch (radio) { + case B_TRUE: + s = "on"; + break; + case B_FALSE: + s = "off"; + break; + default: + status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); + *val_cnt = 1; + +done: + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) +{ + wl_radio_t r; + + switch (*radio) { + case DLADM_WLAN_RADIO_ON: + r = B_TRUE; + break; + case DLADM_WLAN_RADIO_OFF: + r = B_FALSE; + break; + default: + return (DLADM_STATUS_NOTSUP); + } + return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r))); +} + +/* ARGSUSED */ +static dladm_status_t +do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + status = do_set_radio(linkid, &radio); + + return (status); +} + +static dladm_status_t +i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t val_cnt) +{ + char buf[MAXLINELEN]; + int i; + dladm_conf_t conf; + dladm_status_t status; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + /* + * reset case. + */ + if (val_cnt == 0) { + status = dladm_unset_conf_field(conf, prop_name); + if (status == DLADM_STATUS_OK) + status = dladm_write_conf(conf); + goto done; + } + + buf[0] = '\0'; + for (i = 0; i < val_cnt; i++) { + (void) strlcat(buf, prop_val[i], MAXLINELEN); + if (i != val_cnt - 1) + (void) strlcat(buf, ",", MAXLINELEN); + } + + status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); + if (status == DLADM_STATUS_OK) + status = dladm_write_conf(conf); + +done: + dladm_destroy_conf(conf); + return (status); +} + +static dladm_status_t +i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t *val_cntp) +{ + char buf[MAXLINELEN], *str; + uint_t cnt = 0; + dladm_conf_t conf; + dladm_status_t status; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); + if (status != DLADM_STATUS_OK) + goto done; + + str = strtok(buf, ","); + while (str != NULL) { + if (cnt == *val_cntp) { + status = DLADM_STATUS_TOOSMALL; + goto done; + } + (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); + str = strtok(NULL, ","); + } + + *val_cntp = cnt; + +done: + dladm_destroy_conf(conf); + return (status); } diff --git a/usr/src/lib/libdladm/common/llib-ldladm b/usr/src/lib/libdladm/common/llib-ldladm index 467808e937..a6fc19b517 100644 --- a/usr/src/lib/libdladm/common/llib-ldladm +++ b/usr/src/lib/libdladm/common/llib-ldladm @@ -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. */ @@ -32,3 +32,5 @@ #include <libdlaggr.h> #include <libdlwlan.h> #include <libdlvnic.h> +#include <libdlvlan.h> +#include <libdlmgmt.h> diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers index 2672efc195..25ab048469 100644 --- a/usr/src/lib/libdladm/common/mapfile-vers +++ b/usr/src/lib/libdladm/common/mapfile-vers @@ -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" @@ -29,17 +29,18 @@ SUNWprivate_1.1 { global: dladm_info; dladm_walk; - dladm_hold_link; - dladm_rele_link; + dladm_setzid; + dladm_getzid; dladm_status2str; dladm_linkstate2str; dladm_linkduplex2str; dladm_set_rootdir; + dladm_valid_linkname; dladm_mac_walk; dladm_init_linkprop; - dladm_get_prop; - dladm_set_prop; - dladm_walk_prop; + dladm_get_linkprop; + dladm_set_linkprop; + dladm_walk_linkprop; dladm_init_secobj; dladm_get_secobj; dladm_set_secobj; @@ -47,9 +48,7 @@ SUNWprivate_1.1 { dladm_walk_secobj; dladm_secobjclass2str; dladm_str2secobjclass; - dladm_aggr_walk; dladm_aggr_up; - dladm_aggr_down; dladm_aggr_add; dladm_aggr_create; dladm_aggr_delete; @@ -64,15 +63,12 @@ SUNWprivate_1.1 { dladm_aggr_str2lacptimer; dladm_aggr_str2macaddr; dladm_aggr_str2policy; - dladm_wlan_walk; + dladm_aggr_info; + dladm_key2linkid; dladm_wlan_scan; dladm_wlan_connect; dladm_wlan_disconnect; dladm_wlan_get_linkattr; - dladm_wlan_is_valid; - dladm_wlan_set_prop; - dladm_wlan_walk_prop; - dladm_wlan_get_prop; dladm_wlan_essid2str; dladm_wlan_bssid2str; dladm_wlan_secmode2str; @@ -91,6 +87,32 @@ SUNWprivate_1.1 { dladm_wlan_str2auth; dladm_wlan_str2bsstype; dladm_wlan_str2linkstatus; + dladm_vlan_create; + dladm_vlan_delete; + dladm_vlan_up; + dladm_vlan_info; + dladm_class2str; + dladm_media2str; + dladm_rename_link; + dladm_phys_info; + dladm_phys_delete; + dladm_dev2linkid; + dladm_linkid2legacyname; + dladm_create_datalink_id; + dladm_destroy_datalink_id; + dladm_remap_datalink_id; + dladm_up_datalink_id; + dladm_name2info; + dladm_datalink_id2info; + dladm_walk_datalink_id; + dladm_create_conf; + dladm_read_conf; + dladm_write_conf; + dladm_remove_conf; + dladm_destroy_conf; + dladm_get_conf_field; + dladm_set_conf_field; + dladm_unset_conf_field; dladm_wlan_wpa_get_sr; dladm_wlan_wpa_set_ie; dladm_wlan_wpa_set_wpa; @@ -100,8 +122,8 @@ SUNWprivate_1.1 { dladm_vnic_create; dladm_vnic_modify; dladm_vnic_delete; - dladm_vnic_walk_sys; - dladm_vnic_mac_addr_str_to_type; + dladm_vnic_info; + dladm_vnic_str2macaddrtype; local: *; diff --git a/usr/src/lib/libdladm/common/secobj.c b/usr/src/lib/libdladm/common/secobj.c index 61a1cd72e5..7f17a38e4e 100644 --- a/usr/src/lib/libdladm/common/secobj.c +++ b/usr/src/lib/libdladm/common/secobj.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. */ @@ -136,7 +136,7 @@ dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class, obj_val == NULL || obj_len == 0 || obj_len > DLD_SECOBJ_VAL_MAX) return (DLADM_STATUS_BADARG); - if ((flags & DLADM_OPT_TEMP) == 0) + if ((flags & DLADM_OPT_ACTIVE) == 0) goto persist; bzero(&secobj_set, sizeof (secobj_set)); @@ -154,7 +154,7 @@ dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class, if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJSET, &secobj_set, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_SET, &secobj_set, sizeof (secobj_set)) < 0) { status = dladm_errno2status(errno); } @@ -198,7 +198,7 @@ dladm_get_secobj(const char *obj_name, dladm_secobj_class_t *classp, if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, &secobj_get, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_GET, &secobj_get, sizeof (secobj_get)) < 0) status = dladm_errno2status(errno); @@ -225,7 +225,7 @@ dladm_unset_secobj(const char *obj_name, uint_t flags) flags == 0) return (DLADM_STATUS_BADARG); - if ((flags & DLADM_OPT_TEMP) == 0) + if ((flags & DLADM_OPT_ACTIVE) == 0) goto persist; bzero(&secobj_unset, sizeof (secobj_unset)); @@ -233,7 +233,7 @@ dladm_unset_secobj(const char *obj_name, uint_t flags) if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJUNSET, &secobj_unset, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_UNSET, &secobj_unset, sizeof (secobj_unset)) < 0) status = dladm_errno2status(errno); @@ -269,7 +269,7 @@ dladm_walk_secobj(void *arg, boolean_t (*func)(void *, const char *), status = dladm_errno2status(errno); goto done; } - if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, secobj_getp, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_GET, secobj_getp, SECOBJ_BUFSZ) < 0) { status = dladm_errno2status(errno); goto done; @@ -400,7 +400,7 @@ process_secobj_init(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, dladm_status_t *statusp) { *statusp = dladm_set_secobj(sip->si_name, *sip->si_classp, sip->si_val, - *sip->si_lenp, DLADM_OPT_TEMP | DLADM_OPT_CREATE); + *sip->si_lenp, DLADM_OPT_ACTIVE | DLADM_OPT_CREATE); return (B_TRUE); } diff --git a/usr/src/lib/libdlpi/Makefile.com b/usr/src/lib/libdlpi/Makefile.com index a8b5e6be1f..621cb0b217 100644 --- a/usr/src/lib/libdlpi/Makefile.com +++ b/usr/src/lib/libdlpi/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" @@ -36,7 +36,7 @@ include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -linetutil +LDLIBS += -lc -linetutil -ldladm SRCDIR = ../common $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libdlpi/common/libdlpi.c b/usr/src/lib/libdlpi/common/libdlpi.c index b95ff3fd93..f403135b6a 100644 --- a/usr/src/lib/libdlpi/common/libdlpi.c +++ b/usr/src/lib/libdlpi/common/libdlpi.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. */ @@ -44,13 +44,15 @@ #include <ctype.h> #include <net/if_types.h> #include <netinet/arp.h> +#include <libdladm.h> +#include <libdllink.h> #include <libdlpi.h> #include <libintl.h> #include <libinetutil.h> #include "libdlpi_impl.h" -static int i_dlpi_open(const char *, int *, uint_t); +static int i_dlpi_open(const char *, int *, uint_t, boolean_t); static int i_dlpi_style1_open(dlpi_impl_t *); static int i_dlpi_style2_open(dlpi_impl_t *); static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t); @@ -74,6 +76,33 @@ static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *); static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *); static void i_dlpi_deletenotifyid(dlpi_impl_t *); +struct i_dlpi_walklink_arg { + dlpi_walkfunc_t *fn; + void *arg; +}; + +static int +i_dlpi_walk_link(const char *name, void *arg) +{ + struct i_dlpi_walklink_arg *warg = arg; + + return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE : + DLADM_WALK_CONTINUE); +} + +/*ARGSUSED*/ +void +dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags) +{ + struct i_dlpi_walklink_arg warg; + + warg.fn = fn; + warg.arg = arg; + + (void) dladm_walk(i_dlpi_walk_link, &warg, DATALINK_CLASS_ALL, + DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); +} + int dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) { @@ -101,6 +130,8 @@ dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) dip->dli_oflags = flags; dip->dli_notifylistp = NULL; dip->dli_note_processing = B_FALSE; + if (getenv("DLPI_DEVONLY") != NULL) + dip->dli_oflags |= DLPI_DEVONLY; for (cnt = 0; cnt != dip->dli_mod_cnt; cnt++) { (void) strlcpy(dip->dli_modlist[cnt], ifsp.ifsp_mods[cnt], @@ -133,8 +164,19 @@ dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) return (retval); } - if (i_dlpi_style1_open(dip) != DLPI_SUCCESS) { - if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { + if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) { + if (retval == DLPI_ENOTSTYLE2) { + /* + * The error code indicates not to continue the + * style-2 open. Change the error code back to + * DL_SYSERR, so that one would know the cause + * of failure from errno. + */ + retval = DL_SYSERR; + } else { + retval = i_dlpi_style2_open(dip); + } + if (retval != DLPI_SUCCESS) { free(dip); return (retval); } @@ -939,35 +981,98 @@ dlpi_iftype(uint_t dlpitype) } /* - * This function attempts to open linkname under the following namespaces: - * - /dev - * - /devices - * If open doesn't succeed and link doesn't exist (ENOENT), this function - * returns DLPI_ENOLINK, otherwise returns DL_SYSERR. + * This function attempts to open a device under the following namespaces: + * /dev/net - if a data-link with the specified name exists + * /dev - if DLPI_DEVONLY is specified, or if there is no + * data-link with the specified name (could be /dev/ip) + * + * In particular, this function is used to open a data-link node, or some + * special node, such as "/dev/ip" node. It is usually be called firstly + * with style1 being B_TRUE, and if that fails and the return value is not + * DLPI_ENOTSTYLE2, the function will again be called with style1 being + * B_FALSE (style-1 open attempt first, then style-2 open attempt). + * + * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node + * directly. + * + * Otherwise, for style-1 attempt, the function will try to open the style-1 + * /dev/net node, and perhaps fallback to open the style-1 /dev node if the + * give name is not a data-link name (e.g., it is /dev/ip). Note that the + * fallback and the subsequent style-2 attempt will not happen if: + * 1. style-1 opening of the /dev/net node succeeds; + * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT, + * which means that the specific /dev/net node exist, but the attempt fails + * for some other reason; + * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is + * a known device name or its VLAN PPA hack name. (for example, assuming + * device bge0 is renamed to net0, opening /dev/net/bge1000 would return + * ENOENT, but we should not fallback to open /dev/bge1000 in this case, + * as VLAN 1 over the bge0 device should be named as net1000. + * + * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed + * the second style-2 open attempt. */ static int -i_dlpi_open(const char *provider, int *fd, uint_t flags) +i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1) { char path[MAXPATHLEN]; int oflags; + errno = ENOENT; oflags = O_RDWR; if (flags & DLPI_EXCL) oflags |= O_EXCL; - (void) snprintf(path, sizeof (path), "/dev/%s", provider); + if (style1 && !(flags & DLPI_DEVONLY)) { + char driver[DLPI_LINKNAME_MAX]; + char device[DLPI_LINKNAME_MAX]; + datalink_id_t linkid; + uint_t ppa; - if ((*fd = open(path, oflags)) != -1) - return (DLPI_SUCCESS); + /* + * This is not a valid style-1 name. It could be "ip" module + * for example. Fallback to open the /dev node. + */ + if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS) + goto fallback; - /* - * On diskless boot, it's possible the /dev links have not yet - * been created; fallback to /devices. When /dev links are - * created on demand, this code can be removed. - */ - (void) snprintf(path, sizeof (path), "/devices/pseudo/clone@0:%s", - provider); + (void) snprintf(path, sizeof (path), "/dev/net/%s", provider); + if ((*fd = open(path, oflags)) != -1) + return (DLPI_SUCCESS); + + /* + * We don't fallback to open the /dev node when it returns + * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2 + * is returned to indicate not to continue the style-2 open. + */ + if (errno != ENOENT) + return (DLPI_ENOTSTYLE2); + /* + * We didn't find the /dev/net node. Then we check whether + * the given name is a device name or its VLAN PPA hack name + * of a known link. If the answer is yes, and this link + * supports vanity naming, then the link (or the VLAN) should + * also have its /dev/net node but perhaps with another vanity + * name (for example, when bge0 is renamed to net0). In this + * case, although attempt to open the /dev/net/<devname> fails, + * we should not fallback to open the /dev/<devname> node. + */ + (void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver, + ppa >= 1000 ? ppa % 1000 : ppa); + + if (dladm_dev2linkid(device, &linkid) == DLADM_STATUS_OK) { + dladm_phys_attr_t dpa; + + if ((dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE)) == + DLADM_STATUS_OK && !dpa.dp_novanity) { + return (DLPI_ENOTSTYLE2); + } + } + } + +fallback: + (void) snprintf(path, sizeof (path), "/dev/%s", provider); if ((*fd = open(path, oflags)) != -1) return (DLPI_SUCCESS); @@ -988,8 +1093,9 @@ i_dlpi_style1_open(dlpi_impl_t *dip) * where modules need to be pushed onto the device stream, open only * device name, otherwise open the full linkname. */ - retval = i_dlpi_open((dip->dli_mod_cnt != 0) ? dip->dli_provider : - dip->dli_linkname, &fd, dip->dli_oflags); + retval = i_dlpi_open((dip->dli_mod_cnt != 0) ? + dip->dli_provider : dip->dli_linkname, &fd, + dip->dli_oflags, B_TRUE); if (retval != DLPI_SUCCESS) { dip->dli_mod_pushed = 0; @@ -1048,9 +1154,9 @@ i_dlpi_style2_open(dlpi_impl_t *dip) */ if (dip->dli_mod_pushed == 0) { if ((retval = i_dlpi_open(dip->dli_provider, &fd, - dip->dli_oflags)) != DLPI_SUCCESS) + dip->dli_oflags, B_FALSE)) != DLPI_SUCCESS) { return (retval); - + } dip->dli_fd = fd; } else if (dip->dli_mod_pushed == dip->dli_mod_cnt) { if (i_dlpi_remove_ppa(dip->dli_modlist[dip->dli_mod_cnt - 1]) diff --git a/usr/src/lib/libdlpi/common/libdlpi.h b/usr/src/lib/libdlpi/common/libdlpi.h index 93037e1dc5..5b9b1caba5 100644 --- a/usr/src/lib/libdlpi/common/libdlpi.h +++ b/usr/src/lib/libdlpi/common/libdlpi.h @@ -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. */ @@ -43,6 +43,7 @@ extern "C" { /* * Maximum link name length, including terminating NUL, in bytes. + * Must be no larger than MAXLINKNAMELEN (see <sys/param.h>). */ #define DLPI_LINKNAME_MAX 32 @@ -55,12 +56,13 @@ extern "C" { * Flag values for dlpi_open(); those not documented in dlpi_open(3DLPI) * are Consolidation Private and subject to change or removal. */ -#define DLPI_EXCL 0x0001 /* Exclusive open */ +#define DLPI_EXCL 0x0001 /* Exclusive open */ #define DLPI_PASSIVE 0x0002 /* Open DLPI link in passive mode */ #define DLPI_RAW 0x0004 /* Open DLPI link in raw mode */ #define DLPI_SERIAL 0x0008 /* Synchronous serial line interface */ #define DLPI_NOATTACH 0x0010 /* Do not attach PPA */ -#define DLPI_NATIVE 0x0020 /* Open DLPI link in Native mode */ +#define DLPI_NATIVE 0x0020 /* Open DLPI link in native mode */ +#define DLPI_DEVONLY 0x0040 /* Open DLPI link under /dev only */ /* * Timeout to be used in DLPI-related operations, in seconds. @@ -74,25 +76,24 @@ extern "C" { * <sys/dlpi.h>. */ enum { - DLPI_SUCCESS = 10000, /* DLPI operation succeeded */ - DLPI_EINVAL, /* invalid argument */ - DLPI_ELINKNAMEINVAL, /* invalid DLPI linkname */ - DLPI_ENOLINK, /* DLPI link does not exist */ - DLPI_EBADLINK, /* bad DLPI link */ - DLPI_EINHANDLE, /* invalid DLPI handle */ - DLPI_ETIMEDOUT, /* DLPI operation timed out */ - DLPI_EVERNOTSUP, /* unsupported DLPI Version */ - DLPI_EMODENOTSUP, /* unsupported DLPI connection mode */ - DLPI_EUNAVAILSAP, /* unavailable DLPI SAP */ - DLPI_FAILURE, /* DLPI operation failed */ - DLPI_ENOTSTYLE2, /* DLPI style-2 node reports style-1 */ - DLPI_EBADMSG, /* bad DLPI message */ - DLPI_ERAWNOTSUP, /* DLPI raw mode not supported */ - DLPI_ENOTEINVAL, /* invalid DLPI notification type */ - DLPI_ENOTENOTSUP, /* DLPI notification not supported */ - /* by link */ - DLPI_ENOTEIDINVAL, /* invalid DLPI notification id */ - DLPI_ERRMAX /* Highest + 1 libdlpi error code */ + DLPI_SUCCESS = 10000, /* DLPI operation succeeded */ + DLPI_EINVAL, /* invalid argument */ + DLPI_ELINKNAMEINVAL, /* invalid DLPI linkname */ + DLPI_ENOLINK, /* DLPI link does not exist */ + DLPI_EBADLINK, /* bad DLPI link */ + DLPI_EINHANDLE, /* invalid DLPI handle */ + DLPI_ETIMEDOUT, /* DLPI operation timed out */ + DLPI_EVERNOTSUP, /* unsupported DLPI Version */ + DLPI_EMODENOTSUP, /* unsupported DLPI connection mode */ + DLPI_EUNAVAILSAP, /* unavailable DLPI SAP */ + DLPI_FAILURE, /* DLPI operation failed */ + DLPI_ENOTSTYLE2, /* DLPI style-2 node reports style-1 */ + DLPI_EBADMSG, /* bad DLPI message */ + DLPI_ERAWNOTSUP, /* DLPI raw mode not supported */ + DLPI_ENOTEINVAL, /* invalid DLPI notification type */ + DLPI_ENOTENOTSUP, /* DLPI notification not supported by link */ + DLPI_ENOTEIDINVAL, /* invalid DLPI notification id */ + DLPI_ERRMAX /* Highest + 1 libdlpi error code */ }; /* @@ -157,10 +158,10 @@ typedef struct { } dni_data; } dlpi_notifyinfo_t; -#define dni_speed dni_data.dniu_speed -#define dni_size dni_data.dniu_size -#define dni_physaddr dni_data.dniu_addr.physaddr -#define dni_physaddrlen dni_data.dniu_addr.physaddrlen +#define dni_speed dni_data.dniu_speed +#define dni_size dni_data.dniu_size +#define dni_physaddr dni_data.dniu_addr.physaddr +#define dni_physaddrlen dni_data.dniu_addr.physaddrlen typedef struct __dlpi_handle *dlpi_handle_t; @@ -179,6 +180,9 @@ extern const char *dlpi_mactype(uint_t); extern const char *dlpi_strerror(int); extern const char *dlpi_linkname(dlpi_handle_t); +typedef boolean_t dlpi_walkfunc_t(const char *, void *); + +extern void dlpi_walk(dlpi_walkfunc_t *, void *, uint_t); extern int dlpi_open(const char *, dlpi_handle_t *, uint_t); extern void dlpi_close(dlpi_handle_t); extern int dlpi_info(dlpi_handle_t, dlpi_info_t *, uint_t); diff --git a/usr/src/lib/libdlpi/common/mapfile-vers b/usr/src/lib/libdlpi/common/mapfile-vers index aeaf161539..39ecc29922 100644 --- a/usr/src/lib/libdlpi/common/mapfile-vers +++ b/usr/src/lib/libdlpi/common/mapfile-vers @@ -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" @@ -49,6 +49,7 @@ SUNW_1.1 { # first release of libdlpi, Solaris 11 dlpi_set_timeout; dlpi_strerror; dlpi_unbind; + dlpi_walk; }; SUNWprivate { global: diff --git a/usr/src/lib/libinetcfg/Makefile.com b/usr/src/lib/libinetcfg/Makefile.com index d0d667091a..1d1ec9e8a2 100644 --- a/usr/src/lib/libinetcfg/Makefile.com +++ b/usr/src/lib/libinetcfg/Makefile.com @@ -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" @@ -26,8 +26,7 @@ LIBRARY = libinetcfg.a VERS = .1 -OBJECTS = inetcfg.o \ - inetcfg_nic.o +OBJECTS = inetcfg.o include ../../Makefile.lib @@ -36,7 +35,7 @@ include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lnsl -lsocket -ldevinfo +LDLIBS += -lc -lnsl -lsocket -ldlpi SRCDIR = ../common $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libinetcfg/common/inetcfg.c b/usr/src/lib/libinetcfg/common/inetcfg.c index 62b118b894..6e3a2b111f 100644 --- a/usr/src/lib/libinetcfg/common/inetcfg.c +++ b/usr/src/lib/libinetcfg/common/inetcfg.c @@ -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. */ @@ -41,10 +41,9 @@ #include <inet/ip.h> #include <arpa/inet.h> #include <libintl.h> +#include <libdlpi.h> #include <inetcfg.h> -#include "inetcfg_nic.h" - #define ICFG_FAMILY(handle) handle->ifh_interface.if_protocol #define ICFG_TUNNEL_PROTOCOL(protocol) \ @@ -1715,6 +1714,84 @@ get_plumbed_if_list(icfg_if_t **list, int *numif, int proto) { return (ICFG_SUCCESS); } +typedef struct linklist { + struct linklist *ll_next; + char ll_name[DLPI_LINKNAME_MAX]; +} linklist_t; + +typedef struct linkwalk { + linklist_t *lw_list; + int lw_num; + int lw_err; +} linkwalk_t; + +static boolean_t +add_link_list(const char *link, void *arg) +{ + linkwalk_t *lwp = (linkwalk_t *)arg; + linklist_t *entry = NULL; + + if ((entry = calloc(1, sizeof (linklist_t))) == NULL) { + lwp->lw_err = ENOMEM; + return (B_TRUE); + } + (void) strlcpy(entry->ll_name, link, DLPI_LINKNAME_MAX); + + if (lwp->lw_list == NULL) + lwp->lw_list = entry; + else + lwp->lw_list->ll_next = entry; + + lwp->lw_num++; + return (B_FALSE); +} + +/* + * Returns a list of data links that can be plumbed. The list of interfaces is + * returned as an array of icfg_if_t structures. The number of interfaces in + * the array will be returned via the 'numif' argument. + * + * Returns: ICFG_SUCCESS or ICFG_FAILURE. + */ +static int +get_link_list(icfg_if_t **listp, int *numif) { + + linkwalk_t lw = {NULL, 0, 0}; + linklist_t *entry, *next; + icfg_if_t *list; + int save_errno = 0; + int ret = ICFG_FAILURE; + + dlpi_walk(add_link_list, &lw, 0); + if (lw.lw_err != 0) { + errno = lw.lw_err; + goto done; + } + + list = calloc(lw.lw_num, sizeof (icfg_if_t)); + if (list == NULL) + goto done; + + for (entry = lw.lw_list; entry != NULL; entry = entry->ll_next) { + (void) strlcpy(list->if_name, entry->ll_name, + sizeof (list->if_name)); + list->if_protocol = AF_UNSPEC; + list++; + } + *listp = list; + *numif = lw.lw_num; + ret = ICFG_SUCCESS; + +done: + save_errno = errno; + for (entry = lw.lw_list; entry != NULL; entry = next) { + next = entry->ll_next; + free(entry); + } + errno = save_errno; + return (ret); +} + /* * Returns a list of network interfaces. The list of * interfaces is returned as an array of icfg_if_t structures. @@ -1742,7 +1819,7 @@ icfg_get_if_list(icfg_if_t **list, int *numif, int proto, int type) if (type == ICFG_PLUMBED) { return (get_plumbed_if_list(list, numif, proto)); } else if (type == ICFG_INSTALLED) { - return (nic_get_list(list, numif)); + return (get_link_list(list, numif)); } else { errno = EINVAL; return (ICFG_FAILURE); diff --git a/usr/src/lib/libinetcfg/common/inetcfg_nic.c b/usr/src/lib/libinetcfg/common/inetcfg_nic.c deleted file mode 100644 index 2aae088392..0000000000 --- a/usr/src/lib/libinetcfg/common/inetcfg_nic.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * 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. - * - * 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 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <libdevinfo.h> -#include <inetcfg.h> - -/* - * Always traverse the device tree from the root. - */ -#define NIC_DEVTREE_ROOT "/" - -/* - * Private structure used to create a linked list - * of interfaces. - */ -typedef struct niclist { - struct niclist *nl_next; - char nl_name[LIFNAMSIZ]; -} niclist_t; - -/* - * Private structure used by di_walk_minor(). - */ -typedef struct wlkreq { - niclist_t **wr_niclist; - int *wr_numif; - int *wr_syserr; - int *wr_err; -} wlkreq_t; - -/* - * Called by di_walk_node() to walk the list of device nodes and - * force all nodes of type "network" to be loaded. - * - * Returns: DI_WALK_CONTINUE - */ -static int -process_node(di_node_t node, void *arg) -{ - di_prom_handle_t ph = (di_prom_handle_t)arg; - char *pdevtype; - int ret; - - /* - * Only want to process nodes whose device_type is "network". - */ - ret = di_prom_prop_lookup_strings(ph, node, "device_type", &pdevtype); - if ((ret <= 0) || (strcmp(pdevtype, "network") != 0)) { - return (DI_WALK_CONTINUE); - } - - /* - * If the instance is '-1', then the driver for the device - * has not been loaded - so force it to be loaded. Ignore - * errors loading the driver. - */ - if (di_instance(node) == -1) { - node = di_init_driver(di_driver_name(node), 0); - if (node != DI_NODE_NIL) { - di_fini(node); - } - } - return (DI_WALK_CONTINUE); -} - -/* - * Force all "network" drivers to be loaded. - * - * Returns: ICFG_SUCCESS or ICFG_FAILURE. In the case of - * ICFG_FAILURE, syserr will contain the errno. - */ -static int -nic_load_drivers(int *syserr) -{ - di_node_t root_node; - di_prom_handle_t ph; - int ret; - - root_node = di_init(NIC_DEVTREE_ROOT, DINFOCPYALL); - if (root_node == DI_NODE_NIL) { - *syserr = errno; - return (ICFG_FAILURE); - } - - /* - * Create handle to PROM - */ - if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) { - *syserr = errno; - di_fini(root_node); - return (ICFG_FAILURE); - } - - /* - * Walk nodes and make sure all network devices have - * drivers loaded so that devinfo has accurate data. - */ - ret = di_walk_node(root_node, DI_WALK_CLDFIRST, ph, process_node); - if (ret != 0) { - *syserr = errno; - di_prom_fini(ph); - di_fini(root_node); - return (ICFG_FAILURE); - } - - /* - * Clean up handles - */ - di_prom_fini(ph); - di_fini(root_node); - - return (ICFG_SUCCESS); -} - -/* - * Add an interface to the niclist. - * - * Returns: ICFG_SUCCESS or ICFG_FAILURE. In the case of - * ICFG_FAILURE, syserr will contain the errno. - */ -static int -nic_add(niclist_t **niclist, char *name, int instance, int *syserr) -{ - - niclist_t *entry; - - /* - * Allocate new niclist. - */ - if ((entry = (niclist_t *)calloc(1, sizeof (niclist_t))) == NULL) { - *syserr = errno; - return (ICFG_FAILURE); - } - - /* - * If instance is -1, then no need to append instance. - */ - if (instance == -1) { - (void) strlcpy(entry->nl_name, name, sizeof (entry->nl_name)); - } else { - (void) snprintf(entry->nl_name, sizeof (entry->nl_name), - "%s%d", name, instance); - } - - /* - * Add entry to list. - */ - entry->nl_next = *niclist; - *niclist = entry; - - return (ICFG_SUCCESS); -} - -/* - * Called by di_walk_minor() to walk the list - * of ddi_network minor device nodes and add - * the interface to the niclist. - * - * Returns: DI_WALK_CONTINUE or DI_WALK_TERMINATE. - */ -static int -nic_process_minor_nodes(di_node_t node, di_minor_t minor, void *arg) -{ - wlkreq_t *request = (wlkreq_t *)arg; - niclist_t **niclist = request->wr_niclist; - char *name; - char *nodetype; - int instance; - int ret; - - /* - * Look for network devices only. Unfortunately, our walk will - * include nodes with nodetypes of NULL. - */ - nodetype = di_minor_nodetype(minor); - if ((nodetype == NULL) || (strcmp(nodetype, DDI_NT_NET) != 0)) { - return (DI_WALK_CONTINUE); - } - - /* - * In the case of DDM_MINOR minor nodes, the minor - * name is the name of the driver. However, if the name - * doesn't include the instance, then it's not one - * one we're interested in. In the case of other - * minor nodes, we should be able to get the driver name - * and its instance from the node properties. If they are - * not valid, then we're not interested in them. - */ - if (di_minor_type(minor) == DDM_MINOR) { - name = di_minor_name(minor); - if ((name == NULL) || (strlen(name) == 0) || - (!isdigit(name[strlen(name) - 1]))) { - return (DI_WALK_CONTINUE); - } - instance = -1; - } else { - name = di_driver_name(node); - instance = di_instance(node); - if ((name == NULL) || (strlen(name) == 0) || - (instance == -1)) { - return (DI_WALK_CONTINUE); - } - } - - /* - * Add this one to the niclist. - */ - ret = nic_add(niclist, name, instance, request->wr_syserr); - if (ret != ICFG_SUCCESS) { - (*request->wr_err) = ret; - return (DI_WALK_TERMINATE); - } - (*request->wr_numif)++; - - return (DI_WALK_CONTINUE); - -} - -/* - * Frees the resources associated with a niclist. - */ -static void -nic_free_list(niclist_t *niclist) -{ - niclist_t *entry; - - for (entry = niclist; entry != NULL; entry = niclist) { - niclist = niclist->nl_next; - free(entry); - } -} - -/* - * Drives the walk of the network minor device nodes to - * build the niclist. - * - * Returns: ICFG_SUCCESS or ICFG_FAILURE. In the case of - * ICFG_FAILURE, syserr will contain the errno. - */ -static int -nic_build_list(niclist_t **niclist, int *numif, int *syserr) -{ - wlkreq_t request; - di_node_t root_node; - int err = ICFG_SUCCESS; - int ret; - - root_node = di_init(NIC_DEVTREE_ROOT, DINFOSUBTREE | DINFOMINOR); - if (root_node == DI_NODE_NIL) { - *syserr = errno; - return (ICFG_FAILURE); - } - - /* - * di_walk_minor() only allows one arg to be passed to walker. - */ - request.wr_niclist = niclist; - request.wr_numif = numif; - request.wr_syserr = syserr; - request.wr_err = &err; - - ret = di_walk_minor(root_node, DDI_NT_NET, DI_CHECK_ALIAS, &request, - nic_process_minor_nodes); - if (ret != 0) { - *syserr = errno; - di_fini(root_node); - return (ICFG_FAILURE); - } - - /* - * On error, free the partially formed list. - */ - if (err != ICFG_SUCCESS) { - nic_free_list(*niclist); - *numif = 0; - } - - di_fini(root_node); - return (err); -} - -/* - * Convert a niclist into an icfg_if_t array. - * - * Returns: ICFG_SUCCESS or ICFG_FAILURE. In the case of - * ICFG_FAILURE, syserr will contain the errno. - */ -static int -nic_convert_list(icfg_if_t **list, niclist_t *niclist, int numif, - int *syserr) -{ - icfg_if_t *listp; - niclist_t *entry; - - if ((listp = calloc(numif, sizeof (icfg_if_t))) == NULL) { - *syserr = errno; - return (ICFG_FAILURE); - } - *list = listp; - - for (entry = niclist; entry != NULL; entry = entry->nl_next) { - (void) strlcpy(listp->if_name, entry->nl_name, - sizeof (listp->if_name)); - listp->if_protocol = AF_UNSPEC; - listp++; - } - - return (ICFG_SUCCESS); -} - -/* - * Returns the list of network devices installed - * on the machine as an icfg_if_t array. - * - * Returns: ICFG_SUCCESS or ICFG_FAILURE. In the case of - * ICFG_FAILURE, errno will be set. - */ -int -nic_get_list(icfg_if_t **list, int *numif) -{ - niclist_t *niclist = NULL; - int syserr; - int ret; - - if ((ret = nic_load_drivers(&syserr)) != ICFG_SUCCESS) { - goto out; - } - - if ((ret = nic_build_list(&niclist, numif, &syserr)) != ICFG_SUCCESS) { - goto out; - } - - if ((ret = nic_convert_list(list, niclist, *numif, &syserr)) != - ICFG_SUCCESS) { - goto out; - } - -out: - nic_free_list(niclist); - errno = syserr; - return (ret); -} diff --git a/usr/src/lib/librcm/Makefile.com b/usr/src/lib/librcm/Makefile.com index 0678946b95..8d7fe5f117 100644 --- a/usr/src/lib/librcm/Makefile.com +++ b/usr/src/lib/librcm/Makefile.com @@ -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" @@ -31,6 +31,9 @@ OBJECTS= librcm.o librcm_event.o include ../../Makefile.lib +# install this library in the root filesystem +include ../../Makefile.rootfs + LIBS = $(DYNLIB) $(LINTLIB) LDLIBS += -lc -lnvpair $(LINTLIB) := SRCS = ../llib-lrcm diff --git a/usr/src/lib/librcm/librcm.h b/usr/src/lib/librcm/librcm.h index be57013b0a..49ca304a08 100644 --- a/usr/src/lib/librcm/librcm.h +++ b/usr/src/lib/librcm/librcm.h @@ -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. */ @@ -97,8 +97,10 @@ extern "C" { #define RCM_CLIENT_NAME "rcm.client_name" #define RCM_CLIENT_EXPORTS "rcm.client_exports" -/* Resource name to register for new network resources */ +/* Resource name to register for new resources */ #define RCM_RESOURCE_NETWORK_NEW "SUNW_event/resource/new/network" +/* Resource name to register for new links come up */ +#define RCM_RESOURCE_LINK_NEW "SUNW_event/resource/new/link" /* name-value pair definitions for rcm_notify_event() */ #define RCM_NV_DRIVER_NAME "driver_name" @@ -109,6 +111,7 @@ extern "C" { #define RCM_NV_MINOR_TYPE "minor_type" #define RCM_NV_MINOR_NAME "minor_name" #define RCM_NV_MINOR_NODE_TYPE "minor_node_type" +#define RCM_NV_LINKID "linkid" /* * rcm handles diff --git a/usr/src/lib/libuuid/Makefile.com b/usr/src/lib/libuuid/Makefile.com index d1178c5bc6..9611fcd062 100644 --- a/usr/src/lib/libuuid/Makefile.com +++ b/usr/src/lib/libuuid/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" @@ -35,7 +35,7 @@ include ../../Makefile.lib include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lsocket -lnsl -lc -ldlpi -ldladm +LDLIBS += -lsocket -lnsl -lc -ldlpi SRCDIR = ../common $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libuuid/common/etheraddr.c b/usr/src/lib/libuuid/common/etheraddr.c index 6b2011150e..08030e79cf 100644 --- a/usr/src/lib/libuuid/common/etheraddr.c +++ b/usr/src/lib/libuuid/common/etheraddr.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. */ @@ -33,7 +33,6 @@ #include <uuid/uuid.h> #include <sys/sockio.h> #include <libdlpi.h> -#include <libdllink.h> #include <sys/utsname.h> #include <netdb.h> @@ -42,12 +41,7 @@ #include "etheraddr.h" -/* - * debugging flag - */ -static int debug = 0; - -static void get_etheraddr(void *arg, const char *linkname); +static boolean_t get_etheraddr(const char *linkname, void *arg); /* * get an individual arp entry @@ -114,50 +108,35 @@ get_ethernet_address(uuid_node_t *node) * Try to get physical (ethernet) address from network interfaces. */ state.wa_addrvalid = B_FALSE; - if (dladm_walk(get_etheraddr, &state) == 0 && state.wa_addrvalid) { + dlpi_walk(get_etheraddr, &state, 0); + if (state.wa_addrvalid) bcopy(state.wa_etheraddr, node, state.wa_etheraddrlen); - } return (state.wa_addrvalid ? 0 : -1); } /* - * Get the physical address via dlpi and update the flag to true upon success. + * Get the physical address via DLPI and update the flag to true upon success. */ -static void -get_etheraddr(void *arg, const char *linkname) +static boolean_t +get_etheraddr(const char *linkname, void *arg) { int retval; dlpi_handle_t dh; walker_arg_t *statep = arg; - if (!(statep->wa_addrvalid)) { - if (debug) - (void) printf("get_etheraddr: opening %s\n", linkname); - if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { - if (debug) { - (void) fprintf(stderr, "get_etheraddr: " - "cannot open link: \"%s\" %s\n", - linkname, retval); - } - return; - } + if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) + return (B_FALSE); - if (debug) { - (void) printf("get_etheraddr: getting ethernet address" - " from link: %s\n", linkname); - } - statep->wa_etheraddrlen = DLPI_PHYSADDR_MAX; - retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, - statep->wa_etheraddr, &(statep->wa_etheraddrlen)); - if (debug) { - (void) fprintf(stderr, "get_etheraddr: " - "dlpi_get_physaddr: \"%s\" %s\n", linkname, retval); - } + statep->wa_etheraddrlen = DLPI_PHYSADDR_MAX; + retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, + statep->wa_etheraddr, &(statep->wa_etheraddrlen)); - if (retval == DLPI_SUCCESS) - statep->wa_addrvalid = B_TRUE; + dlpi_close(dh); - dlpi_close(dh); + if (retval == DLPI_SUCCESS) { + statep->wa_addrvalid = B_TRUE; + return (B_TRUE); } + return (B_FALSE); } diff --git a/usr/src/lib/libuuid/common/uuid.c b/usr/src/lib/libuuid/common/uuid.c index c494f847d6..db3dd1105f 100644 --- a/usr/src/lib/libuuid/common/uuid.c +++ b/usr/src/lib/libuuid/common/uuid.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 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -273,9 +272,9 @@ _read_state(int fd, uint16_t *clockseq, *timestamp = 0; *clockseq = 0; - if (read(fd, &vol_state, sizeof (uuid_state_t)) < - sizeof (uuid_state_t)) { + if (read(fd, &vol_state, sizeof (vol_state)) < sizeof (vol_state)) { /* This file is being accessed the first time */ + return; } *node = vol_state.node; diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com index 091f59028d..3652da4eee 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_com +++ b/usr/src/pkgdefs/SUNWarc/prototype_com @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -159,8 +159,6 @@ s none usr/lib/llib-lposix4=../../lib/llib-lrt s none usr/lib/llib-lposix4.ln=../../lib/llib-lrt.ln f none usr/lib/llib-lproject 644 root bin f none usr/lib/llib-lproject.ln 644 root bin -f none usr/lib/llib-lrcm 644 root bin -f none usr/lib/llib-lrcm.ln 644 root bin s none usr/lib/llib-lresolv=../../lib/llib-lresolv s none usr/lib/llib-lresolv.ln=../../lib/llib-lresolv.ln s none usr/lib/llib-lrpcsvc=../../lib/llib-lrpcsvc diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386 index 14c4a723e8..8ccb82608d 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarc/prototype_i386 @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -125,7 +125,6 @@ s none usr/lib/amd64/llib-lrt.ln=../../../lib/amd64/llib-lrt.ln s none usr/lib/amd64/llib-lrtld_db.ln=../../../lib/amd64/llib-lrtld_db.ln f none usr/lib/amd64/llib-lpasswdutil.ln 644 root bin s none usr/lib/amd64/llib-lposix4.ln=../../../lib/amd64/llib-lrt.ln -f none usr/lib/amd64/llib-lrcm.ln 644 root bin f none usr/lib/amd64/llib-lsasl.ln 644 root bin s none usr/lib/amd64/llib-lscf.ln=../../../lib/amd64/llib-lscf.ln f none usr/lib/amd64/llib-lsched.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc index 78417f1525..b6b1d53bdd 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -120,7 +120,6 @@ s none usr/lib/sparcv9/llib-lrpcsvc.ln=../../../lib/sparcv9/llib-lrpcsvc.ln s none usr/lib/sparcv9/llib-lrt.ln=../../../lib/sparcv9/llib-lrt.ln s none usr/lib/sparcv9/llib-lrtld_db.ln=../../../lib/sparcv9/llib-lrtld_db.ln s none usr/lib/sparcv9/llib-lposix4.ln=../../../lib/sparcv9/llib-lrt.ln -f none usr/lib/sparcv9/llib-lrcm.ln 644 root bin f none usr/lib/sparcv9/llib-lsasl.ln 644 root bin s none usr/lib/sparcv9/llib-lscf.ln=../../../lib/sparcv9/llib-lscf.ln f none usr/lib/sparcv9/llib-lsched.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_com b/usr/src/pkgdefs/SUNWarcr/prototype_com index f27bca5bd1..9d8016f525 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_com +++ b/usr/src/pkgdefs/SUNWarcr/prototype_com @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -100,6 +100,8 @@ s none lib/llib-lposix4=./llib-lrt s none lib/llib-lposix4.ln=./llib-lrt.ln f none lib/llib-lpthread 644 root bin f none lib/llib-lpthread.ln 644 root bin +f none lib/llib-lrcm 644 root bin +f none lib/llib-lrcm.ln 644 root bin f none lib/llib-lresolv 644 root bin f none lib/llib-lresolv.ln 644 root bin f none lib/llib-lrpcsvc 644 root bin diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_i386 b/usr/src/pkgdefs/SUNWarcr/prototype_i386 index d506baf18f..6bd6be4199 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarcr/prototype_i386 @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -80,6 +80,7 @@ f none lib/amd64/llib-lnvpair.ln 644 root bin f none lib/amd64/llib-lpam.ln 644 root bin s none lib/amd64/llib-lposix4.ln=./llib-lrt.ln f none lib/amd64/llib-lpthread.ln 644 root bin +f none lib/amd64/llib-lrcm.ln 644 root bin f none lib/amd64/llib-lresolv.ln 644 root bin f none lib/amd64/llib-lrpcsvc.ln 644 root bin f none lib/amd64/llib-lrt.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_sparc b/usr/src/pkgdefs/SUNWarcr/prototype_sparc index ec45dc0489..f12ae1bd5d 100644 --- a/usr/src/pkgdefs/SUNWarcr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarcr/prototype_sparc @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -80,6 +80,7 @@ f none lib/sparcv9/llib-lnvpair.ln 644 root bin f none lib/sparcv9/llib-lpam.ln 644 root bin s none lib/sparcv9/llib-lposix4.ln=./llib-lrt.ln f none lib/sparcv9/llib-lpthread.ln 644 root bin +f none lib/sparcv9/llib-lrcm.ln 644 root bin f none lib/sparcv9/llib-lresolv.ln 644 root bin f none lib/sparcv9/llib-lrpcsvc.ln 644 root bin f none lib/sparcv9/llib-lrt.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWckr/prototype_com b/usr/src/pkgdefs/SUNWckr/prototype_com index 67d9395f31..f079d77bef 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_com +++ b/usr/src/pkgdefs/SUNWckr/prototype_com @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -111,6 +111,7 @@ f none kernel/drv/sysevent.conf 644 root sys f none kernel/drv/sysmsg.conf 644 root sys f none kernel/drv/sctp.conf 644 root sys f none kernel/drv/sctp6.conf 644 root sys +f none kernel/drv/softmac.conf 644 root sys f none kernel/drv/tcp.conf 644 root sys f none kernel/drv/tcp6.conf 644 root sys f none kernel/drv/tl.conf 644 root sys diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386 index 670bc09371..a6035e933a 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 @@ -59,6 +59,7 @@ f none kernel/crypto/rsa 755 root sys f none kernel/crypto/sha1 755 root sys f none kernel/crypto/sha2 755 root sys f none kernel/crypto/swrand 755 root sys +f none kernel/dacf/net_dacf 755 root sys f none kernel/devname/sdev_nsconfig_mod 755 root sys f none kernel/drv/aggr 755 root sys f none kernel/drv/arp 755 root sys @@ -123,6 +124,7 @@ f none kernel/drv/sctp6 755 root sys f none kernel/drv/sgen 755 root sys f none kernel/drv/smbios 755 root sys f none kernel/drv/smbios.conf 644 root sys +f none kernel/drv/softmac 755 root sys f none kernel/drv/spdsock 755 root sys f none kernel/drv/st 755 root sys f none kernel/drv/sy 755 root sys @@ -263,6 +265,8 @@ f none kernel/crypto/amd64/rsa 755 root sys f none kernel/crypto/amd64/sha1 755 root sys f none kernel/crypto/amd64/sha2 755 root sys f none kernel/crypto/amd64/swrand 755 root sys +d none kernel/dacf/amd64 755 root sys +f none kernel/dacf/amd64/net_dacf 755 root sys d none kernel/devname/amd64 755 root sys f none kernel/devname/amd64/sdev_nsconfig_mod 755 root sys d none kernel/drv/amd64 755 root sys @@ -322,6 +326,7 @@ f none kernel/drv/amd64/sctp6 755 root sys f none kernel/drv/amd64/sd 755 root sys f none kernel/drv/amd64/sgen 755 root sys f none kernel/drv/amd64/smbios 755 root sys +f none kernel/drv/amd64/softmac 755 root sys f none kernel/drv/amd64/spdsock 755 root sys f none kernel/drv/amd64/st 755 root sys f none kernel/drv/amd64/sy 755 root sys diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc index 43e9f4889e..51074255f0 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc @@ -63,6 +63,7 @@ f none kernel/crypto/sparcv9/sha2 755 root sys f none kernel/crypto/sparcv9/swrand 755 root sys d none kernel/dacf/sparcv9 755 root sys f none kernel/dacf/sparcv9/consconfig_dacf 755 root sys +f none kernel/dacf/sparcv9/net_dacf 755 root sys f none kernel/drv/dad.conf 644 root sys f none kernel/drv/px_pci.conf 644 root sys f none kernel/drv/pxb_plx.conf 644 root sys @@ -123,6 +124,7 @@ f none kernel/drv/sparcv9/sctp 755 root sys f none kernel/drv/sparcv9/sctp6 755 root sys f none kernel/drv/sparcv9/sd 755 root sys f none kernel/drv/sparcv9/sgen 755 root sys +f none kernel/drv/sparcv9/softmac 755 root sys f none kernel/drv/sparcv9/spdsock 755 root sys f none kernel/drv/sparcv9/st 755 root sys f none kernel/drv/sparcv9/sy 755 root sys diff --git a/usr/src/pkgdefs/SUNWcnetr/postinstall b/usr/src/pkgdefs/SUNWcnetr/postinstall index 834e924338..b92d8eafe3 100644 --- a/usr/src/pkgdefs/SUNWcnetr/postinstall +++ b/usr/src/pkgdefs/SUNWcnetr/postinstall @@ -18,18 +18,96 @@ # # 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" # -# Move existing /etc/aggregation.conf entries to /etc/dladm/aggregation.conf -ORIG=$BASEDIR/etc/aggregation.conf -if [ -f $ORIG ]; then - # use cat instead of cp/mv to keep owner+group of dest - cat $ORIG > $BASEDIR/etc/dladm/aggregation.conf + +# +# Convert datalink configuration into a series of dladm(1M) commands and +# keep them in an upgrade script. This script will then be run in the +# network-physical service. +# +# Note that we cannot use the /var/svc/profile/upgrade script because +# that script is run during manifest-import which is too late for +# datalink configuration. +# +UPGRADE_SCRIPT=/var/svc/profile/upgrade_datalink + +AGGR_CONF=/etc/aggregation.conf +ORIG=$BASEDIR/$AGGR_CONF +if [ ! -f "${ORIG}" ]; then + # Try the alternate location. + AGGR_CONF=/etc/dladm/aggregation.conf + ORIG=$BASEDIR/$AGGR_CONF +fi + +# Now upgrade aggregation.conf to the new format. +if [ -f "${ORIG}" ]; then + # Strip off comments, then each remaining line defines an + # aggregation the admnistrator configured on the old system. + # Each line corresponds to one dladm command that is appended + # to the upgrade script. + cat $ORIG | grep '^[^#]' | while read line; do + echo $line | while read aggr_index rest + do + policy=`echo $rest | /usr/bin/awk '{print $1}'` + nports=`echo $rest | /usr/bin/awk '{print $2}'` + ports=`echo $rest | /usr/bin/awk '{print $3}'` + mac=`echo $rest | /usr/bin/awk '{print $4}'` + lacp_mode=`echo $rest | /usr/bin/awk '{print $5}'` + lacp_timer=`echo $rest | /usr/bin/awk '{print $6}'` + dladm_string="dladm create-aggr -P $policy -l \ + $lacp_mode -T $lacp_timer" + # A fixed MAC address + if [ "${mac}" != "auto" ]; then + dladm_string="$dladm_string -u $mac" + fi + i=1 + while [ $i -le "${nports}" ]; do + device=`echo $ports | cut -d, -f$i` + # Older aggregation.conf files have the format + # of device_name/port_number. We don't need + # the port number, so get rid of it if it is + # there. + device=`echo $device | cut -d/ -f1` + i=`expr $i + 1` + dladm_string="$dladm_string -d $device" + done + dladm_string="$dladm_string $aggr_index" + echo $dladm_string >> \ + ${PKG_INSTALL_ROOT}/$UPGRADE_SCRIPT + done + done + # no longer needed, get rid of it. + rm -f $ORIG + removef $PKGINST $AGGR_CONF > /dev/null + removef -f $PKGINST > /dev/null 2>&1 +fi + +# Upgrade linkprop.conf +ORIG=$BASEDIR/etc/dladm/linkprop.conf + +if [ -f "${ORIG}" ]; then + # Strip off comments, then each remaining line lists properties + # the administrator configured for a particular interface. + # Each line includes several properties, but we can only set + # one property per dladm invocation. + cat $ORIG | grep '^[^#]' | while read line; do + echo $line | while read link rest + do + while [ -n "${rest}" ]; do + linkprop=`echo $rest | cut -d";" -f1` + rest=`echo $rest | cut -d";" -f2-` + echo dladm set-linkprop -p $linkprop $link >> \ + ${PKG_INSTALL_ROOT}/$UPGRADE_SCRIPT + done + done + done + # no longer needed, get rid of it rm -f $ORIG - removef $PKGINST /etc/aggregation.conf > /dev/null + removef $PKGINST /etc/dladm/linkprop.conf > /dev/null removef -f $PKGINST > /dev/null 2>&1 fi diff --git a/usr/src/pkgdefs/SUNWcnetr/prototype_com b/usr/src/pkgdefs/SUNWcnetr/prototype_com index 5c58a3ec59..7ac9fa4428 100644 --- a/usr/src/pkgdefs/SUNWcnetr/prototype_com +++ b/usr/src/pkgdefs/SUNWcnetr/prototype_com @@ -50,9 +50,8 @@ i i.dhcpagent # d none etc 755 root sys d none etc/dladm 755 dladm sys -e preserve etc/dladm/aggregation.conf 644 dladm sys -e preserve etc/dladm/linkprop.conf 644 dladm sys e preserve etc/dladm/secobj.conf 600 dladm sys +e preserve etc/dladm/datalink.conf 644 dladm sys d none etc/default 755 root sys e dhcpagent etc/default/dhcpagent 644 root sys e preserve etc/default/inetinit 644 root sys diff --git a/usr/src/pkgdefs/SUNWcsd/prototype_com b/usr/src/pkgdefs/SUNWcsd/prototype_com index 8312217923..1c036a6c15 100644 --- a/usr/src/pkgdefs/SUNWcsd/prototype_com +++ b/usr/src/pkgdefs/SUNWcsd/prototype_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" @@ -72,6 +72,7 @@ i i.preserve d none dev 755 root sys d none dev/dsk 755 root sys d none dev/fd 555 root root +d none dev/net 755 root sys d none dev/pts 755 root sys d none dev/rdsk 755 root sys d none dev/rmt 755 root sys diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index ba88abbe25..3b070ff330 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -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" @@ -219,8 +219,8 @@ s none usr/lib/libproc.so.1=../../lib/libproc.so.1 s none usr/lib/libproc.so=../../lib/libproc.so.1 s none usr/lib/libpthread.so=../../lib/libpthread.so.1 s none usr/lib/libpthread.so.1=../../lib/libpthread.so.1 -s none usr/lib/librcm.so=./librcm.so.1 -f none usr/lib/librcm.so.1 755 root bin +s none usr/lib/librcm.so=../../lib/librcm.so.1 +s none usr/lib/librcm.so.1=../../lib/librcm.so.1 s none usr/lib/libresolv.so=../../lib/libresolv.so.2 s none usr/lib/libresolv.so.1=../../lib/libresolv.so.1 s none usr/lib/libresolv.so.2=../../lib/libresolv.so.2 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index 9571de2a01..c03e9554f6 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -286,8 +286,8 @@ s none usr/lib/amd64/libproc.so.1=../../../lib/amd64/libproc.so.1 s none usr/lib/amd64/libproc.so=../../../lib/amd64/libproc.so.1 s none usr/lib/amd64/libpthread.so.1=../../../lib/amd64/libpthread.so.1 s none usr/lib/amd64/libpthread.so=../../../lib/amd64/libpthread.so.1 -f none usr/lib/amd64/librcm.so.1 755 root bin -s none usr/lib/amd64/librcm.so=librcm.so.1 +s none usr/lib/amd64/librcm.so.1=../../../lib/amd64/librcm.so.1 +s none usr/lib/amd64/librcm.so=../../../lib/amd64/librcm.so.1 s none usr/lib/amd64/libresolv.so.2=../../../lib/amd64/libresolv.so.2 s none usr/lib/amd64/libresolv.so=../../../lib/amd64/libresolv.so.2 s none usr/lib/amd64/librpcsvc.so.1=../../../lib/amd64/librpcsvc.so.1 diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index 8cbccaab92..22376c5573 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -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" @@ -274,8 +274,8 @@ s none usr/lib/sparcv9/libproc.so.1=../../../lib/sparcv9/libproc.so.1 s none usr/lib/sparcv9/libproc.so=../../../lib/sparcv9/libproc.so.1 s none usr/lib/sparcv9/libpthread.so.1=../../../lib/sparcv9/libpthread.so.1 s none usr/lib/sparcv9/libpthread.so=../../../lib/sparcv9/libpthread.so.1 -f none usr/lib/sparcv9/librcm.so.1 755 root bin -s none usr/lib/sparcv9/librcm.so=librcm.so.1 +s none usr/lib/sparcv9/librcm.so.1=../../../lib/sparcv9/librcm.so.1 +s none usr/lib/sparcv9/librcm.so=../../../lib/sparcv9/librcm.so.1 s none usr/lib/sparcv9/libresolv.so.2=../../../lib/sparcv9/libresolv.so.2 s none usr/lib/sparcv9/libresolv.so=../../../lib/sparcv9/libresolv.so.2 s none usr/lib/sparcv9/librestart.so.1=../../../lib/sparcv9/librestart.so.1 diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_com b/usr/src/pkgdefs/SUNWcslr/prototype_com index cb2541f54d..7c30e112b9 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_com +++ b/usr/src/pkgdefs/SUNWcslr/prototype_com @@ -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" @@ -113,6 +113,8 @@ f none lib/libproc.so.1 755 root bin s none lib/libproc.so=libproc.so.1 f none lib/libpthread.so.1 755 root bin s none lib/libpthread.so=libpthread.so.1 +s none lib/librcm.so=./librcm.so.1 +f none lib/librcm.so.1 755 root bin s none lib/libresolv.so=libresolv.so.2 f none lib/libresolv.so.1 755 root bin f none lib/libresolv.so.2 755 root bin diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_i386 b/usr/src/pkgdefs/SUNWcslr/prototype_i386 index cd3f254f42..739d6c9e7b 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcslr/prototype_i386 @@ -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" @@ -114,6 +114,8 @@ s none lib/amd64/libproc.so=libproc.so.1 f none lib/amd64/libproc.so.1 755 root bin s none lib/amd64/libpthread.so=libpthread.so.1 f none lib/amd64/libpthread.so.1 755 root bin +s none lib/amd64/librcm.so=librcm.so.1 +f none lib/amd64/librcm.so.1 755 root bin s none lib/amd64/libresolv.so=libresolv.so.2 f none lib/amd64/libresolv.so.2 755 root bin s none lib/amd64/librestart.so=librestart.so.1 diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_sparc b/usr/src/pkgdefs/SUNWcslr/prototype_sparc index 9cdc618110..5cbfd8e0e9 100644 --- a/usr/src/pkgdefs/SUNWcslr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcslr/prototype_sparc @@ -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" @@ -115,6 +115,8 @@ f none lib/sparcv9/libproc.so.1 755 root bin s none lib/sparcv9/libproc.so=libproc.so.1 s none lib/sparcv9/libpthread.so=libpthread.so.1 f none lib/sparcv9/libpthread.so.1 755 root bin +s none lib/sparcv9/librcm.so=librcm.so.1 +f none lib/sparcv9/librcm.so.1 755 root bin s none lib/sparcv9/libresolv.so=libresolv.so.2 f none lib/sparcv9/libresolv.so.2 755 root bin f none lib/sparcv9/librestart.so.1 0755 root bin diff --git a/usr/src/pkgdefs/SUNWcsr/Makefile b/usr/src/pkgdefs/SUNWcsr/Makefile index 1bd6428e71..108112faa8 100644 --- a/usr/src/pkgdefs/SUNWcsr/Makefile +++ b/usr/src/pkgdefs/SUNWcsr/Makefile @@ -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" @@ -64,6 +64,7 @@ DATAFILES += \ r.rbac \ i.renamenew \ i.renameold \ + i.seedmanifest \ i.services \ i.shadow \ i.syslogconf \ diff --git a/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl index 3447c3832d..02cbf6c19b 100644 --- a/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -44,7 +44,7 @@ DESC="core software for a specific instruction-set architecture" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL="" -CLASSES="none ttydefs initd renamenew preserve cronroot passwd tiservices inetdconf definit etcremote nsswitch netconfig deflogin defsu syslogconf ttysrch group inittab etcrpc etcprofile mailxrc shadow locallogin localprofile logadmconf logindevperm nscd fstypes pamconf services rbac renameold dhcpinittab policyconf pkcs11confbase defpasswd defkbd vfstab manifest hosts kmfconfbase" +CLASSES="none ttydefs initd renamenew preserve cronroot passwd tiservices inetdconf definit etcremote nsswitch netconfig deflogin defsu syslogconf ttysrch group inittab etcrpc etcprofile mailxrc shadow locallogin localprofile logadmconf logindevperm nscd fstypes pamconf services rbac renameold dhcpinittab policyconf pkcs11confbase defpasswd defkbd vfstab manifest hosts kmfconfbase seedmanifest" BASEDIR=/ SUNW_PKGVERS="1.0" SUNW_PKG_ALLZONES="true" diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index fd364d5816..a978136dfc 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -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. # # ident "%Z%%M% %I% %E% SMI" @@ -84,6 +84,7 @@ i r.manifest i i.ttydefs i i.hosts i i.kmfconfbase +i i.seedmanifest # # source locations relative to the prototype file # @@ -127,6 +128,7 @@ d none etc/crypto/crls 755 root sys f none etc/datemsk 444 root sys s none etc/dcopy=../usr/sbin/dcopy d none etc/default 755 root sys +f none etc/.dlmgmt_door 444 root sys e preserve etc/default/cron 644 root sys e preserve etc/default/devfsadm 644 root sys e preserve etc/default/fs 644 root sys @@ -379,6 +381,7 @@ f none lib/svc/method/svc-consadm 0555 root bin f none lib/svc/method/svc-cron 0555 root bin f none lib/svc/method/svc-forwarding 0555 root bin f none lib/svc/method/svc-legacy-routing 0555 root bin +f none lib/svc/method/svc-dlmgmtd 0555 root bin f none lib/svc/method/svc-nscd 0555 root bin f none lib/svc/method/svc-utmpd 0555 root bin f none lib/svc/method/system-log 0555 root bin @@ -411,6 +414,7 @@ f none sbin/soconfig 555 root bin f none sbin/init 555 root sys s none sbin/jsh=sh s none sbin/pfsh=sh +f none sbin/dlmgmtd 555 root bin f none sbin/mount 555 root bin f none sbin/mountall 555 root sys f none sbin/netstrategy 555 root bin @@ -496,6 +500,7 @@ d none var/svc/manifest/network 755 root sys f manifest var/svc/manifest/network/forwarding.xml 0444 root sys f manifest var/svc/manifest/network/inetd.xml 0444 root sys f manifest var/svc/manifest/network/inetd-upgrade.xml 0444 root sys +f seedmanifest var/svc/manifest/network/dlmgmt.xml 0444 root sys f manifest var/svc/manifest/network/network-initial.xml 0444 root sys f manifest var/svc/manifest/network/network-loopback.xml 0444 root sys f manifest var/svc/manifest/network/network-physical.xml 0444 root sys diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 13f5d5ada7..6fe9f5d9c6 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_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" @@ -636,6 +636,8 @@ f none usr/lib/rcm/modules/SUNW_ip_anon_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_ip_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_mpxio_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_network_rcm.so 555 root bin +f none usr/lib/rcm/modules/SUNW_vlan_rcm.so 555 root bin +f none usr/lib/rcm/modules/SUNW_aggr_rcm.so 555 root bin f none usr/lib/rcm/modules/SUNW_swap_rcm.so 555 root bin f none usr/lib/rcm/rcm_daemon 555 root bin d none usr/lib/rcm/scripts 755 root bin diff --git a/usr/src/pkgdefs/common_files/i.minorperm_i386 b/usr/src/pkgdefs/common_files/i.minorperm_i386 index 3fcbe492a5..7ce4b86cce 100644 --- a/usr/src/pkgdefs/common_files/i.minorperm_i386 +++ b/usr/src/pkgdefs/common_files/i.minorperm_i386 @@ -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" @@ -307,6 +307,7 @@ kssl:* fbt:fbt profile:profile sdt:sdt +softmac:* systrace:systrace lx_ptm:lx_ptmajor lx_systrace:* diff --git a/usr/src/pkgdefs/common_files/i.minorperm_sparc b/usr/src/pkgdefs/common_files/i.minorperm_sparc index 982301f228..6085660226 100644 --- a/usr/src/pkgdefs/common_files/i.minorperm_sparc +++ b/usr/src/pkgdefs/common_files/i.minorperm_sparc @@ -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" @@ -330,6 +330,7 @@ kssl:* fbt:fbt profile:profile sdt:sdt +softmac:* systrace:systrace physmem:* smbsrv:* diff --git a/usr/src/pkgdefs/common_files/i.seedmanifest b/usr/src/pkgdefs/common_files/i.seedmanifest new file mode 100644 index 0000000000..e112bb6285 --- /dev/null +++ b/usr/src/pkgdefs/common_files/i.seedmanifest @@ -0,0 +1,68 @@ +#!/bin/sh +# +# 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" +# +# i.seedmanifest - smf(5) service manifest install class action script +# for services that must be in the seed repository. +# +# PLEASE NOTE: Use of this CAS means that the SMF repository format cannot +# change, since it may need to modify an SMF repository on another system +# image. As such, any use of this CAS must be cleared with the SMF team. +# + +repfile=$PKG_INSTALL_ROOT/etc/svc/repository.db + +# +# If the repository does not yet exist, create it from the appropriate seed. +# +if [ ! -f $repfile ]; then + if [ -n "$SUNW_PKG_INSTALL_ZONENAME" -a \ + "$SUNW_PKG_INSTALL_ZONENAME" != "global" ]; then + dbfile=nonglobal.db + else + dbfile=global.db + fi + + if [ -f $PKG_INSTALL_ROOT/lib/svc/seed/$dbfile ]; then + /usr/bin/cp $PKG_INSTALL_ROOT/lib/svc/seed/$dbfile $repfile + /usr/bin/chmod 0600 $repfile + /usr/bin/chown root:sys $repfile + fi + + # + # Since our service is in the seed, we're done. + # + exit 0 +fi + +while read src dst; do + /usr/bin/cp -p $src $dst + + SVCCFG_REPOSITORY=$repfile SVCCFG_CHECKHASH=1 \ + /usr/sbin/svccfg import $dst +done + +exit 0 diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index 5cce2bb77a..6386d20ffd 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -82,14 +82,14 @@ usr/lib/libdhcpsvc.so i386 # # Private MAC driver header files # -usr/include/sys/aggr.h i386 -usr/include/sys/aggr_impl.h i386 -usr/include/sys/dld.h i386 -usr/include/sys/dld_impl.h i386 -usr/include/sys/dls.h i386 -usr/include/sys/dls_impl.h i386 -usr/include/sys/mac.h i386 -usr/include/sys/mac_impl.h i386 +usr/include/sys/aggr.h i386 +usr/include/sys/aggr_impl.h i386 +usr/include/sys/dld.h i386 +usr/include/sys/dld_impl.h i386 +usr/include/sys/dls.h i386 +usr/include/sys/dls_impl.h i386 +usr/include/sys/mac.h i386 +usr/include/sys/mac_impl.h i386 # # Private GLDv3 userland libraries and headers # @@ -100,6 +100,8 @@ usr/include/libdlaggr.h i386 usr/include/libdlwlan.h i386 usr/include/libdlwlan_impl.h i386 usr/include/libdlvnic.h i386 +usr/include/libdlvlan.h i386 +usr/include/libdlmgmt.h i386 lib/libdladm.so i386 lib/llib-ldladm.ln i386 lib/amd64/libdladm.so i386 diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 1276876a82..31c3fe737a 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -89,6 +89,8 @@ usr/include/libdlaggr.h sparc usr/include/libdlwlan.h sparc usr/include/libdlwlan_impl.h sparc usr/include/libdlvnic.h sparc +usr/include/libdlvlan.h sparc +usr/include/libdlmgmt.h sparc lib/libdladm.so sparc lib/llib-ldladm.ln sparc lib/sparcv9/libdladm.so sparc diff --git a/usr/src/tools/abi/etc/ABI_i386.db b/usr/src/tools/abi/etc/ABI_i386.db index a931463e13..8923034d4a 100644 --- a/usr/src/tools/abi/etc/ABI_i386.db +++ b/usr/src/tools/abi/etc/ABI_i386.db @@ -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. # # CDDL HEADER START @@ -19672,8 +19672,8 @@ creat64 lib/libpthread.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.4 SUNW_1.1 000000 creat64 lib/libthread.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.6.1 SUNW_1.1 0000001 0000001 0 0 0 0 0 0 createQuery usr/lib/libnisdb.so.2 0 0 0 0 0 0 0 0 0 0 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 0000111 0 0000111 0 0 0 0 0 create_auth_reply usr/lib/libkrb.so.1 0 0 SUNW_1.1 SUNW_0.7 0 0 0 0 0 0 0 0 0 0 0 0 1111111 1000000 0 0111111 0 0 0 0 -create_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -create_event_service usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +create_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +create_event_service lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 create_history_entry usr/lib/krb5/libkadm5srv.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 create_policy_1 usr/lib/krb5/libkadm5clnt.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 create_policy_1 usr/lib/krb5/amd64/libkadm5clnt.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 @@ -24405,8 +24405,8 @@ get_der_length usr/lib/amd64/libgss.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate get_devname usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 get_devname lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 get_either_iter usr/lib/krb5/libkadm5srv.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0000111 0 0000111 0 0 0 0 0 -get_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -get_event_service usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +get_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +get_event_service lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 get_hspname usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 get_hspname lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 get_install_root usr/lib/libadm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0001111 0 0001110 0000001 0 0 0 0 @@ -37990,96 +37990,96 @@ raw lib/amd64/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 00000 raw lib/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 0000001 0000001 0 0 0 0 0 0 rb_test usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 rb_test lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_alloc_handle usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_alloc_handle usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_append_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_append_info usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_dir usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_exec_cmd usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_exec_cmd usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_free_handle usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_handle usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_free_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_info usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_client_name usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_client_name usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_get_info usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_info_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_info_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_rsrcstate usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_rsrcstate usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_script_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_script_dir usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_error usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_error usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_info usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_modname usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_modname usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_next usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_next usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_pid usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_pid usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_properties usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_properties usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_rsrc usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_rsrc usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_seqnum usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_seqnum usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_info_state usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_state usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_is_script usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_is_script usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_log_message usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_log_message usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_module_close usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_close usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_module_dir usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_dir usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_module_open usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_open usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_capacity_change usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_capacity_change usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_event usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_online usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_online usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_online_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_online_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_remove usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_remove usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_remove_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_remove_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_resume usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_resume usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_notify_resume_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_resume_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_register_capacity usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_capacity usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_register_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_event usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_register_interest usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_register_interest usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_request_capacity_change usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_capacity_change usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_request_offline usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_offline usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_request_offline_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_offline_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_request_suspend usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_suspend usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_request_suspend_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_suspend_list usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_script_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_script_dir usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_unregister_capacity usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_capacity usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_unregister_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_event usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_unregister_interest usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_unregister_interest usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_alloc_handle lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_alloc_handle lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_append_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_append_info lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_dir lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_exec_cmd lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_exec_cmd lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_free_handle lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_handle lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_free_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_info lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_client_name lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_client_name lib/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_get_info lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_info_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_info_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_rsrcstate lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_rsrcstate lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_script_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_script_dir lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_error lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_error lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_info lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_modname lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_modname lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_next lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_next lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_pid lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_pid lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_properties lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_properties lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_rsrc lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_rsrc lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_seqnum lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_seqnum lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_info_state lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_state lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_is_script lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_is_script lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_log_message lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_log_message lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_module_close lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_close lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_module_dir lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_dir lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_module_open lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_open lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_capacity_change lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_capacity_change lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_event lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_online lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_online lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_online_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_online_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_remove lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_remove lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_remove_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_remove_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_resume lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_resume lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_notify_resume_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_resume_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_register_capacity lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_capacity lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_register_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_event lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_register_interest lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_register_interest lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_request_capacity_change lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_capacity_change lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_request_offline lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_offline lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_request_offline_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_offline_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_request_suspend lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_suspend lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_request_suspend_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_suspend_list lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_script_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_script_dir lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_unregister_capacity lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_capacity lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_unregister_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_event lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_unregister_interest lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_unregister_interest lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 rcmd usr/lib/libsocket.so.1 0 0 SUNW_1.3 SUNW_0.7 0 0 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 0 0 1111111 1011110 0 0100001 0 0 0 0 rcmd lib/amd64/libsocket.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.5 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 rcmd lib/libsocket.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.5 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 @@ -38773,8 +38773,8 @@ restartterm lib/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 000 resync_genid usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 resync_genid lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 retrieve_inetd_hash usr/lib/libinetsvc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -revoke_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -revoke_event_service usr/lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +revoke_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +revoke_event_service lib/amd64/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 rewind usr/lib/libc.so.1 0 0 SUNW_1.18 SYSVABI_1.3 0 0 SUNW_1.20 SYSVABI_1.3 SUNW_1.21 SYSVABI_1.3 SUNW_1.21 SYSVABI_1.3 SUNW_1.21.2 SYSVABI_1.3 0 0 1111111 1011110 0 0100001 0 0 0 0 rewind lib/libc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SYSVABI_1.3 0000001 0000001 0 0 0 0 0 0 rewind usr/lib/libc/libc_hwcap1.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SYSVABI_1.3 0000001 0000001 0 0 0 0 0 0 @@ -39950,25 +39950,25 @@ sdssc_suspend usr/lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWpriva sdssc_suspend lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 sdssc_version usr/lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 sdssc_version lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -se_alloc usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_end_of_data usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_free usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_get_next_tuple usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_print usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_alloc lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_end_of_data lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_free lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_get_next_tuple lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_print lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 se_print usr/lib/libsysevent.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0001111 0 0001110 0000001 0 0 0 0 se_print lib/amd64/libsysevent.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 se_print lib/libsysevent.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -se_tuple_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_name usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_type usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_name lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_type lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 seconvert usr/lib/libc.so.1 0 0 SUNW_1.18 SUNW_0.7 0 0 SUNW_1.20 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21.2 SUNW_0.7 0 0 1111111 1011110 0 0100001 0 0 0 0 seconvert lib/libc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 seconvert usr/lib/libc/libc_hwcap1.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 diff --git a/usr/src/tools/abi/etc/ABI_sparc.db b/usr/src/tools/abi/etc/ABI_sparc.db index 6a20a08077..2050a5a070 100644 --- a/usr/src/tools/abi/etc/ABI_sparc.db +++ b/usr/src/tools/abi/etc/ABI_sparc.db @@ -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. # # CDDL HEADER START @@ -21175,8 +21175,8 @@ creat64 lib/libthread.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.6.1 SUNW_1.1 00000 createQuery usr/lib/libnisdb.so.2 0 0 0 0 0 0 0 0 0 0 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 SUNWprivate_2.1 0000111 0 0000111 0 0 0 0 0 create_auth_reply usr/lib/sparcv9/libkrb.so.1 0 0 SUNW_1.1 SUNW_0.7 SUNW_1.1 SUNW_0.7 0 0 0 0 0 0 0 0 0 0 1111111 1100000 0 0011111 0 0 0 0 create_auth_reply usr/lib/libkrb.so.1 0 0 SUNW_1.1 SUNW_0.7 SUNW_1.1 SUNW_0.7 0 0 0 0 0 0 0 0 0 0 1111111 1100000 0 0011111 0 0 0 0 -create_event_service usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -create_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +create_event_service lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +create_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 create_history_entry usr/lib/krb5/libkadm5srv.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 create_policy_1 usr/lib/krb5/libkadm5clnt.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 create_policy_1 usr/lib/krb5/sparcv9/libkadm5clnt.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 @@ -26754,8 +26754,8 @@ get_devname usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate get_devname lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 get_either_iter usr/lib/krb5/libkadm5srv.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0000111 0 0000111 0 0 0 0 0 get_enclosure usr/lib/libssd.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 -get_event_service usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -get_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +get_event_service lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +get_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 get_hspname usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 get_hspname lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 get_install_root usr/lib/sparcv9/libadm.so.1 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0111111 0 0101110 0010001 0 0 0 0 @@ -42089,96 +42089,96 @@ raw lib/sparcv9/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 000 raw lib/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 0000001 0000001 0 0 0 0 0 0 rb_test usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 rb_test lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_alloc_handle usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_alloc_handle usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_append_info usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_append_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_dir usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_exec_cmd usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_exec_cmd usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_handle usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_handle usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_info usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_free_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_get_client_name usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_client_name usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -rcm_get_info usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_get_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_get_info_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_info_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_rsrcstate usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_rsrcstate usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_script_dir usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_get_script_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_error usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_error usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_info usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_info usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_modname usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_modname usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_next usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_next usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_pid usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_pid usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_properties usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_properties usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_info_rsrc usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_rsrc usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_seqnum usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_seqnum usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_state usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_info_state usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_is_script usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_is_script usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_log_message usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_log_message usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_close usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_close usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_dir usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_dir usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_open usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_module_open usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_capacity_change usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_capacity_change usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_event usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_online usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_online usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_online_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_online_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_remove usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_remove usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_remove_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_remove_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_resume usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_resume usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_notify_resume_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_notify_resume_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_capacity usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_capacity usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_event usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_register_interest usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_register_interest usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_capacity_change usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_capacity_change usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_offline usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_offline usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_offline_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_offline_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_suspend usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_suspend usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_request_suspend_list usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_request_suspend_list usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_script_dir usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_script_dir usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_capacity usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_capacity usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_event usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_event usr/lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 -rcm_unregister_interest usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -rcm_unregister_interest usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_alloc_handle lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_alloc_handle lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_append_info lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_append_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_dir lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_exec_cmd lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_exec_cmd lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_handle lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_handle lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_info lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_free_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_get_client_name lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_client_name lib/librcm.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 +rcm_get_info lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_get_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_get_info_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_info_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_rsrcstate lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_rsrcstate lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_script_dir lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_get_script_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_error lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_error lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_info lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_info lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_modname lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_modname lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_next lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_next lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_pid lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_pid lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_properties lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_properties lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_info_rsrc lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_rsrc lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_seqnum lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_seqnum lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_state lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_info_state lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_is_script lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_is_script lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_log_message lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_log_message lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_close lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_close lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_dir lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_dir lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_open lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_module_open lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_capacity_change lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_capacity_change lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_event lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_online lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_online lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_online_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_online_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_remove lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_remove lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_remove_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_remove_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_resume lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_resume lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_notify_resume_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_notify_resume_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_capacity lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_capacity lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_event lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_register_interest lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_register_interest lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_capacity_change lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_capacity_change lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_offline lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_offline lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_offline_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_offline_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_suspend lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_suspend lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_request_suspend_list lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_request_suspend_list lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_script_dir lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_script_dir lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_capacity lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_capacity lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_event lib/sparcv9/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_event lib/librcm.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0001111 0 0001111 0 0 0 0 0 +rcm_unregister_interest lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +rcm_unregister_interest lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 rcmd usr/lib/sparcv9/libsocket.so.1 0 0 SUNW_1.3 SUNW_0.7 SUNW_1.3 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 0 0 1111111 1111110 0 0000001 0 0 0 0 rcmd usr/lib/libsocket.so.1 0 0 SUNW_1.3 SUNW_0.7 SUNW_1.3 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 SUNW_1.4 SUNW_0.7 0 0 1111111 1111110 0 0000001 0 0 0 0 rcmd lib/sparcv9/libsocket.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.5 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 @@ -42887,8 +42887,8 @@ restartterm lib/libcurses.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.1 SUNW_1.1 000 resync_genid usr/lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 resync_genid lib/libmeta.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 retrieve_inetd_hash usr/lib/libinetsvc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -revoke_event_service usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 -revoke_event_service usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +revoke_event_service lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 +revoke_event_service lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0011111 0 0011111 0 0 0 0 0 rewind usr/lib/sparcv9/libc.so.1 0 0 SUNW_1.18 SUNW_0.7 SUNW_1.18 SUNW_0.7 SUNW_1.20 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21.2 SUNW_0.7 0 0 1111111 1111110 0 0000001 0 0 0 0 rewind usr/lib/libc.so.1 0 0 SUNW_1.18 SYSVABI_1.3 SUNW_1.18 SYSVABI_1.3 SUNW_1.20 SYSVABI_1.3 SUNW_1.21 SYSVABI_1.3 SUNW_1.21 SYSVABI_1.3 SUNW_1.21.2 SYSVABI_1.3 0 0 1111111 1111110 0 0000001 0 0 0 0 rewind lib/sparcv9/libc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 @@ -44119,42 +44119,42 @@ sdssc_suspend usr/lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWpriva sdssc_suspend lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 sdssc_version usr/lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0000111 0 0000110 0000001 0 0 0 0 sdssc_version lib/libmeta.so.1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -se_alloc usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_alloc usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_bytes usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_ints usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_strings usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_append_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_end_of_data usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_end_of_data usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_free usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_free usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_get_next_tuple usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_get_next_tuple usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_bytes usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_ints usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_strings usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_lookup_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_print usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_print usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_alloc lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_alloc lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_bytes lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_ints lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_strings lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_append_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_end_of_data lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_end_of_data lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_free lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_free lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_get_next_tuple lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_get_next_tuple lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_bytes lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_ints lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_strings lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_lookup_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_print lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_print lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 se_print usr/lib/sparcv9/libsysevent.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0001111 0 0001110 0000001 0 0 0 0 se_print usr/lib/libsysevent.so.1 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0001111 0 0001110 0000001 0 0 0 0 se_print lib/sparcv9/libsysevent.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 se_print lib/libsysevent.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0000001 0 0000001 0 0 0 0 0 -se_tuple_bytes usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_bytes usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_ints usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_ints usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_name usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_name usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_strings usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_strings usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_type usr/lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 -se_tuple_type usr/lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_bytes lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_bytes lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_ints lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_ints lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_name lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_name lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_strings lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_strings lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_type lib/sparcv9/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 +se_tuple_type lib/librcm.so.1 0 0 0 0 0 0 SUNWprivate_1.1 SUNWprivate_1.1 0 0 0 0 0 0 0 0 0011111 0 0010000 0001111 0 0 0 0 seconvert usr/lib/sparcv9/libc.so.1 0 0 SUNW_1.18 SUNW_0.7 SUNW_1.18 SUNW_0.7 SUNW_1.20 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21.2 SUNW_0.7 0 0 1111111 1111110 0 0000001 0 0 0 0 seconvert usr/lib/libc.so.1 0 0 SUNW_1.18 SUNW_0.7 SUNW_1.18 SUNW_0.7 SUNW_1.20 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21 SUNW_0.7 SUNW_1.21.2 SUNW_0.7 0 0 1111111 1111110 0 0000001 0 0 0 0 seconvert lib/sparcv9/libc.so.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SUNW_1.22 SUNW_0.7 0000001 0000001 0 0 0 0 0 0 diff --git a/usr/src/tools/abi/etc/exceptions b/usr/src/tools/abi/etc/exceptions index e43fe02e11..8d9f937d27 100644 --- a/usr/src/tools/abi/etc/exceptions +++ b/usr/src/tools/abi/etc/exceptions @@ -280,7 +280,7 @@ PSARC 2006/715: RULE W2: usr/lib/smbsrv/libsqlite.so.1 4480868: RULE W3: usr/lib/libpool.so.1 PSARC 2006/744: RULE W3: usr/lib/libpri.so.1 4480868: RULE W3: usr/lib/libprint.so.2 -4480868: RULE W3: usr/lib/librcm.so.1 +4480868: RULE W3: lib/librcm.so.1 4480868: RULE W3: usr/lib/librsm.so.2 4480868: RULE W3: usr/lib/libsched.so.1 4480868: RULE W3: usr/lib/libsldap.so.1 @@ -332,8 +332,8 @@ PSARC 2004/619: RULE W3: usr/lib/amd64/liblm.so.1 4480868: RULE W3: usr/lib/sparcv9/libpool.so.1 PSARC 2004/619: RULE W3: usr/lib/amd64/libpool.so.1 PSARC 2006/744: RULE W3: usr/lib/sparcv9/libpri.so.1 -4480868: RULE W3: usr/lib/sparcv9/librcm.so.1 -PSARC 2004/619: RULE W3: usr/lib/amd64/librcm.so.1 +4480868: RULE W3: lib/sparcv9/librcm.so.1 +PSARC 2004/619: RULE W3: lib/amd64/librcm.so.1 4480868: RULE W3: usr/lib/sparcv9/librsm.so.2 PSARC 2004/619: RULE W3: usr/lib/amd64/librsm.so.2 4480868: RULE W3: usr/lib/sparcv9/libsched.so.1 diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index 8a70cece12..e913bef178 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -186,7 +186,6 @@ global_zone_only_files=" etc/dladm/* etc/bootrc etc/crypto/kcf.conf - etc/datalink.conf etc/devlink.tab etc/driver_aliases etc/driver_classes @@ -494,6 +493,41 @@ enable_next_boot () { fi } +# +# If we're in the global zone, import the manifest for the specified service. +# Note that we will need to see whether we are in an smf root if we are using +# an alternate root. If so, import the service directly; otherwise, print the +# warning messages. +# +# $1: the path of the xml file (the related path to /var/svc/manifest) +# $2: the service name - specified only if the service is enabled after reboot. +# +smf_import_service() { + if [[ $zone = global && -f $rootprefix/var/svc/manifest/$1 ]]; then + if [[ -n $rootprefix && -x /usr/sbin/svccfg ]]; then + SVCCFG_REPOSITORY=$rootprefix/etc/svc/repository.db \ + /usr/sbin/svccfg import $rootprefix/var/svc/manifest/$1 + elif [[ -n $rootprefix ]]; then + echo "Warning: This system does not have SMF, so I" + echo "cannot ensure the pre-import of $1. If it does" + echo "not work, reboot your alternate root to fix it." + elif [[ -x /tmp/bfubin/svccfg ]]; then + if [[ "${2}a" == a ]]; then + /tmp/bfubin/svccfg import /var/svc/manifest/$1 + else + tmpfile=/tmp/`echo "$1" | tr / :`.$$ + sed -e "s/enabled='true'/enabled='false'/" \ + /var/svc/manifest/$1 > "$tmpfile" + /tmp/bfubin/svccfg import "$tmpfile" + # + # Make sure the service is enabled after reboot. + # + enable_next_boot $2 + fi + fi + fi +} + smf_inetd_disable() { inetconf=$rootprefix/etc/inet/inetd.conf inettmp=/tmp/inetd.tmp.$$ @@ -613,6 +647,97 @@ inetd_conf_svm_hack() { fi } +upgrade_aggr_and_linkprop () { + # Since aggregation.conf and linkprop.conf are upgraded by + # SUNWcnetr's postinstall script, put the relevant portions of the + # postinstall script here, modified to rename the old files instead + # of removing them. + + # + # Convert datalink configuration into a series of dladm(1M) commands + # and keep them in an upgrade script. This script will then be run + # in the network-physical service. + # + # Note that we cannot use the /var/svc/profile/upgrade script because + # that script is run in the manifest-import service which is too late + # for the datalink configuration. + # + UPGRADE_SCRIPT=/var/svc/profile/upgrade_datalink + + AGGR_CONF=/etc/aggregation.conf + ORIG=$rootprefix$AGGR_CONF + if [[ ! -f $ORIG ]]; then + # Try the alternate location. + AGGR_CONF=/etc/dladm/aggregation.conf + ORIG=$rootprefix$AGGR_CONF + fi + + if [[ -f $ORIG ]]; then + # Strip off comments, then each remaining line defines + # an aggregation the administrator configured on the old + # system. Each line corresponds to one dladm command + # that is appended to the upgrade script. + cat $ORIG | grep '^[^#]' | while read line; do + echo $line | while read aggr_index rest + do + policy=`echo $rest | /usr/bin/awk '{print $1}'` + nports=`echo $rest | /usr/bin/awk '{print $2}'` + ports=`echo $rest | /usr/bin/awk '{print $3}'` + mac=`echo $rest | /usr/bin/awk '{print $4}'` + lacp_mode=`echo $rest | /usr/bin/awk \ + '{print $5}'` + lacp_timer=`echo $rest | /usr/bin/awk \ + '{print $6}'` + dladm_string="dladm create-aggr -P $policy -l \ + $lacp_mode -T $lacp_timer" + # A fixed MAC address + if [[ $mac != "auto" ]]; then + dladm_string="$dladm_string -u $mac" + fi + i=1 + while [ $i -le $nports ]; do + device=`echo $ports | cut -d, -f$i` + # Older aggregation.conf files have the + # format of device_name/port_number. + # We don't need the port number, so get + # rid of it if it is there. + device=`echo $device | cut -d/ -f1` + ((i = i + 1)) + dladm_string="$dladm_string -d \ + $device" + done + dladm_string="$dladm_string $aggr_index" + echo $dladm_string >> \ + $rootprefix$UPGRADE_SCRIPT + done + done + mv $ORIG $ORIG.bak + fi + + # Upgrade linkprop.conf + ORIG=$rootprefix/etc/dladm/linkprop.conf + + if [[ -f $ORIG ]]; then + # Strip off comments, then each remaining line lists + # properties the administrator configured for a + # particular interface. Each line includes several + # properties, but we can only set one property per + # dladm invocation. + cat $ORIG | grep '^[^#]' | while read line; do + echo $line | while read link rest + do + while [ -n "$rest" ]; do + linkprop=`echo $rest | cut -d";" -f1` + rest=`echo $rest | cut -d";" -f2-` + echo dladm set-linkprop -p $linkprop \ + $link >> $rootprefix$UPGRADE_SCRIPT + done + done + done + mv $ORIG $ORIG.bak + fi +} + # update x86 version mpt.conf for property tape mpttapeprop='[ ]*tape[ ]*=[ ]*"sctp"[ ]*;' update_mptconf_i386() @@ -1124,6 +1249,9 @@ smf_obsolete_manifests=" var/svc/manifest/network/pfil.xml var/svc/manifest/platform/sun4u/mpxio-upgrade.xml var/svc/manifest/network/tname.xml + var/svc/manifest/network/aggregation.xml + var/svc/manifest/network/datalink.xml + var/svc/manifest/network/datalink-init.xml " # smf services whose manifests have been renamed @@ -1138,6 +1266,9 @@ smf_obsolete_methods=" lib/svc/method/print-server lib/svc/method/svc-volfs lib/svc/method/pfil + lib/svc/method/aggregation + lib/svc/method/datalink + lib/svc/method/datalink-init " smf_cleanup () { @@ -1244,52 +1375,61 @@ smf_cleanup_initd() { } smf_delete_manifest() { - ( - mfst=$1 - cd $root - [ -f $mfst ] || return; - if [ -r /etc/svc/volatile/repository_door ]; then - ENTITIES=`/tmp/bfubin/svccfg inventory $mfst` - for fmri in $ENTITIES; do - /tmp/bfubin/svccfg delete -f $fmri - done - fi - rm $mfst - ) +( + mfst=$1 + cd $root + [[ -f $mfst ]] || return; + if [ -r /etc/svc/volatile/repository_door ]; then + ENTITIES=`/tmp/bfubin/svccfg inventory $mfst` + for fmri in $ENTITIES; do + if [[ -n $root && $root != "/" ]]; then + SVCCFG_REPOSITORY=$root/etc/svc/repository.db + export SVCCFG_REPOSITORY + fi + /tmp/bfubin/svccfg delete -f $fmri >/dev/null 2>&1 + if [[ -n $root && $root != "/" ]]; then + unset SVCCFG_REPOSITORY + fi + done + fi + rm $mfst +) } smf_delete_methods() { - ( - cd $root; - rm -f $smf_obsolete_methods - ) +( + cd $root; + rm -f $smf_obsolete_methods +) } smf_delete_renamed_manifests() { - ( - cd $root; - rm -f $smf_renamed_manifests - ) +( + cd $root; + rm -f $smf_renamed_manifests +) } -smf_gldv3_manifests=" - var/svc/manifest/network/aggregation.xml - var/svc/manifest/network/datalink.xml - var/svc/manifest/network/datalink-init.xml -" -smf_gldv3_methods=" - lib/svc/method/aggregation - lib/svc/method/datalink - lib/svc/method/datalink-init -" -smf_cleanup_gldv3() { - ( - for f in $smf_gldv3_manifests; do - smf_delete_manifest $f - done - cd $root; - rm -f $smf_gldv3_methods - ) +smf_cleanup_dlmgmtd() { +( + # + # Delete the service instance, then refresh all its dependents in the + # cases of alternative root and zones. + # + smf_delete_manifest "var/svc/manifest/network/dlmgmt.xml" + + if [[ -n $root && $root != "/" ]]; then + export SVCCFG_REPOSITORY=$root/etc/svc/repository.db + /tmp/bfubin/svccfg -s svc:/network/physical:nwam refresh + /tmp/bfubin/svccfg -s svc:/network/physical:default refresh + /tmp/bfubin/svccfg -s svc:/system/device/local:default refresh + unset SVCCFG_REPOSITORY + fi + cd $root + rm -f lib/svc/method/svc-dlmgmtd + rm -f etc/.dlmgmt_door + rm -f sbin/dlmgmtd +) } old_mfst_dir="var/svc/manifest.orig" @@ -1574,8 +1714,9 @@ smf_apply_conf () { done smf_delete_methods smf_delete_renamed_manifests - if [ $need_datalink = no ]; then - smf_cleanup_gldv3 + + if [[ $dlmgmtd_status = cleanup ]]; then + smf_cleanup_dlmgmtd fi print "Disabling unneeded inetd.conf entries ..." @@ -1830,78 +1971,17 @@ EOFA fi fi - # If we're in the global zone, and using an alternate root, see if - # we are in an smf root. If so, import name-service-cache. If we're - # not bfu'ing an alternate root, and we're post-smf, import - # name-service-cache. This is to get name-service-cache(with correct - # dependencies) in the repository before reboot. If we're bfu'ing - # from pre-smf, this isn't an issue, as name-service-cache will be - # installed with correct dependencies. - if [[ $zone = global && - -f $rootprefix/var/svc/manifest/system/name-service-cache.xml ]]; - then - if [[ -n $rootprefix ]]; then - if [ -x /usr/sbin/svccfg ]; then - SVCCFG_REPOSITORY=$rootprefix/etc/svc/repository.db - /usr/sbin/svccfg import \ - $rootprefix/var/svc/manifest/system/name-service-cache.xml - else - echo "Warning: This system does not have SMF, so I " - echo "cannot ensure the pre-import of " - echo "name-service-cache. If name-service-cache does " - echo "not work, reboot your alternate root to fix it." - fi - elif [ -x /tmp/bfubin/svccfg ]; then - /tmp/bfubin/svccfg import \ - /var/svc/manifest/system/name-service-cache.xml - fi - fi - - # If we're in the global zone, and using an alternate root, see if - # we are in an smf root. If so, import datalink and aggregation svcs. - # If we're not bfu'ing an alternate root, and we're post-smf, - # import datalink and aggregation. This is to get them - # in the repository before reboot. If we're bfu'ing from pre-smf, - # this isn't an issue, as they are in the seed repository. - if [[ $zone = global && - -f $rootprefix/var/svc/manifest/network/datalink.xml ]]; then - if [[ -n $rootprefix ]]; then - if [ -x /usr/sbin/svccfg ]; then - SVCCFG_REPOSITORY=$rootprefix/etc/svc/repository.db - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/aggregation.xml \ - | svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/datalink.xml \ - | svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - $rootprefix/var/svc/manifest/network/datalink-init.xml \ - | svccfg import - - else - echo "Warning: This system does not have SMF, so I" - echo "cannot ensure the pre-import of datalink and" - echo "network aggregation. If they do not work" - echo "reboot your alternate root to fix it." - fi - elif [ -x /tmp/bfubin/svccfg ]; then - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/aggregation.xml | \ - svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/datalink.xml | \ - svccfg import - - sed -e "s/enabled='true'/enabled='false'/" \ - /var/svc/manifest/network/datalink-init.xml | \ - svccfg import - - fi + # + # Import the name-service-cache service. This is to get the service + # (with correct dependencies) in the repository before reboot. + # + smf_import_service system/name-service-cache.xml - # - # Make sure the services are enabled after reboot. - # - enable_next_boot svc:/network/aggregation:default - enable_next_boot svc:/network/datalink:default - enable_next_boot svc:/network/datalink-init:default - fi + # + # Import the datalink-management service. + # + smf_import_service network/dlmgmt.xml \ + svc:/network/datalink-management:default # Enable new NFS status and nlockmgr services if client is enabled cat >> $rootprefix/var/svc/profile/upgrade <<-EOF @@ -2050,7 +2130,6 @@ done boot_is_pcfs=no have_realmode=no is_pcfs_boot=no -need_datalink=no new_dladm=no # Set when moving to either directboot or multiboot @@ -2348,9 +2427,25 @@ if [ $target_isa = i386 ] && [ $multi_or_direct = yes ] && \ fi fi -if $ZCAT $cpiodir/generic.root$ZFIX | cpio -it 2>/dev/null | \ - grep datalink.conf > /dev/null 2>&1 ; then - need_datalink=yes +# +# Check whether the archives have a datalink-management services; this is +# later used to determine whether we need to upgrade the existing datalink +# configuration and if the datalink-management service needs to be removed. +# +if archive_file_exists generic.sbin "sbin/dlmgmtd"; then + dlmgmtd_exists=true +else + dlmgmtd_exists=false +fi +# +# Set the value of dlmgmtd_status based on the existence of the +# /sbin/dlmgmtd file +# +dlmgmtd_status=none +if [[ -f $root/sbin/dlmgmtd ]] && ! $dlmgmtd_exists ; then + dlmgmtd_status=cleanup +elif [[ ! -f $root/sbin/dlmgmtd ]] && $dlmgmtd_exists ; then + dlmgmtd_status=new fi # @@ -2832,49 +2927,6 @@ if [ $archive_type = directboot ] && [ $diskless = no ]; then rm -f /tmp/bfubin/miniroot-unzipped fi -create_datalink_conf() -{ - # /etc/datalink.conf needs to be populated. - drivers="bge rge xge" - conf=$rootprefix/etc/datalink.conf - - if [ ! -f $conf ]; then - # nothing to do if we bfu'ed from an archive that doesn't - # provide /etc/datalink.conf - return - fi - - ls -1 $rootprefix/etc | egrep -e '^hostname.|^hostname6.|^dhcp.' | \ - cut -d . -f2 | sort -u > /tmp/ifnames.$$ - - for driver in $drivers - do - grep $driver /tmp/ifnames.$$ | \ - while read ifname - do - devnum=`echo $ifname | sed "s/$driver//g"` - if [ "$driver$devnum" != $ifname -o \ - -n "`echo $devnum | tr -d '[0-9]'`" ]; then - echo "skipping invalid interface $ifname" - continue - fi - - vid=`expr $devnum / 1000` - inst=`expr $devnum % 1000` - - awk '{ print $1 }' $conf | grep $ifname > /dev/null - if [ $? -ne 0 ]; then - # An entry for that interface does not exist - printf \ - "$ifname\t$driver$inst\t0\t$vid\n" \ - >> $conf - fi - done - done - - rm -f /tmp/ifnames.$$ -} - revert_aggregation_conf() { aggrconf=$rootprefix/etc/aggregation.conf @@ -4725,8 +4777,8 @@ get_rootdev_list() elif [[ $metadev = /dev/md/rdsk/* ]]; then metavol=`echo "$metadev" | sed -e "s#/dev/md/rdsk/##"` rootdevlist=`metastat -p $metavol |\ - grep -v "^$metavol[ ]" |\ - nawk '{print $4}' | sed -e "s#/dev/rdsk/##"` + grep -v "^$metavol[ ]" |\ + nawk '{print $4}' | sed -e "s#/dev/rdsk/##"` fi for rootdev in $rootdevlist do @@ -5114,27 +5166,27 @@ EOF install_sparc_failsafe() { # check if failsafe already installed - if [ -f $rootprefix/platform/$karch/failsafe ]; then - return - fi - if [ -z "$FAILSAFE_SERVER" ]; then - FAILSAFE_SERVER="netinstall.sfbay" - fi - if [ -z "$FAILSAFE_IMAGE" ]; then - FAILSAFE_IMAGE="export/nv/s/latest" - fi - fs_wos_image="/net/${FAILSAFE_SERVER}/${FAILSAFE_IMAGE}" - fs_archive="${fs_wos_image}/boot/sparc.miniroot" - if [ ! -d $fs_wos_image ] || [ ! -f $fs_archive ]; then + if [ -f $rootprefix/platform/$karch/failsafe ]; then + return + fi + if [ -z "$FAILSAFE_SERVER" ]; then + FAILSAFE_SERVER="netinstall.sfbay" + fi + if [ -z "$FAILSAFE_IMAGE" ]; then + FAILSAFE_IMAGE="export/nv/s/latest" + fi + fs_wos_image="/net/${FAILSAFE_SERVER}/${FAILSAFE_IMAGE}" + fs_archive="${fs_wos_image}/boot/sparc.miniroot" + if [ ! -d $fs_wos_image ] || [ ! -f $fs_archive ]; then # XXX Remove this fallback to a known good archive once real - # XXX images with boot archives become available. + # XXX images with boot archives become available. fs_wos_image="/net/netinstall.sfbay/export/setje/nbs-latest" - fs_archive="${fs_wos_image}/boot/sparc.miniroot" - fi - if [ -d $fs_wos_image ] || [ ! -f $fs_archive ]; then - echo "Installing failsafe archive from $fs_wos_image" - cp $fs_archive $rootprefix/platform/$karch/failsafe - fi + fs_archive="${fs_wos_image}/boot/sparc.miniroot" + fi + if [ -d $fs_wos_image ] || [ ! -f $fs_archive ]; then + echo "Installing failsafe archive from $fs_wos_image" + cp $fs_archive $rootprefix/platform/$karch/failsafe + fi } disable_boot_service() @@ -6415,17 +6467,17 @@ mondo_loop() { print "done."; fi; - # Remove pre dboot krtld as well as obsolete boot blocks - # - if [ $zone = global ]; then - rm -rf \ - $root/kernel/misc/sparcv9/krtld \ - $root/platform/sun4u/ufsboot \ - $root/platform/sun4v/ufsboot \ - $usr/platform/sun4c/lib/fs/ufs/bootblk \ - $usr/platform/sun4d/lib/fs/ufs/bootblk \ - $usr/platform/sun4m/lib/fs/ufs/bootblk - fi + # Remove pre dboot krtld as well as obsolete boot blocks + # + if [ $zone = global ]; then + rm -rf \ + $root/kernel/misc/sparcv9/krtld \ + $root/platform/sun4u/ufsboot \ + $root/platform/sun4v/ufsboot \ + $usr/platform/sun4c/lib/fs/ufs/bootblk \ + $usr/platform/sun4d/lib/fs/ufs/bootblk \ + $usr/platform/sun4m/lib/fs/ufs/bootblk + fi # # Remove kmdbmod from /kernel @@ -7070,6 +7122,15 @@ mondo_loop() { # rm -f $usr/platform/sun4u/include/sys/us_drv.h + # + # Remove new files in order to go backward. + # + rm -f $root/usr/lib/rcm/modules/SUNW_vlan_rcm.so + rm -f $root/usr/lib/rcm/modules/SUNW_aggr_rcm.so + rm -f $root/kernel/drv/softmac + rm -f $root/kernel/drv/sparcv9/softmac + rm -f $root/kernel/drv/amd64/softmac + # End of pre-archive extraction hacks. if [ $diskless = no -a $zone = global ]; then @@ -7084,14 +7145,14 @@ mondo_loop() { print "Installing boot block on $rootslice." cd $usr/platform/$karch/lib/fs/ufs installboot ./bootblk $rootslice - elif [[ "$rootslice" = /dev/md/rdsk/* ]]; then - print "Detected SVM root." - cd $usr/platform/$karch/lib/fs/ufs - get_rootdev_list | while read physlice - do + elif [[ "$rootslice" = /dev/md/rdsk/* ]]; then + print "Detected SVM root." + cd $usr/platform/$karch/lib/fs/ufs + get_rootdev_list | while read physlice + do print "Installing bootblk on $physlice." - installboot ./bootblk $physlice - done + installboot ./bootblk $physlice + done fi ;; i386) @@ -7119,8 +7180,8 @@ mondo_loop() { extract_archives root generic $archlist if [ $target_isa = i386 ]; then extract_boot_archives boot $archlist - elif [ $newboot_sparc = yes ]; then - extract_boot_archives boot generic + elif [ $newboot_sparc = yes ]; then + extract_boot_archives boot generic fi else export PATH=/tmp/bfubin @@ -7236,9 +7297,9 @@ mondo_loop() { # Cleanup old RBAC profiles rbac_cleanup - # Fix network datalink configuration - if [ $zone = global -a $need_datalink = yes ]; then - create_datalink_conf + # Obsolete GLDv3 /etc/datalink.conf file". + if [[ $zone = global && -f $rootprefix/etc/datalink.conf ]]; then + rm -f $rootprefix/etc/datalink.conf fi print "\nRestoring configuration files.\n" @@ -7425,12 +7486,12 @@ mondo_loop() { # # update boot archives for new boot sparc - # - if [ $newboot_sparc = yes ] && \ + # + if [ $newboot_sparc = yes ] && \ [[ $rootslice = /dev/rdsk/* || $rootslice = /dev/md/rdsk/* ]]; then build_boot_archive - install_sparc_failsafe + install_sparc_failsafe fi # Check for damage due to CR 6379341. This was actually fixed @@ -7461,20 +7522,24 @@ mondo_loop() { fi fi - # Move existing /etc/aggregation.conf entries to - # /etc/dladm/aggregation.conf; or, if bfu'ing - # backwards, move aggregation.conf back to /etc - aggr_old=$rootprefix/etc/aggregation.conf - aggr_new=$rootprefix/etc/dladm/aggregation.conf - if [ $new_dladm = yes ]; then - if [ -f $aggr_old ]; then - # use cat instead of cp/mv to keep - # owner+group of dest - cat $aggr_old > $aggr_new - rm -f $aggr_old - fi + if [[ $dlmgmtd_status = new ]]; then + # Upgrade existing /etc/aggregation.conf (or + # /etc/dladm/aggregation.conf) and linkprop.conf + upgrade_aggr_and_linkprop else - if [ -f $aggr_new ]; then + # Move existing /etc/aggregation.conf entries to + # /etc/dladm/aggregation.conf; or, if bfu'ing + # backwards, move aggregation.conf back to /etc + aggr_old=$rootprefix/etc/aggregation.conf + aggr_new=$rootprefix/etc/dladm/aggregation.conf + if [[ $new_dladm = yes ]]; then + if [[ -f $aggr_old ]]; then + # use cat instead of cp/mv to keep + # owner+group of dest + cat $aggr_old > $aggr_new + rm -f $aggr_old + fi + elif [[ -f $aggr_new ]]; then cp $aggr_new $aggr_old chgrp sys $aggr_old rm -rf $rootprefix/etc/dladm diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 5beed63ce0..6bb7e481f4 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -561,7 +561,8 @@ CN_OBJS += cons.o DLD_OBJS += dld_drv.o dld_proto.o dld_str.o -DLS_OBJS += dls.o dls_link.o dls_mod.o dls_stat.o dls_vlan.o dls_soft_ring.o +DLS_OBJS += dls.o dls_link.o dls_mod.o dls_stat.o dls_vlan.o \ + dls_soft_ring.o dls_mgmt.o GLD_OBJS += gld.o gldutil.o @@ -578,6 +579,9 @@ AGGR_OBJS += aggr_dev.o aggr_ctl.o aggr_grp.o aggr_port.o \ VNIC_OBJS += vnic_ctl.o vnic_dev.o vnic_bcast.o vnic_cl.o +SOFTMAC_OBJS += softmac_main.o softmac_ctl.o softmac_capab.o \ + softmac_dev.o softmac_stat.o softmac_pkt.o + NET80211_OBJS += net80211.o net80211_proto.o net80211_input.o \ net80211_output.o net80211_node.o net80211_crypto.o \ net80211_crypto_none.o net80211_crypto_wep.o net80211_ioctl.o \ @@ -848,7 +852,8 @@ DCFS_OBJS += dc_vnops.o DEVFS_OBJS += devfs_subr.o devfs_vfsops.o devfs_vnops.o DEV_OBJS += sdev_subr.o sdev_vfsops.o sdev_vnops.o \ - sdev_ptsops.o sdev_comm.o sdev_profile.o sdev_ncache.o + sdev_ptsops.o sdev_comm.o sdev_profile.o \ + sdev_ncache.o sdev_netops.o CTFS_OBJS += ctfs_all.o ctfs_cdir.o ctfs_ctl.o ctfs_event.o \ ctfs_latest.o ctfs_root.o ctfs_sym.o ctfs_tdir.o ctfs_tmpl.o @@ -1528,6 +1533,8 @@ CH_COM_OBJS = ch_mac.o ch_subr.o cspi.o espi.o ixf1010.o mc3.o mc4.o mc5.o \ # PCI_STRING_OBJS = pci_strings.o +NET_DACF_OBJS += net_dacf.o + # # Xframe 10G NIC driver module # diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index 4b2282b3ef..208b098b53 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -743,6 +743,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/softmac/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/scsi_vhci/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1593,6 +1597,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/scsi/impl/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/scsi/targets/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/softmac/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/sfe/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) diff --git a/usr/src/uts/common/fs/dev/sdev_netops.c b/usr/src/uts/common/fs/dev/sdev_netops.c new file mode 100644 index 0000000000..b51b155344 --- /dev/null +++ b/usr/src/uts/common/fs/dev/sdev_netops.c @@ -0,0 +1,397 @@ +/* + * 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" + +/* + * vnode ops for the /dev/net directory + * + * The lookup is based on the internal vanity naming node table. We also + * override readdir in order to delete net nodes no longer in-use. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/sunndi.h> +#include <fs/fs_subr.h> +#include <sys/fs/dv_node.h> +#include <sys/fs/sdev_impl.h> +#include <sys/policy.h> +#include <sys/zone.h> +#include <sys/dls.h> + +struct vnodeops *devnet_vnodeops; + +/* + * Called by zone_walk_datalink() to see if the given link name belongs to the + * given zone. Returns 0 to continue the walk, -1 if the link name is found. + */ +static int +devnet_validate_name(const char *link, void *arg) +{ + return ((strcmp(link, arg) == 0) ? -1 : 0); +} + +/* + * Check if a net sdev_node is still valid - i.e. it represents a current + * network link. + * This serves two purposes + * - only valid net nodes are returned during lookup() and readdir(). + * - since net sdev_nodes are not actively destroyed when a network link + * goes away, we use the validator to do deferred cleanup i.e. when such + * nodes are encountered during subsequent lookup() and readdir(). + */ +int +devnet_validate(struct sdev_node *dv) +{ + char *nm = dv->sdev_name; + datalink_id_t linkid; + + ASSERT(!(dv->sdev_flags & SDEV_STALE)); + ASSERT(dv->sdev_state == SDEV_READY); + + if (SDEV_IS_GLOBAL(dv)) { + return ((dls_mgmt_get_linkid(nm, &linkid) != 0) ? + SDEV_VTOR_INVALID : SDEV_VTOR_VALID); + } else { + return ((zone_datalink_walk(getzoneid(), devnet_validate_name, + nm) == -1) ? SDEV_VTOR_VALID : SDEV_VTOR_INVALID); + } +} + +/* + * This callback is invoked from devname_lookup_func() to create + * a net entry when the node is not found in the cache. + */ +static int +devnet_create_rvp(const char *nm, struct vattr *vap, dls_dl_handle_t *ddhp) +{ + timestruc_t now; + dev_t dev; + int error; + + if ((error = dls_devnet_open(nm, ddhp, &dev)) != 0) { + sdcmn_err12(("devnet_create_rvp: not a valid vanity name " + "network node: %s\n", nm)); + return (error); + } + + /* + * This is a valid network device (at least at this point in time). + * Create the node by setting the attribute; the rest is taken care + * of by devname_lookup_func(). + */ + *vap = sdev_vattr_chr; + vap->va_mode |= 0666; + vap->va_rdev = dev; + + gethrestime(&now); + vap->va_atime = now; + vap->va_mtime = now; + vap->va_ctime = now; + return (0); +} + +/* + * Lookup for /dev/net directory + * If the entry does not exist, the devnet_create_rvp() callback + * is invoked to create it. Nodes do not persist across reboot. + */ +/*ARGSUSED3*/ +static int +devnet_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, + struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred, + caller_context_t *ct, int *direntflags, pathname_t *realpnp) +{ + struct sdev_node *ddv = VTOSDEV(dvp); + struct sdev_node *dv = NULL; + dls_dl_handle_t ddh = NULL; + struct vattr vattr; + int nmlen; + int error = ENOENT; + + if (SDEVTOV(ddv)->v_type != VDIR) + return (ENOTDIR); + + /* + * Empty name or ., return node itself. + */ + nmlen = strlen(nm); + if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) { + *vpp = SDEVTOV(ddv); + VN_HOLD(*vpp); + return (0); + } + + /* + * .., return the parent directory + */ + if ((nmlen == 2) && (strcmp(nm, "..") == 0)) { + *vpp = SDEVTOV(ddv->sdev_dotdot); + VN_HOLD(*vpp); + return (0); + } + + rw_enter(&ddv->sdev_contents, RW_WRITER); + + /* + * directory cache lookup: + */ + if ((dv = sdev_cache_lookup(ddv, nm)) != NULL) { + if (dv->sdev_state == SDEV_READY) { + if (!(dv->sdev_flags & SDEV_ATTR_INVALID)) + goto found; + } else { + ASSERT(dv->sdev_state == SDEV_ZOMBIE); + goto failed; + } + } + + /* + * ZOMBIED parent does not allow new node creation, bail out early. + */ + if (ddv->sdev_state == SDEV_ZOMBIE) + goto failed; + + error = devnet_create_rvp(nm, &vattr, &ddh); + if (error != 0) + goto failed; + + error = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL, cred, SDEV_READY); + if (error != 0) { + ASSERT(dv == NULL); + dls_devnet_close(ddh); + goto failed; + } + + ASSERT(dv != NULL); + + rw_enter(&dv->sdev_contents, RW_WRITER); + if (dv->sdev_flags & SDEV_ATTR_INVALID) { + /* + * SDEV_ATTR_INVALID means that this device has been + * detached, and its dev_t might've been changed too. + * Therefore, sdev_node's 'vattr' needs to be updated. + */ + SDEVTOV(dv)->v_rdev = vattr.va_rdev; + ASSERT(dv->sdev_attr != NULL); + dv->sdev_attr->va_rdev = vattr.va_rdev; + dv->sdev_flags &= ~SDEV_ATTR_INVALID; + } + ASSERT(dv->sdev_private == NULL); + dv->sdev_private = ddh; + rw_exit(&dv->sdev_contents); + +found: + ASSERT(SDEV_HELD(dv)); + rw_exit(&ddv->sdev_contents); + return (sdev_to_vp(dv, vpp)); + +failed: + rw_exit(&ddv->sdev_contents); + + if (dv != NULL) + SDEV_RELE(dv); + + *vpp = NULL; + return (error); +} + +static int +devnet_filldir_datalink(const char *link, void *arg) +{ + struct sdev_node *ddv = arg; + struct vattr vattr; + struct sdev_node *dv; + dls_dl_handle_t ddh = NULL; + + ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); + if ((dv = sdev_cache_lookup(ddv, (char *)link)) != NULL) + goto found; + + if (devnet_create_rvp(link, &vattr, &ddh) != 0) + return (0); + + ASSERT(ddh != NULL); + dls_devnet_close(ddh); + + if (sdev_mknode(ddv, (char *)link, &dv, &vattr, NULL, NULL, kcred, + SDEV_READY) != 0) { + return (0); + } + + /* + * As there is no reference holding the network device, it could be + * detached. Set SDEV_ATTR_INVALID so that the 'vattr' will be updated + * later. + */ + rw_enter(&dv->sdev_contents, RW_WRITER); + dv->sdev_flags |= SDEV_ATTR_INVALID; + rw_exit(&dv->sdev_contents); + +found: + SDEV_SIMPLE_RELE(dv); + return (0); +} + +static void +devnet_filldir(struct sdev_node *ddv) +{ + sdev_node_t *dv, *next; + char link[MAXLINKNAMELEN]; + datalink_id_t linkid; + + ASSERT(RW_READ_HELD(&ddv->sdev_contents)); + if (rw_tryupgrade(&ddv->sdev_contents) == NULL) { + rw_exit(&ddv->sdev_contents); + rw_enter(&ddv->sdev_contents, RW_WRITER); + } + + for (dv = ddv->sdev_dot; dv; dv = next) { + next = dv->sdev_next; + + /* skip stale nodes */ + if (dv->sdev_flags & SDEV_STALE) + continue; + + /* validate and prune only ready nodes */ + if (dv->sdev_state != SDEV_READY) + continue; + + switch (devnet_validate(dv)) { + case SDEV_VTOR_VALID: + case SDEV_VTOR_SKIP: + continue; + case SDEV_VTOR_INVALID: + sdcmn_err12(("devnet_filldir: destroy invalid " + "node: %s(%p)\n", dv->sdev_name, (void *)dv)); + break; + } + + if (SDEVTOV(dv)->v_count > 0) + continue; + SDEV_HOLD(dv); + /* remove the cache node */ + (void) sdev_cache_update(ddv, &dv, dv->sdev_name, + SDEV_CACHE_DELETE); + } + + if (((ddv->sdev_flags & SDEV_BUILD) == 0) && !dls_devnet_rebuild()) + goto done; + + if (SDEV_IS_GLOBAL(ddv)) { + linkid = DATALINK_INVALID_LINKID; + do { + linkid = dls_mgmt_get_next(linkid, DATALINK_CLASS_ALL, + DATALINK_ANY_MEDIATYPE, DLMGMT_ACTIVE); + + if ((linkid != DATALINK_INVALID_LINKID) && + (dls_mgmt_get_linkinfo(linkid, link, + NULL, NULL, NULL) == 0)) { + (void) devnet_filldir_datalink(link, ddv); + } + } while (linkid != DATALINK_INVALID_LINKID); + } else { + (void) zone_datalink_walk(getzoneid(), + devnet_filldir_datalink, ddv); + } + + ddv->sdev_flags &= ~SDEV_BUILD; + +done: + rw_downgrade(&ddv->sdev_contents); +} + +/* + * Display all instantiated network datalink device nodes. + * A /dev/net entry will be created only after the first lookup of + * the network datalink device succeeds. + */ +/*ARGSUSED4*/ +static int +devnet_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, + int *eofp, caller_context_t *ct, int flags) +{ + struct sdev_node *sdvp = VTOSDEV(dvp); + + ASSERT(sdvp); + + if (uiop->uio_offset == 0) + devnet_filldir(sdvp); + + return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); +} + +/* + * This callback is invoked from devname_inactive_func() to release + * the net entry which was held in devnet_create_rvp(). + */ +static void +devnet_inactive_callback(struct vnode *dvp) +{ + struct sdev_node *sdvp = VTOSDEV(dvp); + dls_dl_handle_t ddh; + + if (dvp->v_type == VDIR) + return; + + ASSERT(dvp->v_type == VCHR); + rw_enter(&sdvp->sdev_contents, RW_WRITER); + ddh = sdvp->sdev_private; + sdvp->sdev_private = NULL; + sdvp->sdev_flags |= SDEV_ATTR_INVALID; + rw_exit(&sdvp->sdev_contents); + + /* + * "ddh" (sdev_private) could be NULL if devnet_lookup fails. + */ + if (ddh != NULL) + dls_devnet_close(ddh); +} + +/*ARGSUSED*/ +static void +devnet_inactive(struct vnode *dvp, struct cred *cred, caller_context_t *ct) +{ + devname_inactive_func(dvp, cred, devnet_inactive_callback); +} + +/* + * We override lookup and readdir to build entries based on the + * in kernel vanity naming node table. + */ +const fs_operation_def_t devnet_vnodeops_tbl[] = { + VOPNAME_READDIR, { .vop_readdir = devnet_readdir }, + VOPNAME_LOOKUP, { .vop_lookup = devnet_lookup }, + VOPNAME_INACTIVE, { .vop_inactive = devnet_inactive }, + VOPNAME_CREATE, { .error = fs_nosys }, + VOPNAME_REMOVE, { .error = fs_nosys }, + VOPNAME_MKDIR, { .error = fs_nosys }, + VOPNAME_RMDIR, { .error = fs_nosys }, + VOPNAME_SYMLINK, { .error = fs_nosys }, + VOPNAME_SETSECATTR, { .error = fs_nosys }, + NULL, NULL +}; diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c index 1075391d17..0159fc568e 100644 --- a/usr/src/uts/common/fs/dev/sdev_subr.c +++ b/usr/src/uts/common/fs/dev/sdev_subr.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. */ @@ -588,6 +588,9 @@ static struct sdev_vop_table vtab[] = { "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE }, + { "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate, + SDEV_DYNAMIC | SDEV_VTOR }, + { NULL, NULL, NULL, NULL, NULL, 0} }; @@ -3709,3 +3712,70 @@ devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags, rw_exit(&parent->sdev_contents); return (0); } + +/* + * a generic inactive() function + */ +void +devname_inactive_func(struct vnode *vp, struct cred *cred, + void (*callback)(struct vnode *)) +{ + int clean; + struct sdev_node *dv = VTOSDEV(vp); + struct sdev_node *ddv = dv->sdev_dotdot; + struct sdev_node *idv; + struct sdev_node *prev = NULL; + int state; + struct devname_nsmap *map = NULL; + struct devname_ops *dirops = NULL; + void (*fn)(devname_handle_t *, struct cred *) = NULL; + + rw_enter(&ddv->sdev_contents, RW_WRITER); + state = dv->sdev_state; + + mutex_enter(&vp->v_lock); + ASSERT(vp->v_count >= 1); + + if (vp->v_count == 1 && callback != NULL) + callback(vp); + + clean = (vp->v_count == 1) && (state == SDEV_ZOMBIE); + + /* + * last ref count on the ZOMBIE node is released. + * clean up the sdev_node, and + * release the hold on the backing store node so that + * the ZOMBIE backing stores also cleaned out. + */ + if (clean) { + ASSERT(ddv); + if (SDEV_IS_GLOBAL(dv)) { + map = ddv->sdev_mapinfo; + dirops = map ? map->dir_ops : NULL; + if (dirops && (fn = dirops->devnops_inactive)) + (*fn)(&(dv->sdev_handle), cred); + } + + ddv->sdev_nlink--; + if (vp->v_type == VDIR) { + dv->sdev_nlink--; + } + for (idv = ddv->sdev_dot; idv && idv != dv; + prev = idv, idv = idv->sdev_next) + ; + ASSERT(idv == dv); + if (prev == NULL) + ddv->sdev_dot = dv->sdev_next; + else + prev->sdev_next = dv->sdev_next; + dv->sdev_next = NULL; + dv->sdev_nlink--; + --vp->v_count; + mutex_exit(&vp->v_lock); + sdev_nodedestroy(dv, 0); + } else { + --vp->v_count; + mutex_exit(&vp->v_lock); + } + rw_exit(&ddv->sdev_contents); +} diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c index ff662afc82..b0b67d2a71 100644 --- a/usr/src/uts/common/fs/dev/sdev_vnops.c +++ b/usr/src/uts/common/fs/dev/sdev_vnops.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. */ @@ -1215,61 +1215,7 @@ sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp, static void sdev_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct) { - int clean; - struct sdev_node *dv = VTOSDEV(vp); - struct sdev_node *ddv = dv->sdev_dotdot; - struct sdev_node *idv; - struct sdev_node *prev = NULL; - int state; - struct devname_nsmap *map = NULL; - struct devname_ops *dirops = NULL; - void (*fn)(devname_handle_t *, struct cred *) = NULL; - - rw_enter(&ddv->sdev_contents, RW_WRITER); - state = dv->sdev_state; - - mutex_enter(&vp->v_lock); - ASSERT(vp->v_count >= 1); - - clean = (vp->v_count == 1) && (state == SDEV_ZOMBIE); - - /* - * last ref count on the ZOMBIE node is released. - * clean up the sdev_node, and - * release the hold on the backing store node so that - * the ZOMBIE backing stores also cleaned out. - */ - if (clean) { - ASSERT(ddv); - if (SDEV_IS_GLOBAL(dv)) { - map = ddv->sdev_mapinfo; - dirops = map ? map->dir_ops : NULL; - if (dirops && (fn = dirops->devnops_inactive)) - (*fn)(&(dv->sdev_handle), cred); - } - - ddv->sdev_nlink--; - if (vp->v_type == VDIR) { - dv->sdev_nlink--; - } - for (idv = ddv->sdev_dot; idv && idv != dv; - prev = idv, idv = idv->sdev_next) - ; - ASSERT(idv == dv); - if (prev == NULL) - ddv->sdev_dot = dv->sdev_next; - else - prev->sdev_next = dv->sdev_next; - dv->sdev_next = NULL; - dv->sdev_nlink--; - --vp->v_count; - mutex_exit(&vp->v_lock); - sdev_nodedestroy(dv, 0); - } else { - --vp->v_count; - mutex_exit(&vp->v_lock); - } - rw_exit(&ddv->sdev_contents); + devname_inactive_func(vp, cred, NULL); } /*ARGSUSED2*/ diff --git a/usr/src/uts/common/fs/nfs/nfs_dlinet.c b/usr/src/uts/common/fs/nfs/nfs_dlinet.c index 632a5b29a7..944df0336d 100644 --- a/usr/src/uts/common/fs/nfs/nfs_dlinet.c +++ b/usr/src/uts/common/fs/nfs/nfs_dlinet.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. */ @@ -221,11 +221,6 @@ static void revarpinput(ldi_handle_t, struct netbuf *); static void init_netbuf(struct netbuf *); static void free_netbuf(struct netbuf *); static int rtioctl(TIUSER *, int, struct rtentry *); -static int dl_info(ldi_handle_t, dl_info_ack_t *); -extern int dl_attach(ldi_handle_t, int); -extern int dl_bind(ldi_handle_t, uint32_t, uint32_t, uint32_t, - uint32_t); -extern int dl_phys_addr(ldi_handle_t, struct ether_addr *); static void init_config(void); static void cacheinit(void); @@ -1553,19 +1548,19 @@ revarp_myaddr(TIUSER *tiptr) return (rc); } - if (rc = dl_attach(lh, ifunit)) { + if (rc = dl_attach(lh, ifunit, NULL)) { nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n"); (void) ldi_close(lh, FREAD|FWRITE, CRED()); return (rc); } - if (rc = dl_bind(lh, ETHERTYPE_REVARP, 0, DL_CLDLS, 0)) { + if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) { nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n"); (void) ldi_close(lh, FREAD|FWRITE, CRED()); return (rc); } - if (rc = dl_info(lh, &info)) { + if (rc = dl_info(lh, &info, NULL, NULL, NULL)) { nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n"); (void) ldi_close(lh, FREAD|FWRITE, CRED()); return (rc); @@ -1611,8 +1606,10 @@ revarp_start(ldi_handle_t lh, struct netbuf *myaddr) mblk_t *mp; struct dladdr *dlsap; static int done = 0; + size_t addrlen = ETHERADDRL; - if (dl_phys_addr(lh, &myether) != 0) { + if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 || + addrlen != ETHERADDRL) { /* Fallback using per-node address */ (void) localetheraddr((struct ether_addr *)NULL, &myether); cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using " @@ -2092,7 +2089,6 @@ myxdr_pmap(XDR *xdrs, struct pmap *regs) return (FALSE); } - /* * From SunOS callrpc.c */ @@ -2121,64 +2117,6 @@ mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr, return (cl_stat); } -static int -dl_info(ldi_handle_t lh, dl_info_ack_t *info) -{ - dl_info_req_t *info_req; - dl_error_ack_t *error_ack; - union DL_primitives *dl_prim; - mblk_t *mp; - int error; - - if ((mp = allocb(sizeof (dl_info_req_t), BPRI_MED)) == NULL) { - cmn_err(CE_WARN, "dl_info: allocb failed"); - return (ENOSR); - } - mp->b_datap->db_type = M_PROTO; - - info_req = (dl_info_req_t *)mp->b_wptr; - mp->b_wptr += sizeof (dl_info_req_t); - info_req->dl_primitive = DL_INFO_REQ; - - (void) ldi_putmsg(lh, mp); - if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { - nfs_perror(error, "dl_info: ldi_getmsg failed: %m\n"); - return (error); - } - - dl_prim = (union DL_primitives *)mp->b_rptr; - switch (dl_prim->dl_primitive) { - case DL_INFO_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_info_ack_t)) { - printf("dl_info: DL_INFO_ACK protocol error\n"); - break; - } - *info = *(dl_info_ack_t *)mp->b_rptr; - freemsg(mp); - return (0); - - case DL_ERROR_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { - printf("dl_info: DL_ERROR_ACK protocol error\n"); - break; - } - - error_ack = (dl_error_ack_t *)dl_prim; - printf("dl_info: DLPI error %u\n", error_ack->dl_errno); - break; - - default: - printf("dl_bind: bad ACK header %u\n", dl_prim->dl_primitive); - break; - } - - /* - * Error return only. - */ - freemsg(mp); - return (-1); -} - /* * Configure the 'default' interface based on existing boot properties. */ diff --git a/usr/src/uts/common/inet/arp/arp.c b/usr/src/uts/common/inet/arp/arp.c index b96128c4c9..1fe7942f08 100644 --- a/usr/src/uts/common/inet/arp/arp.c +++ b/usr/src/uts/common/inet/arp/arp.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. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -3443,7 +3443,7 @@ ar_rput_dlpi(queue_t *q, mblk_t *mp) freemsg(mp); return; } - err_str = dlpi_prim_str(dlp->error_ack.dl_error_primitive); + err_str = dl_primstr(dlp->error_ack.dl_error_primitive); DTRACE_PROBE2(rput_dl_error, arl_t *, arl, dl_error_ack_t *, &dlp->error_ack); switch (dlp->error_ack.dl_error_primitive) { diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 29b59311ba..6ef38c8c6c 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -3069,8 +3069,6 @@ struct ipsec_out_s; struct mac_header_info_s; extern boolean_t ip_assign_ifindex(uint_t *, ip_stack_t *); -extern const char *dlpi_prim_str(int); -extern const char *dlpi_err_str(int); extern void ill_frag_timer(void *); extern ill_t *ill_first(int, int, ill_walk_context_t *, ip_stack_t *); extern ill_t *ill_next(ill_walk_context_t *, ill_t *); diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index 29d96f16ae..77beff2c4c 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -6053,76 +6053,6 @@ ip_dlpi_alloc(size_t len, t_uscalar_t prim) return (mp); } -const char * -dlpi_prim_str(int prim) -{ - switch (prim) { - case DL_INFO_REQ: return ("DL_INFO_REQ"); - case DL_INFO_ACK: return ("DL_INFO_ACK"); - case DL_ATTACH_REQ: return ("DL_ATTACH_REQ"); - case DL_DETACH_REQ: return ("DL_DETACH_REQ"); - case DL_BIND_REQ: return ("DL_BIND_REQ"); - case DL_BIND_ACK: return ("DL_BIND_ACK"); - case DL_UNBIND_REQ: return ("DL_UNBIND_REQ"); - case DL_OK_ACK: return ("DL_OK_ACK"); - case DL_ERROR_ACK: return ("DL_ERROR_ACK"); - case DL_ENABMULTI_REQ: return ("DL_ENABMULTI_REQ"); - case DL_DISABMULTI_REQ: return ("DL_DISABMULTI_REQ"); - case DL_PROMISCON_REQ: return ("DL_PROMISCON_REQ"); - case DL_PROMISCOFF_REQ: return ("DL_PROMISCOFF_REQ"); - case DL_UNITDATA_REQ: return ("DL_UNITDATA_REQ"); - case DL_UNITDATA_IND: return ("DL_UNITDATA_IND"); - case DL_UDERROR_IND: return ("DL_UDERROR_IND"); - case DL_PHYS_ADDR_REQ: return ("DL_PHYS_ADDR_REQ"); - case DL_PHYS_ADDR_ACK: return ("DL_PHYS_ADDR_ACK"); - case DL_SET_PHYS_ADDR_REQ: return ("DL_SET_PHYS_ADDR_REQ"); - case DL_NOTIFY_REQ: return ("DL_NOTIFY_REQ"); - case DL_NOTIFY_ACK: return ("DL_NOTIFY_ACK"); - case DL_NOTIFY_IND: return ("DL_NOTIFY_IND"); - case DL_CAPABILITY_REQ: return ("DL_CAPABILITY_REQ"); - case DL_CAPABILITY_ACK: return ("DL_CAPABILITY_ACK"); - case DL_CONTROL_REQ: return ("DL_CONTROL_REQ"); - case DL_CONTROL_ACK: return ("DL_CONTROL_ACK"); - default: return ("<unknown primitive>"); - } -} - -const char * -dlpi_err_str(int err) -{ - switch (err) { - case DL_ACCESS: return ("DL_ACCESS"); - case DL_BADADDR: return ("DL_BADADDR"); - case DL_BADCORR: return ("DL_BADCORR"); - case DL_BADDATA: return ("DL_BADDATA"); - case DL_BADPPA: return ("DL_BADPPA"); - case DL_BADPRIM: return ("DL_BADPRIM"); - case DL_BADQOSPARAM: return ("DL_BADQOSPARAM"); - case DL_BADQOSTYPE: return ("DL_BADQOSTYPE"); - case DL_BADSAP: return ("DL_BADSAP"); - case DL_BADTOKEN: return ("DL_BADTOKEN"); - case DL_BOUND: return ("DL_BOUND"); - case DL_INITFAILED: return ("DL_INITFAILED"); - case DL_NOADDR: return ("DL_NOADDR"); - case DL_NOTINIT: return ("DL_NOTINIT"); - case DL_OUTSTATE: return ("DL_OUTSTATE"); - case DL_SYSERR: return ("DL_SYSERR"); - case DL_UNSUPPORTED: return ("DL_UNSUPPORTED"); - case DL_UNDELIVERABLE: return ("DL_UNDELIVERABLE"); - case DL_NOTSUPPORTED : return ("DL_NOTSUPPORTED "); - case DL_TOOMANY: return ("DL_TOOMANY"); - case DL_NOTENAB: return ("DL_NOTENAB"); - case DL_BUSY: return ("DL_BUSY"); - case DL_NOAUTO: return ("DL_NOAUTO"); - case DL_NOXIDAUTO: return ("DL_NOXIDAUTO"); - case DL_NOTESTAUTO: return ("DL_NOTESTAUTO"); - case DL_XIDAUTO: return ("DL_XIDAUTO"); - case DL_TESTAUTO: return ("DL_TESTAUTO"); - case DL_PENDING: return ("DL_PENDING"); - default: return ("<unknown error>"); - } -} - /* * Debug formatting routine. Returns a character string representation of the * addr in buf, of the form xxx.xxx.xxx.xxx. This routine takes the address @@ -15443,13 +15373,13 @@ ip_dlpi_error(ill_t *ill, t_uscalar_t prim, t_uscalar_t dl_err, if (dl_err == DL_SYSERR) { (void) mi_strlog(ill->ill_rq, 1, SL_CONSOLE|SL_ERROR|SL_TRACE, "%s: %s failed: DL_SYSERR (errno %u)\n", - ill->ill_name, dlpi_prim_str(prim), err); + ill->ill_name, dl_primstr(prim), err); return; } (void) mi_strlog(ill->ill_rq, 1, SL_CONSOLE|SL_ERROR|SL_TRACE, - "%s: %s failed: %s\n", ill->ill_name, dlpi_prim_str(prim), - dlpi_err_str(dl_err)); + "%s: %s failed: %s\n", ill->ill_name, dl_primstr(prim), + dl_errstr(dl_err)); } /* @@ -15470,9 +15400,9 @@ ip_rput_dlpi(queue_t *q, mblk_t *mp) if (dloa->dl_primitive == DL_ERROR_ACK) { ip2dbg(("ip_rput_dlpi(%s): DL_ERROR_ACK %s (0x%x): " "%s (0x%x), unix %u\n", ill->ill_name, - dlpi_prim_str(dlea->dl_error_primitive), + dl_primstr(dlea->dl_error_primitive), dlea->dl_error_primitive, - dlpi_err_str(dlea->dl_errno), + dl_errstr(dlea->dl_errno), dlea->dl_errno, dlea->dl_unix_errno)); } @@ -15532,7 +15462,7 @@ ip_rput_dlpi(queue_t *q, mblk_t *mp) case DL_OK_ACK: ip1dbg(("ip_rput: DL_OK_ACK for %s\n", - dlpi_prim_str((int)dloa->dl_correct_primitive))); + dl_primstr((int)dloa->dl_correct_primitive))); switch (dloa->dl_correct_primitive) { case DL_UNBIND_REQ: mutex_enter(&ill->ill_lock); @@ -15624,7 +15554,7 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) switch (dloa->dl_primitive) { case DL_ERROR_ACK: ip1dbg(("ip_rput_dlpi_writer: got DL_ERROR_ACK for %s\n", - dlpi_prim_str(dlea->dl_error_primitive))); + dl_primstr(dlea->dl_error_primitive))); switch (dlea->dl_error_primitive) { case DL_PROMISCON_REQ: @@ -16254,7 +16184,7 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) } case DL_OK_ACK: ip2dbg(("DL_OK_ACK %s (0x%x)\n", - dlpi_prim_str((int)dloa->dl_correct_primitive), + dl_primstr((int)dloa->dl_correct_primitive), dloa->dl_correct_primitive)); switch (dloa->dl_correct_primitive) { case DL_PROMISCON_REQ: diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 4e83f1862e..fde1ec4d19 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -18147,7 +18147,7 @@ ill_dl_down(ill_t *ill) ill->ill_unbind_mp = NULL; if (mp != NULL) { ip1dbg(("ill_dl_down: %s (%u) for %s\n", - dlpi_prim_str(*(int *)mp->b_rptr), *(int *)mp->b_rptr, + dl_primstr(*(int *)mp->b_rptr), *(int *)mp->b_rptr, ill->ill_name)); mutex_enter(&ill->ill_lock); ill->ill_state_flags |= ILL_DL_UNBIND_IN_PROGRESS; @@ -18222,7 +18222,7 @@ ill_dlpi_dispatch(ill_t *ill, mblk_t *mp) prim = dlp->dl_primitive; ip1dbg(("ill_dlpi_dispatch: sending %s (%u) to %s\n", - dlpi_prim_str(prim), prim, ill->ill_name)); + dl_primstr(prim), prim, ill->ill_name)); switch (prim) { case DL_PHYS_ADDR_REQ: @@ -18360,11 +18360,11 @@ ill_dlpi_pending(ill_t *ill, t_uscalar_t prim) if (pending == DL_PRIM_INVAL) { (void) mi_strlog(ill->ill_rq, 1, SL_CONSOLE|SL_ERROR|SL_TRACE, "received unsolicited ack for %s on %s\n", - dlpi_prim_str(prim), ill->ill_name); + dl_primstr(prim), ill->ill_name); } else { (void) mi_strlog(ill->ill_rq, 1, SL_CONSOLE|SL_ERROR|SL_TRACE, "received unexpected ack for %s on %s (expecting %s)\n", - dlpi_prim_str(prim), ill->ill_name, dlpi_prim_str(pending)); + dl_primstr(prim), ill->ill_name, dl_primstr(pending)); } return (B_FALSE); } @@ -18385,7 +18385,7 @@ ill_dlpi_done(ill_t *ill, t_uscalar_t prim) ASSERT(ill->ill_dlpi_pending == prim); ip1dbg(("ill_dlpi_done: %s has completed %s (%u)\n", ill->ill_name, - dlpi_prim_str(ill->ill_dlpi_pending), ill->ill_dlpi_pending)); + dl_primstr(ill->ill_dlpi_pending), ill->ill_dlpi_pending)); if ((mp = ill->ill_dlpi_deferred) == NULL) { ill->ill_dlpi_pending = DL_PRIM_INVAL; diff --git a/usr/src/uts/common/inet/ip/ip_squeue.c b/usr/src/uts/common/inet/ip/ip_squeue.c index 8df412e468..9bfe536d61 100644 --- a/usr/src/uts/common/inet/ip/ip_squeue.c +++ b/usr/src/uts/common/inet/ip/ip_squeue.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. */ @@ -707,8 +707,6 @@ ip_soft_ring_assignment(ill_t *ill, ill_rx_ring_t *ip_ring, ip_taskq_arg_t *taskq_arg; boolean_t refheld; - ASSERT(servicing_interrupt()); - mutex_enter(&ill->ill_lock); if (!(ill->ill_state_flags & ILL_SOFT_RING_ASSIGN)) { taskq_arg = (ip_taskq_arg_t *) diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index 47ae998331..e836fcdab2 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -20878,7 +20878,12 @@ tcp_multisend_data(tcp_t *tcp, ire_t *ire, const ill_t *ill, mblk_t *md_mp_head, ire->ire_last_used_time = lbolt; /* send it down */ - putnext(ire->ire_stq, md_mp_head); + if (ILL_DLS_CAPABLE(ill)) { + ill_dls_capab_t *ill_dls = ill->ill_dls_capab; + ill_dls->ill_tx(ill_dls->ill_tx_handle, md_mp_head); + } else { + putnext(ire->ire_stq, md_mp_head); + } /* we're done for TCP/IPv4 */ if (tcp->tcp_ipversion == IPV4_VERSION) diff --git a/usr/src/uts/common/io/afe/afe.c b/usr/src/uts/common/io/afe/afe.c index 96e32b6019..e734b75333 100644 --- a/usr/src/uts/common/io/afe/afe.c +++ b/usr/src/uts/common/io/afe/afe.c @@ -52,6 +52,7 @@ #include <sys/mac_ether.h> #include <sys/ddi.h> #include <sys/sunddi.h> +#include <sys/vlan.h> #include "afe.h" #include "afeimpl.h" @@ -542,6 +543,7 @@ afe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) macp->m_callbacks = &afe_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; if (mac_register(macp, &afep->afe_mh) == DDI_SUCCESS) { mac_free(macp); diff --git a/usr/src/uts/common/io/aggr/aggr_ctl.c b/usr/src/uts/common/io/aggr/aggr_ctl.c index f0990702cf..1e0fdbc437 100644 --- a/usr/src/uts/common/io/aggr/aggr_ctl.c +++ b/usr/src/uts/common/io/aggr/aggr_ctl.c @@ -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. */ @@ -68,7 +68,8 @@ aggr_ioc_modify(mblk_t *mp, int mode) boolean_t mac_fixed; uchar_t mac_addr[ETHERADDRL]; uint8_t modify_mask_arg, modify_mask = 0; - uint32_t rc, key; + datalink_id_t linkid; + uint32_t rc; aggr_lacp_mode_t lacp_mode; aggr_lacp_timer_t lacp_timer; @@ -76,7 +77,7 @@ aggr_ioc_modify(mblk_t *mp, int mode) if (MBLKL(mp->b_cont) < STRUCT_SIZE(modify_arg)) return (EINVAL); - key = STRUCT_FGET(modify_arg, lu_key); + linkid = STRUCT_FGET(modify_arg, lu_linkid); modify_mask_arg = STRUCT_FGET(modify_arg, lu_modify_mask); if (modify_mask_arg & LAIOC_MODIFY_POLICY) { @@ -100,7 +101,7 @@ aggr_ioc_modify(mblk_t *mp, int mode) lacp_timer = STRUCT_FGET(modify_arg, lu_lacp_timer); } - rc = aggr_grp_modify(key, NULL, modify_mask, policy, mac_fixed, + rc = aggr_grp_modify(linkid, NULL, modify_mask, policy, mac_fixed, mac_addr, lacp_mode, lacp_timer); freemsg(mp->b_cont); @@ -119,6 +120,7 @@ aggr_ioc_create(mblk_t *mp, int mode) laioc_port_t *ports = NULL; uint32_t policy; boolean_t mac_fixed; + boolean_t force; uchar_t mac_addr[ETHERADDRL]; aggr_lacp_mode_t lacp_mode; aggr_lacp_timer_t lacp_timer; @@ -143,9 +145,11 @@ aggr_ioc_create(mblk_t *mp, int mode) bcopy(STRUCT_FGET(create_arg, lc_mac), mac_addr, ETHERADDRL); mac_fixed = STRUCT_FGET(create_arg, lc_mac_fixed); + force = STRUCT_FGET(create_arg, lc_force); - rc = aggr_grp_create(STRUCT_FGET(create_arg, lc_key), - nports, ports, policy, mac_fixed, mac_addr, lacp_mode, lacp_timer); + rc = aggr_grp_create(STRUCT_FGET(create_arg, lc_linkid), + STRUCT_FGET(create_arg, lc_key), nports, ports, policy, + mac_fixed, force, mac_addr, lacp_mode, lacp_timer); freemsg(mp->b_cont); mp->b_cont = NULL; @@ -162,7 +166,7 @@ aggr_ioc_delete(mblk_t *mp, int mode) if (STRUCT_SIZE(delete_arg) > MBLKL(mp)) return (EINVAL); - rc = aggr_grp_delete(STRUCT_FGET(delete_arg, ld_key)); + rc = aggr_grp_delete(STRUCT_FGET(delete_arg, ld_linkid)); freemsg(mp->b_cont); mp->b_cont = NULL; @@ -175,9 +179,9 @@ typedef struct aggr_ioc_info_state { } aggr_ioc_info_state_t; static int -aggr_ioc_info_new_grp(void *arg, uint32_t key, uchar_t *mac, - boolean_t mac_fixed, uint32_t policy, uint32_t nports, - aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) +aggr_ioc_info_new_grp(void *arg, datalink_id_t linkid, uint32_t key, + uchar_t *mac, boolean_t mac_fixed, boolean_t force, uint32_t policy, + uint32_t nports, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) { aggr_ioc_info_state_t *state = arg; laioc_info_group_t grp; @@ -185,9 +189,11 @@ aggr_ioc_info_new_grp(void *arg, uint32_t key, uchar_t *mac, if (state->bytes_left < sizeof (grp)) return (ENOSPC); + grp.lg_linkid = linkid; grp.lg_key = key; bcopy(mac, grp.lg_mac, ETHERADDRL); grp.lg_mac_fixed = mac_fixed; + grp.lg_force = force; grp.lg_policy = policy; grp.lg_nports = nports; grp.lg_lacp_mode = lacp_mode; @@ -201,7 +207,7 @@ aggr_ioc_info_new_grp(void *arg, uint32_t key, uchar_t *mac, } static int -aggr_ioc_info_new_port(void *arg, char *devname, uchar_t *mac, +aggr_ioc_info_new_port(void *arg, datalink_id_t linkid, uchar_t *mac, aggr_port_state_t portstate, aggr_lacp_state_t *lacp_state) { aggr_ioc_info_state_t *state = arg; @@ -210,7 +216,7 @@ aggr_ioc_info_new_port(void *arg, char *devname, uchar_t *mac, if (state->bytes_left < sizeof (port)) return (ENOSPC); - bcopy(devname, port.lp_devname, MAXNAMELEN + 1); + port.lp_linkid = linkid; bcopy(mac, port.lp_mac, ETHERADDRL); port.lp_state = portstate; port.lp_lacp_state = *lacp_state; @@ -227,7 +233,7 @@ static int aggr_ioc_info(mblk_t *mp, int mode) { laioc_info_t *info_argp; - uint32_t ngroups, group_key; + datalink_id_t linkid; int rc, len; aggr_ioc_info_state_t state; @@ -235,19 +241,18 @@ aggr_ioc_info(mblk_t *mp, int mode) return (EINVAL); info_argp = (laioc_info_t *)mp->b_cont->b_rptr; + /* - * Key of the group to return. If zero, the call returns information - * regarding all groups currently defined. + * linkid of the group to return. Must not be DATALINK_INVALID_LINKID. */ - group_key = info_argp->li_group_key; + if ((linkid = info_argp->li_group_linkid) == DATALINK_INVALID_LINKID) + return (EINVAL); state.bytes_left = len - sizeof (laioc_info_t); state.where = (uchar_t *)(info_argp + 1); - rc = aggr_grp_info(&ngroups, group_key, &state, aggr_ioc_info_new_grp, - aggr_ioc_info_new_port); - if (rc == 0) - info_argp->li_ngroups = ngroups; + rc = aggr_grp_info(linkid, &state, + aggr_ioc_info_new_grp, aggr_ioc_info_new_port); return (rc); } @@ -258,6 +263,7 @@ aggr_ioc_add(mblk_t *mp, int mode) STRUCT_HANDLE(laioc_add_rem, add_arg); uint32_t nports; laioc_port_t *ports = NULL; + boolean_t force; int rc, len; STRUCT_SET_HANDLE(add_arg, mode, (void *)mp->b_cont->b_rptr); @@ -272,9 +278,10 @@ aggr_ioc_add(mblk_t *mp, int mode) return (EINVAL); ports = (laioc_port_t *)(STRUCT_BUF(add_arg) + 1); + force = STRUCT_FGET(add_arg, la_force); - rc = aggr_grp_add_ports(STRUCT_FGET(add_arg, la_key), - nports, ports); + rc = aggr_grp_add_ports(STRUCT_FGET(add_arg, la_linkid), + nports, force, ports); freemsg(mp->b_cont); mp->b_cont = NULL; @@ -302,7 +309,7 @@ aggr_ioc_remove(mblk_t *mp, int mode) ports = (laioc_port_t *)(STRUCT_BUF(rem_arg) + 1); - rc = aggr_grp_rem_ports(STRUCT_FGET(rem_arg, la_key), + rc = aggr_grp_rem_ports(STRUCT_FGET(rem_arg, la_linkid), nports, ports); freemsg(mp->b_cont); diff --git a/usr/src/uts/common/io/aggr/aggr_dev.c b/usr/src/uts/common/io/aggr/aggr_dev.c index f56b8f4f2f..2bdd97fc3f 100644 --- a/usr/src/uts/common/io/aggr/aggr_dev.c +++ b/usr/src/uts/common/io/aggr/aggr_dev.c @@ -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. */ @@ -160,6 +160,12 @@ aggr_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) return (ENOSR); /* + * The ioctl handling callback to process control ioctl + * messages; see comments above dld_ioctl() for details. + */ + dsp->ds_ioctl = aggr_ioctl; + + /* * The aggr control node uses its own set of entry points. */ WR(q)->q_qinfo = &aggr_w_ctl_qinit; @@ -177,6 +183,8 @@ aggr_close(queue_t *q) if (dsp->ds_type == DLD_CONTROL) { qprocsoff(q); + dld_finish_pending_task(dsp); + dsp->ds_ioctl = NULL; dld_str_destroy(dsp); return (0); } @@ -187,7 +195,7 @@ static void aggr_wput(queue_t *q, mblk_t *mp) { if (DB_TYPE(mp) == M_IOCTL) - aggr_ioctl(q, mp); + dld_ioctl(q, mp); else freemsg(mp); } diff --git a/usr/src/uts/common/io/aggr/aggr_grp.c b/usr/src/uts/common/io/aggr/aggr_grp.c index b89e4496e4..65105e298e 100644 --- a/usr/src/uts/common/io/aggr/aggr_grp.c +++ b/usr/src/uts/common/io/aggr/aggr_grp.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. */ @@ -31,9 +31,8 @@ * An instance of the structure aggr_grp_t is allocated for each * link aggregation group. When created, aggr_grp_t objects are * entered into the aggr_grp_hash hash table maintained by the modhash - * module. The hash key is the port number associated with the link - * aggregation group. The port number associated with a group corresponds - * the key associated with the group. + * module. The hash key is the linkid associated with the link + * aggregation group. * * A set of MAC ports are associated with each association group. */ @@ -52,9 +51,11 @@ #include <sys/atomic.h> #include <sys/stat.h> #include <sys/modhash.h> +#include <sys/id_space.h> #include <sys/strsun.h> #include <sys/dlpi.h> - +#include <sys/dls.h> +#include <sys/vlan.h> #include <sys/aggr.h> #include <sys/aggr_impl.h> @@ -67,35 +68,28 @@ static int aggr_m_stat(void *, uint_t, uint64_t *); static void aggr_m_resources(void *); static void aggr_m_ioctl(void *, queue_t *, mblk_t *); static boolean_t aggr_m_capab_get(void *, mac_capab_t, void *); - -static aggr_port_t *aggr_grp_port_lookup(aggr_grp_t *, const char *); +static aggr_port_t *aggr_grp_port_lookup(aggr_grp_t *, datalink_id_t); static int aggr_grp_rem_port(aggr_grp_t *, aggr_port_t *, boolean_t *, boolean_t *); + static void aggr_grp_capab_set(aggr_grp_t *); static boolean_t aggr_grp_capab_check(aggr_grp_t *, aggr_port_t *); static uint_t aggr_grp_max_sdu(aggr_grp_t *); +static uint32_t aggr_grp_max_margin(aggr_grp_t *); static boolean_t aggr_grp_sdu_check(aggr_grp_t *, aggr_port_t *); +static boolean_t aggr_grp_margin_check(aggr_grp_t *, aggr_port_t *); static kmem_cache_t *aggr_grp_cache; static mod_hash_t *aggr_grp_hash; static krwlock_t aggr_grp_lock; static uint_t aggr_grp_cnt; +static id_space_t *key_ids; #define GRP_HASHSZ 64 -#define GRP_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)key) +#define GRP_HASH_KEY(linkid) ((mod_hash_key_t)(uintptr_t)linkid) static uchar_t aggr_zero_mac[] = {0, 0, 0, 0, 0, 0}; -/* used by grp_info_walker */ -typedef struct aggr_grp_info_state { - uint32_t ls_group_key; - boolean_t ls_group_found; - aggr_grp_info_new_grp_fn_t ls_new_grp_fn; - aggr_grp_info_new_port_fn_t ls_new_port_fn; - void *ls_fn_arg; - int ls_rc; -} aggr_grp_info_state_t; - #define AGGR_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB) static mac_callbacks_t aggr_m_callbacks = { @@ -153,11 +147,21 @@ aggr_grp_init(void) GRP_HASHSZ, mod_hash_null_valdtor); rw_init(&aggr_grp_lock, NULL, RW_DEFAULT, NULL); aggr_grp_cnt = 0; + + /* + * Allocate an id space to manage key values (when key is not + * specified). The range of the id space will be from + * (AGGR_MAX_KEY + 1) to UINT16_MAX, because the LACP protocol + * uses a 16-bit key. + */ + key_ids = id_space_create("aggr_key_ids", AGGR_MAX_KEY + 1, UINT16_MAX); + ASSERT(key_ids != NULL); } void aggr_grp_fini(void) { + id_space_destroy(key_ids); rw_destroy(&aggr_grp_lock); mod_hash_destroy_idhash(aggr_grp_hash); kmem_cache_destroy(aggr_grp_cache); @@ -409,7 +413,8 @@ aggr_grp_port_mac_changed(aggr_grp_t *grp, aggr_port_t *port, * Add a port to a link aggregation group. */ static int -aggr_grp_add_port(aggr_grp_t *grp, const char *name, aggr_port_t **pp) +aggr_grp_add_port(aggr_grp_t *grp, datalink_id_t linkid, boolean_t force, + aggr_port_t **pp) { aggr_port_t *port, **cport; int err; @@ -418,7 +423,7 @@ aggr_grp_add_port(aggr_grp_t *grp, const char *name, aggr_port_t **pp) ASSERT(RW_WRITE_HELD(&grp->lg_lock)); /* create new port */ - err = aggr_port_create(name, &port); + err = aggr_port_create(linkid, force, &port); if (err != 0) return (err); @@ -459,16 +464,17 @@ aggr_grp_add_port(aggr_grp_t *grp, const char *name, aggr_port_t **pp) * Add one or more ports to an existing link aggregation group. */ int -aggr_grp_add_ports(uint32_t key, uint_t nports, laioc_port_t *ports) +aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, + laioc_port_t *ports) { int rc, i, nadded = 0; aggr_grp_t *grp = NULL; aggr_port_t *port; boolean_t link_state_changed = B_FALSE; - /* get group corresponding to key */ + /* get group corresponding to linkid */ rw_enter(&aggr_grp_lock, RW_READER); - if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp) != 0) { rw_exit(&aggr_grp_lock); return (ENOENT); @@ -482,8 +488,8 @@ aggr_grp_add_ports(uint32_t key, uint_t nports, laioc_port_t *ports) /* add the specified ports to group */ for (i = 0; i < nports; i++) { /* add port to group */ - if ((rc = aggr_grp_add_port(grp, ports[i].lp_devname, &port)) != - 0) { + if ((rc = aggr_grp_add_port(grp, ports[i].lp_linkid, + force, &port)) != 0) { goto bail; } ASSERT(port != NULL); @@ -491,7 +497,8 @@ aggr_grp_add_ports(uint32_t key, uint_t nports, laioc_port_t *ports) /* check capabilities */ if (!aggr_grp_capab_check(grp, port) || - !aggr_grp_sdu_check(grp, port)) { + !aggr_grp_sdu_check(grp, port) || + !aggr_grp_margin_check(grp, port)) { rc = ENOTSUP; goto bail; } @@ -532,7 +539,7 @@ bail: if (rc != 0) { /* stop and remove ports that have been added */ for (i = 0; i < nadded && !grp->lg_closing; i++) { - port = aggr_grp_port_lookup(grp, ports[i].lp_devname); + port = aggr_grp_port_lookup(grp, ports[i].lp_linkid); ASSERT(port != NULL); if (grp->lg_started) { rw_enter(&port->lp_lock, RW_WRITER); @@ -555,7 +562,7 @@ bail: * Update properties of an existing link aggregation group. */ int -aggr_grp_modify(uint32_t key, aggr_grp_t *grp_arg, uint8_t update_mask, +aggr_grp_modify(datalink_id_t linkid, aggr_grp_t *grp_arg, uint8_t update_mask, uint32_t policy, boolean_t mac_fixed, const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) { @@ -565,9 +572,9 @@ aggr_grp_modify(uint32_t key, aggr_grp_t *grp_arg, uint8_t update_mask, boolean_t link_state_changed = B_FALSE; if (grp_arg == NULL) { - /* get group corresponding to key */ + /* get group corresponding to linkid */ rw_enter(&aggr_grp_lock, RW_READER); - if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp) != 0) { rc = ENOENT; goto bail; @@ -660,9 +667,9 @@ bail: * Returns 0 on success, an errno on failure. */ int -aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, - uint32_t policy, boolean_t mac_fixed, uchar_t *mac_addr, - aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) +aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, + laioc_port_t *ports, uint32_t policy, boolean_t mac_fixed, boolean_t force, + uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer) { aggr_grp_t *grp = NULL; aggr_port_t *port; @@ -677,8 +684,8 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, rw_enter(&aggr_grp_lock, RW_WRITER); - /* does a group with the same key already exist? */ - err = mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + /* does a group with the same linkid already exist? */ + err = mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp); if (err == 0) { rw_exit(&aggr_grp_lock); @@ -692,8 +699,8 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, grp->lg_refs = 1; grp->lg_closing = B_FALSE; - grp->lg_key = key; - + grp->lg_force = force; + grp->lg_linkid = linkid; grp->lg_ifspeed = 0; grp->lg_link_state = LINK_STATE_UNKNOWN; grp->lg_link_duplex = LINK_DUPLEX_UNKNOWN; @@ -707,8 +714,17 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, grp->lg_nattached_ports = 0; grp->lg_ntx_ports = 0; + /* + * If key is not specified by the user, allocate the key. + */ + if ((key == 0) && ((key = (uint32_t)id_alloc(key_ids)) == 0)) { + err = ENOMEM; + goto bail; + } + grp->lg_key = key; + for (i = 0; i < nports; i++) { - err = aggr_grp_add_port(grp, ports[i].lp_devname, NULL); + err = aggr_grp_add_port(grp, ports[i].lp_linkid, force, NULL); if (err != 0) goto bail; } @@ -744,21 +760,29 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, /* set the initial group capabilities */ aggr_grp_capab_set(grp); - if ((mac = mac_alloc(MAC_VERSION)) == NULL) + if ((mac = mac_alloc(MAC_VERSION)) == NULL) { + err = ENOMEM; goto bail; + } mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; mac->m_driver = grp; mac->m_dip = aggr_dip; - mac->m_instance = key; + mac->m_instance = grp->lg_key > AGGR_MAX_KEY ? (uint_t)-1 : grp->lg_key; mac->m_src_addr = grp->lg_addr; mac->m_callbacks = &aggr_m_callbacks; mac->m_min_sdu = 0; mac->m_max_sdu = grp->lg_max_sdu = aggr_grp_max_sdu(grp); + mac->m_margin = aggr_grp_max_margin(grp); err = mac_register(mac, &grp->lg_mh); mac_free(mac); if (err != 0) goto bail; + if ((err = dls_devnet_create(grp->lg_mh, grp->lg_linkid)) != 0) { + (void) mac_unregister(grp->lg_mh); + goto bail; + } + /* set LACP mode */ aggr_lacp_set_mode(grp, lacp_mode, lacp_timer); @@ -774,7 +798,7 @@ aggr_grp_create(uint32_t key, uint_t nports, laioc_port_t *ports, mac_link_update(grp->lg_mh, grp->lg_link_state); /* add new group to hash table */ - err = mod_hash_insert(aggr_grp_hash, GRP_HASH_KEY(key), + err = mod_hash_insert(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t)grp); ASSERT(err == 0); aggr_grp_cnt++; @@ -800,7 +824,7 @@ bail: rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - kmem_cache_free(aggr_grp_cache, grp); + AGGR_GRP_REFRELE(grp); } rw_exit(&aggr_grp_lock); @@ -808,18 +832,17 @@ bail: } /* - * Return a pointer to the member of a group with specified device name - * and port number. + * Return a pointer to the member of a group with specified linkid. */ static aggr_port_t * -aggr_grp_port_lookup(aggr_grp_t *grp, const char *devname) +aggr_grp_port_lookup(aggr_grp_t *grp, datalink_id_t linkid) { aggr_port_t *port; ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock)); for (port = grp->lg_ports; port != NULL; port = port->lp_next) { - if (strcmp(port->lp_devname, devname) == 0) + if (port->lp_linkid == linkid) break; } @@ -909,7 +932,7 @@ aggr_grp_rem_port(aggr_grp_t *grp, aggr_port_t *port, /* * If the group MAC address has changed, update the MAC address of - * the remaining consistuent ports according to the new MAC + * the remaining constituent ports according to the new MAC * address of the group. */ if (mac_addr_changed && aggr_grp_update_ports_mac(grp)) @@ -928,7 +951,7 @@ done: * Remove one or more ports from an existing link aggregation group. */ int -aggr_grp_rem_ports(uint32_t key, uint_t nports, laioc_port_t *ports) +aggr_grp_rem_ports(datalink_id_t linkid, uint_t nports, laioc_port_t *ports) { int rc = 0, i; aggr_grp_t *grp = NULL; @@ -936,9 +959,9 @@ aggr_grp_rem_ports(uint32_t key, uint_t nports, laioc_port_t *ports) boolean_t mac_addr_update = B_FALSE, mac_addr_changed; boolean_t link_state_update = B_FALSE, link_state_changed; - /* get group corresponding to key */ + /* get group corresponding to linkid */ rw_enter(&aggr_grp_lock, RW_READER); - if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp) != 0) { rw_exit(&aggr_grp_lock); return (ENOENT); @@ -957,7 +980,7 @@ aggr_grp_rem_ports(uint32_t key, uint_t nports, laioc_port_t *ports) /* first verify that all the groups are valid */ for (i = 0; i < nports; i++) { - if (aggr_grp_port_lookup(grp, ports[i].lp_devname) == NULL) { + if (aggr_grp_port_lookup(grp, ports[i].lp_linkid) == NULL) { /* port not found */ rc = ENOENT; goto bail; @@ -967,7 +990,7 @@ aggr_grp_rem_ports(uint32_t key, uint_t nports, laioc_port_t *ports) /* remove the specified ports from group */ for (i = 0; i < nports && !grp->lg_closing; i++) { /* lookup port */ - port = aggr_grp_port_lookup(grp, ports[i].lp_devname); + port = aggr_grp_port_lookup(grp, ports[i].lp_linkid); ASSERT(port != NULL); /* stop port if group has already been started */ @@ -1002,35 +1025,49 @@ bail: } int -aggr_grp_delete(uint32_t key) +aggr_grp_delete(datalink_id_t linkid) { aggr_grp_t *grp = NULL; aggr_port_t *port, *cport; + datalink_id_t tmpid; mod_hash_val_t val; int err; rw_enter(&aggr_grp_lock, RW_WRITER); - if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(key), + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp) != 0) { rw_exit(&aggr_grp_lock); return (ENOENT); } + /* + * Note that dls_devnet_destroy() must be called before lg_lock is + * held. Otherwise, it will deadlock if another thread is in + * aggr_m_stat() and thus has a kstat_hold() on the kstats that + * dls_devnet_destroy() needs to delete. + */ + if ((err = dls_devnet_destroy(grp->lg_mh, &tmpid)) != 0) { + rw_exit(&aggr_grp_lock); + return (err); + } + ASSERT(linkid == tmpid); + AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); - grp->lg_closing = B_TRUE; - /* * Unregister from the MAC service module. Since this can * fail if a client hasn't closed the MAC port, we gracefully * fail the operation. */ + grp->lg_closing = B_TRUE; if ((err = mac_disable(grp->lg_mh)) != 0) { grp->lg_closing = B_FALSE; rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); + + (void) dls_devnet_create(grp->lg_mh, linkid); rw_exit(&aggr_grp_lock); return (err); } @@ -1053,7 +1090,7 @@ aggr_grp_delete(uint32_t key) rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - (void) mod_hash_remove(aggr_grp_hash, GRP_HASH_KEY(key), &val); + (void) mod_hash_remove(aggr_grp_hash, GRP_HASH_KEY(linkid), &val); ASSERT(grp == (aggr_grp_t *)val); ASSERT(aggr_grp_cnt > 0); @@ -1069,84 +1106,52 @@ void aggr_grp_free(aggr_grp_t *grp) { ASSERT(grp->lg_refs == 0); + if (grp->lg_key > AGGR_MAX_KEY) { + id_free(key_ids, grp->lg_key); + grp->lg_key = 0; + } kmem_cache_free(aggr_grp_cache, grp); } -/* - * Walker invoked when building the list of configured groups and - * their ports that must be passed up to user-space. - */ - -/*ARGSUSED*/ -static uint_t -aggr_grp_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +int +aggr_grp_info(datalink_id_t linkid, void *fn_arg, + aggr_grp_info_new_grp_fn_t new_grp_fn, + aggr_grp_info_new_port_fn_t new_port_fn) { - aggr_grp_t *grp; - aggr_port_t *port; - aggr_grp_info_state_t *state = arg; + aggr_grp_t *grp; + aggr_port_t *port; + int rc = 0; - if (state->ls_rc != 0) - return (MH_WALK_TERMINATE); /* terminate walk */ + rw_enter(&aggr_grp_lock, RW_READER); - grp = (aggr_grp_t *)val; + if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), + (mod_hash_val_t *)&grp) != 0) { + rw_exit(&aggr_grp_lock); + return (ENOENT); + } rw_enter(&grp->lg_lock, RW_READER); - if (state->ls_group_key != 0 && grp->lg_key != state->ls_group_key) - goto bail; - - state->ls_group_found = B_TRUE; - - state->ls_rc = state->ls_new_grp_fn(state->ls_fn_arg, grp->lg_key, - grp->lg_addr, grp->lg_addr_fixed, grp->lg_tx_policy, + rc = new_grp_fn(fn_arg, grp->lg_linkid, + (grp->lg_key > AGGR_MAX_KEY) ? 0 : grp->lg_key, grp->lg_addr, + grp->lg_addr_fixed, grp->lg_force, grp->lg_tx_policy, grp->lg_nports, grp->lg_lacp_mode, grp->aggr.PeriodicTimer); - if (state->ls_rc != 0) + if (rc != 0) goto bail; for (port = grp->lg_ports; port != NULL; port = port->lp_next) { - rw_enter(&port->lp_lock, RW_READER); - - state->ls_rc = state->ls_new_port_fn(state->ls_fn_arg, - port->lp_devname, port->lp_addr, port->lp_state, - &port->lp_lacp.ActorOperPortState); - + rc = new_port_fn(fn_arg, port->lp_linkid, port->lp_addr, + port->lp_state, &port->lp_lacp.ActorOperPortState); rw_exit(&port->lp_lock); - if (state->ls_rc != 0) + if (rc != 0) goto bail; } bail: rw_exit(&grp->lg_lock); - return ((state->ls_rc == 0) ? MH_WALK_CONTINUE : MH_WALK_TERMINATE); -} - -int -aggr_grp_info(uint_t *ngroups, uint32_t group_key, void *fn_arg, - aggr_grp_info_new_grp_fn_t new_grp_fn, - aggr_grp_info_new_port_fn_t new_port_fn) -{ - aggr_grp_info_state_t state; - int rc = 0; - - rw_enter(&aggr_grp_lock, RW_READER); - - *ngroups = aggr_grp_cnt; - - bzero(&state, sizeof (state)); - state.ls_group_key = group_key; - state.ls_new_grp_fn = new_grp_fn; - state.ls_new_port_fn = new_port_fn; - state.ls_fn_arg = fn_arg; - - mod_hash_walk(aggr_grp_hash, aggr_grp_info_walker, &state); - - if ((rc = state.ls_rc) == 0 && group_key != 0 && - !state.ls_group_found) - rc = ENOENT; - rw_exit(&aggr_grp_lock); return (rc); } @@ -1193,7 +1198,7 @@ aggr_grp_stat(aggr_grp_t *grp, uint_t stat, uint64_t *val) *val += aggr_port_stat(port, stat); /* * minus the port stat when it was added, plus any residual - * ammount for the group. + * amount for the group. */ if (IS_MAC_STAT(stat)) { stat_index = stat - MAC_STAT_MIN; @@ -1366,6 +1371,10 @@ aggr_m_capab_get(void *arg, mac_capab_t cap, void *cap_data) * status for this capability. */ return (grp->lg_gldv3_polling); + case MAC_CAPAB_NO_NATIVEVLAN: + return (!grp->lg_vlan); + case MAC_CAPAB_NO_ZCOPY: + return (!grp->lg_zcopy); default: return (B_FALSE); } @@ -1442,18 +1451,25 @@ aggr_grp_capab_set(aggr_grp_t *grp) grp->lg_hcksum_txflags = (uint32_t)-1; grp->lg_gldv3_polling = B_TRUE; + grp->lg_zcopy = B_TRUE; + grp->lg_vlan = B_TRUE; for (port = grp->lg_ports; port != NULL; port = port->lp_next) { if (!mac_capab_get(port->lp_mh, MAC_CAPAB_HCKSUM, &cksum)) cksum = 0; grp->lg_hcksum_txflags &= cksum; + grp->lg_vlan &= + !mac_capab_get(port->lp_mh, MAC_CAPAB_NO_NATIVEVLAN, NULL); + + grp->lg_zcopy &= + !mac_capab_get(port->lp_mh, MAC_CAPAB_NO_ZCOPY, NULL); + grp->lg_gldv3_polling &= mac_capab_get(port->lp_mh, MAC_CAPAB_POLL, NULL); } } - /* * Checks whether the capabilities of the port being added are compatible * with the current capabilities of the aggregation. @@ -1461,10 +1477,20 @@ aggr_grp_capab_set(aggr_grp_t *grp) static boolean_t aggr_grp_capab_check(aggr_grp_t *grp, aggr_port_t *port) { - uint32_t hcksum_txflags; + uint32_t hcksum_txflags; ASSERT(grp->lg_ports != NULL); + if (((!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_NATIVEVLAN, NULL)) & + grp->lg_vlan) != grp->lg_vlan) { + return (B_FALSE); + } + + if (((!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_ZCOPY, NULL)) & + grp->lg_zcopy) != grp->lg_zcopy) { + return (B_FALSE); + } + if (!mac_capab_get(port->lp_mh, MAC_CAPAB_HCKSUM, &hcksum_txflags)) { if (grp->lg_hcksum_txflags != 0) return (B_FALSE); @@ -1514,3 +1540,46 @@ aggr_grp_sdu_check(aggr_grp_t *grp, aggr_port_t *port) return (port_mi->mi_sdu_max >= grp->lg_max_sdu); } + +/* + * Returns the maximum margin according to the margin of the constituent ports. + */ +static uint32_t +aggr_grp_max_margin(aggr_grp_t *grp) +{ + uint32_t margin = UINT32_MAX; + aggr_port_t *port; + + ASSERT(RW_WRITE_HELD(&grp->lg_lock)); + ASSERT(grp->lg_ports != NULL); + + for (port = grp->lg_ports; port != NULL; port = port->lp_next) { + if (margin > port->lp_margin) + margin = port->lp_margin; + } + + grp->lg_margin = margin; + return (margin); +} + +/* + * Checks if the maximum margin of the specified port is compatible + * with the maximum margin of the specified aggregation group, returns + * B_TRUE if it is, B_FALSE otherwise. + */ +static boolean_t +aggr_grp_margin_check(aggr_grp_t *grp, aggr_port_t *port) +{ + if (port->lp_margin >= grp->lg_margin) + return (B_TRUE); + + /* + * See whether the current margin value is allowed to be changed to + * the new value. + */ + if (!mac_margin_update(grp->lg_mh, port->lp_margin)) + return (B_FALSE); + + grp->lg_margin = port->lp_margin; + return (B_TRUE); +} diff --git a/usr/src/uts/common/io/aggr/aggr_lacp.c b/usr/src/uts/common/io/aggr/aggr_lacp.c index d881b8f1b3..8b8c296b09 100644 --- a/usr/src/uts/common/io/aggr/aggr_lacp.c +++ b/usr/src/uts/common/io/aggr/aggr_lacp.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. */ @@ -88,10 +88,10 @@ static uint16_t lacp_system_priority = 0x1000; * is used to detect misconfiguration. */ typedef struct lacp_sel_ports { - uint16_t sp_key; + datalink_id_t sp_grp_linkid; + datalink_id_t sp_linkid; /* Note: sp_partner_system must be 2-byte aligned */ struct ether_addr sp_partner_system; - char sp_devname[MAXNAMELEN + 1]; uint32_t sp_partner_key; struct lacp_sel_ports *sp_next; } lacp_sel_ports_t; @@ -188,8 +188,8 @@ aggr_lacp_init_port(aggr_port_t *portp) /* actor port # */ pl->ActorPortNumber = portp->lp_portid; - AGGR_LACP_DBG(("aggr_lacp_init_port(%s): " - "ActorPortNumber = 0x%x\n", portp->lp_devname, + AGGR_LACP_DBG(("aggr_lacp_init_port(%d): " + "ActorPortNumber = 0x%x\n", portp->lp_linkid, pl->ActorPortNumber)); pl->ActorPortPriority = (uint16_t)lacp_port_priority; @@ -198,9 +198,9 @@ aggr_lacp_init_port(aggr_port_t *portp) pl->ActorAdminPortKey = aggrp->lg_key; pl->ActorOperPortKey = pl->ActorAdminPortKey; - AGGR_LACP_DBG(("aggr_lacp_init_port(%s) " + AGGR_LACP_DBG(("aggr_lacp_init_port(%d) " "ActorAdminPortKey = 0x%x, ActorAdminPortKey = 0x%x\n", - portp->lp_devname, pl->ActorAdminPortKey, pl->ActorOperPortKey)); + portp->lp_linkid, pl->ActorAdminPortKey, pl->ActorOperPortKey)); /* Actor admin. port state */ pl->ActorAdminPortState.bit.activity = B_FALSE; @@ -427,8 +427,8 @@ lacp_periodic_sm(aggr_port_t *portp) stop_periodic_timer(portp); pl->sm.periodic_state = LACP_NO_PERIODIC; pl->NTT = B_FALSE; - AGGR_LACP_DBG(("lacp_periodic_sm(%s):NO LACP " - "%s--->%s\n", portp->lp_devname, + AGGR_LACP_DBG(("lacp_periodic_sm(%d):NO LACP " + "%s--->%s\n", portp->lp_linkid, lacp_periodic_str[oldstate], lacp_periodic_str[pl->sm.periodic_state])); return; @@ -443,8 +443,8 @@ lacp_periodic_sm(aggr_port_t *portp) stop_periodic_timer(portp); pl->sm.periodic_state = LACP_NO_PERIODIC; pl->NTT = B_FALSE; - AGGR_LACP_DBG(("lacp_periodic_sm(%s):STOP %s--->%s\n", - portp->lp_devname, lacp_periodic_str[oldstate], + AGGR_LACP_DBG(("lacp_periodic_sm(%d):STOP %s--->%s\n", + portp->lp_linkid, lacp_periodic_str[oldstate], lacp_periodic_str[pl->sm.periodic_state])); return; } @@ -644,9 +644,9 @@ lacp_mux_sm(aggr_port_t *portp) if (pl->ActorOperPortState.bit.collecting || pl->ActorOperPortState.bit.distributing) { - AGGR_LACP_DBG(("trunk link: (%s): " + AGGR_LACP_DBG(("trunk link: (%d): " "Collector_Distributor Disabled.\n", - portp->lp_devname)); + portp->lp_linkid)); } pl->ActorOperPortState.bit.collecting = @@ -708,8 +708,8 @@ again: return; } - AGGR_LACP_DBG(("lacp_mux_sm(%s):%s--->%s\n", - portp->lp_devname, lacp_mux_str[oldstate], + AGGR_LACP_DBG(("lacp_mux_sm(%d):%s--->%s\n", + portp->lp_linkid, lacp_mux_str[oldstate], lacp_mux_str[pl->sm.mux_state])); /* perform actions on entering a new state */ @@ -717,9 +717,9 @@ again: case LACP_DETACHED: if (pl->ActorOperPortState.bit.collecting || pl->ActorOperPortState.bit.distributing) { - AGGR_LACP_DBG(("trunk link: (%s): " + AGGR_LACP_DBG(("trunk link: (%d): " "Collector_Distributor Disabled.\n", - portp->lp_devname)); + portp->lp_linkid)); } pl->ActorOperPortState.bit.sync = @@ -739,9 +739,9 @@ again: case LACP_ATTACHED: if (pl->ActorOperPortState.bit.collecting || pl->ActorOperPortState.bit.distributing) { - AGGR_LACP_DBG(("trunk link: (%s): " + AGGR_LACP_DBG(("trunk link: (%d): " "Collector_Distributor Disabled.\n", - portp->lp_devname)); + portp->lp_linkid)); } pl->ActorOperPortState.bit.sync = B_TRUE; @@ -765,9 +765,9 @@ again: case LACP_COLLECTING_DISTRIBUTING: if (!pl->ActorOperPortState.bit.collecting && !pl->ActorOperPortState.bit.distributing) { - AGGR_LACP_DBG(("trunk link: (%s): " + AGGR_LACP_DBG(("trunk link: (%d): " "Collector_Distributor Enabled.\n", - portp->lp_devname)); + portp->lp_linkid)); } pl->ActorOperPortState.bit.distributing = B_TRUE; @@ -798,8 +798,8 @@ receive_marker_pdu(aggr_port_t *portp, mblk_t *mp) AGGR_LACP_LOCK(portp->lp_grp); - AGGR_LACP_DBG(("trunk link: (%s): MARKER PDU received:\n", - portp->lp_devname)); + AGGR_LACP_DBG(("trunk link: (%d): MARKER PDU received:\n", + portp->lp_linkid)); /* LACP_OFF state not in specification so check here. */ if (!portp->lp_lacp.sm.lacp_on) @@ -809,47 +809,47 @@ receive_marker_pdu(aggr_port_t *portp, mblk_t *mp) goto bail; if (markerp->version != MARKER_VERSION) { - AGGR_LACP_DBG(("trunk link (%s): Malformed MARKER PDU: " + AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: " "version = %d does not match s/w version %d\n", - portp->lp_devname, markerp->version, MARKER_VERSION)); + portp->lp_linkid, markerp->version, MARKER_VERSION)); goto bail; } if (markerp->tlv_marker == MARKER_RESPONSE_TLV) { /* We do not yet send out MARKER info PDUs */ - AGGR_LACP_DBG(("trunk link (%s): MARKER RESPONSE PDU: " + AGGR_LACP_DBG(("trunk link (%d): MARKER RESPONSE PDU: " " MARKER TLV = %d - We don't send out info type!\n", - portp->lp_devname, markerp->tlv_marker)); + portp->lp_linkid, markerp->tlv_marker)); goto bail; } if (markerp->tlv_marker != MARKER_INFO_TLV) { - AGGR_LACP_DBG(("trunk link (%s): Malformed MARKER PDU: " - " MARKER TLV = %d \n", portp->lp_devname, + AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: " + " MARKER TLV = %d \n", portp->lp_linkid, markerp->tlv_marker)); goto bail; } if (markerp->marker_len != MARKER_INFO_RESPONSE_LENGTH) { - AGGR_LACP_DBG(("trunk link (%s): Malformed MARKER PDU: " - " MARKER length = %d \n", portp->lp_devname, + AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: " + " MARKER length = %d \n", portp->lp_linkid, markerp->marker_len)); goto bail; } if (markerp->requestor_port != portp->lp_lacp.PartnerOperPortNum) { - AGGR_LACP_DBG(("trunk link (%s): MARKER PDU: " + AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: " " MARKER Port %d not equal to Partner port %d\n", - portp->lp_devname, markerp->requestor_port, + portp->lp_linkid, markerp->requestor_port, portp->lp_lacp.PartnerOperPortNum)); goto bail; } if (ether_cmp(&markerp->system_id, &portp->lp_lacp.PartnerOperSystem) != 0) { - AGGR_LACP_DBG(("trunk link (%s): MARKER PDU: " + AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: " " MARKER MAC not equal to Partner MAC\n", - portp->lp_devname)); + portp->lp_linkid)); goto bail; } @@ -1013,7 +1013,7 @@ lacp_misconfig_check(aggr_port_t *portp) for (cport = sel_ports; cport != NULL; cport = cport->sp_next) { /* skip entries of the group of the port being checked */ - if (cport->sp_key == grp->lg_key) + if (cport->sp_grp_linkid == grp->lg_linkid) continue; if ((ether_cmp(&cport->sp_partner_system, @@ -1035,12 +1035,12 @@ lacp_misconfig_check(aggr_port_t *portp) mac->ether_addr_octet[4], mac->ether_addr_octet[5]); portp->lp_lacp.sm.selected = AGGR_UNSELECTED; - cmn_err(CE_NOTE, "aggr key %d port %s: Port Partner " - "MAC %s and key %d in use on aggregation " - "key %d port %s\n", grp->lg_key, - portp->lp_devname, mac_str, - portp->lp_lacp.PartnerOperKey, cport->sp_key, - cport->sp_devname); + + cmn_err(CE_NOTE, "aggr %d port %d: Port Partner " + "MAC %s and key %d in use on aggregation %d " + "port %d\n", grp->lg_linkid, portp->lp_linkid, + mac_str, portp->lp_lacp.PartnerOperKey, + cport->sp_grp_linkid, cport->sp_linkid); break; } } @@ -1062,10 +1062,8 @@ lacp_sel_ports_del(aggr_port_t *portp) prev = &sel_ports; for (cport = sel_ports; cport != NULL; prev = &cport->sp_next, cport = cport->sp_next) { - if (bcmp(portp->lp_devname, cport->sp_devname, - MAXNAMELEN + 1) == 0) { + if (portp->lp_linkid == cport->sp_linkid) break; - } } if (cport == NULL) { @@ -1096,8 +1094,7 @@ lacp_sel_ports_add(aggr_port_t *portp) last = &sel_ports; for (cport = sel_ports; cport != NULL; last = &cport->sp_next, cport = cport->sp_next) { - if (bcmp(portp->lp_devname, cport->sp_devname, - MAXNAMELEN + 1) == 0) { + if (portp->lp_linkid == cport->sp_linkid) { ASSERT(cport->sp_partner_key == portp->lp_lacp.PartnerOperKey); ASSERT(ether_cmp(&cport->sp_partner_system, @@ -1115,11 +1112,11 @@ lacp_sel_ports_add(aggr_port_t *portp) return (B_FALSE); } - new_port->sp_key = portp->lp_grp->lg_key; + new_port->sp_grp_linkid = portp->lp_grp->lg_linkid; bcopy(&portp->lp_lacp.PartnerOperSystem, &new_port->sp_partner_system, sizeof (new_port->sp_partner_system)); new_port->sp_partner_key = portp->lp_lacp.PartnerOperKey; - bcopy(portp->lp_devname, new_port->sp_devname, MAXNAMELEN + 1); + new_port->sp_linkid = portp->lp_linkid; *last = new_port; @@ -1165,9 +1162,9 @@ lacp_selection_logic(aggr_port_t *portp) if (pl->sm.begin || !pl->sm.lacp_enabled || (portp->lp_state != AGGR_PORT_STATE_ATTACHED)) { - AGGR_LACP_DBG(("lacp_selection_logic:(%s): " + AGGR_LACP_DBG(("lacp_selection_logic:(%d): " "selected %d-->%d (begin=%d, lacp_enabled = %d, " - "lp_state=%d)\n", portp->lp_devname, pl->sm.selected, + "lp_state=%d)\n", portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED, pl->sm.begin, pl->sm.lacp_enabled, portp->lp_state)); @@ -1181,8 +1178,8 @@ lacp_selection_logic(aggr_port_t *portp) * If LACP is not enabled then selected is never set. */ if (!pl->sm.lacp_enabled) { - AGGR_LACP_DBG(("lacp_selection_logic:(%s): selected %d-->%d\n", - portp->lp_devname, pl->sm.selected, AGGR_UNSELECTED)); + AGGR_LACP_DBG(("lacp_selection_logic:(%d): selected %d-->%d\n", + portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED)); lacp_port_unselect(portp); lacp_mux_sm(portp); @@ -1250,8 +1247,8 @@ lacp_selection_logic(aggr_port_t *portp) */ if (ether_cmp(&pl->PartnerOperSystem, (struct ether_addr *)&aggrp->lg_addr) == 0) { - cmn_err(CE_NOTE, "trunk link: (%s): Loopback condition.\n", - portp->lp_devname); + cmn_err(CE_NOTE, "trunk link: (%d): Loopback condition.\n", + portp->lp_linkid); lacp_port_unselect(portp); lacp_mux_sm(portp); @@ -1306,10 +1303,9 @@ lacp_selection_logic(aggr_port_t *portp) */ lacp_port_unselect(portp); - cmn_err(CE_NOTE, "trunk link: (%s): Port Partner MAC or" - " key (%d) incompatible with Aggregation Partner " - "MAC or key (%d)\n", - portp->lp_devname, pl->PartnerOperKey, + cmn_err(CE_NOTE, "trunk link: (%d): Port Partner MAC " + "or key (%d) incompatible with Aggregation Partner " + "MAC or key (%d)\n", portp->lp_linkid, pl->PartnerOperKey, aggrp->aggr.PartnerOperAggrKey); lacp_mux_sm(portp); @@ -1318,8 +1314,8 @@ lacp_selection_logic(aggr_port_t *portp) /* If we get to here, automatically set selected */ if (pl->sm.selected != AGGR_SELECTED) { - AGGR_LACP_DBG(("lacp_selection_logic:(%s): " - "selected %d-->%d\n", portp->lp_devname, + AGGR_LACP_DBG(("lacp_selection_logic:(%d): " + "selected %d-->%d\n", portp->lp_linkid, pl->sm.selected, AGGR_SELECTED)); if (!lacp_port_select(portp)) return; @@ -1360,12 +1356,12 @@ lacp_selection_logic(aggr_port_t *portp) } if (aggrp->aggr.ready) { - AGGR_LACP_DBG(("lacp_selection_logic:(%s): " - "aggr.ready already set\n", portp->lp_devname)); + AGGR_LACP_DBG(("lacp_selection_logic:(%d): " + "aggr.ready already set\n", portp->lp_linkid)); lacp_mux_sm(portp); } else { - AGGR_LACP_DBG(("lacp_selection_logic:(%s): Ready %d-->%d\n", - portp->lp_devname, aggrp->aggr.ready, B_TRUE)); + AGGR_LACP_DBG(("lacp_selection_logic:(%d): Ready %d-->%d\n", + portp->lp_linkid, aggrp->aggr.ready, B_TRUE)); aggrp->aggr.ready = B_TRUE; for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) @@ -1388,8 +1384,8 @@ wait_while_timer_pop(void *data) AGGR_LACP_LOCK(portp->lp_grp); - AGGR_LACP_DBG(("trunk link:(%s): wait_while_timer pop \n", - portp->lp_devname)); + AGGR_LACP_DBG(("trunk link:(%d): wait_while_timer pop \n", + portp->lp_linkid)); portp->lp_lacp.wait_while_timer.id = 0; portp->lp_lacp.sm.ready_n = B_TRUE; @@ -1441,8 +1437,8 @@ aggr_lacp_port_attached(aggr_port_t *portp) ASSERT(portp->lp_state == AGGR_PORT_STATE_ATTACHED); ASSERT(RW_WRITE_HELD(&portp->lp_lock)); - AGGR_LACP_DBG(("aggr_lacp_port_attached: port %s\n", - portp->lp_devname)); + AGGR_LACP_DBG(("aggr_lacp_port_attached: port %d\n", + portp->lp_linkid)); portp->lp_lacp.sm.port_enabled = B_TRUE; /* link on */ @@ -1497,8 +1493,8 @@ aggr_lacp_port_detached(aggr_port_t *portp) ASSERT(AGGR_LACP_LOCK_HELD(grp)); ASSERT(RW_WRITE_HELD(&portp->lp_lock)); - AGGR_LACP_DBG(("aggr_lacp_port_detached: port %s\n", - portp->lp_devname)); + AGGR_LACP_DBG(("aggr_lacp_port_detached: port %d\n", + portp->lp_linkid)); portp->lp_lacp.sm.port_enabled = B_FALSE; @@ -1542,7 +1538,7 @@ lacp_on(aggr_port_t *portp) lacp_reset_port(portp); portp->lp_lacp.sm.lacp_on = B_TRUE; - AGGR_LACP_DBG(("lacp_on:(%s): \n", portp->lp_devname)); + AGGR_LACP_DBG(("lacp_on:(%d): \n", portp->lp_linkid)); lacp_receive_sm(portp, NULL); lacp_mux_sm(portp); @@ -1570,12 +1566,12 @@ lacp_off(aggr_port_t *portp) portp->lp_lacp.sm.lacp_on = B_FALSE; - AGGR_LACP_DBG(("lacp_off:(%s): \n", portp->lp_devname)); + AGGR_LACP_DBG(("lacp_off:(%d): \n", portp->lp_linkid)); /* - * Disable Slow Protocol Timers. We must temporarely release - * the group and port locks in order to avod deadlocks. Make - * sure that the port nor the group are closing after re-acquiring + * Disable Slow Protocol Timers. We must temporarily release + * the group and port locks to avoid deadlocks. Make sure that + * neither the port nor group are closing after re-acquiring * their locks. */ rw_exit(&portp->lp_lock); @@ -1619,8 +1615,8 @@ valid_lacp_pdu(aggr_port_t *portp, lacp_t *lacp) (lacp->partner_info.information_len != sizeof (link_info_t)) || (lacp->collector_len != LACP_COLLECTOR_INFO_LEN) || (lacp->terminator_len != LACP_TERMINATOR_INFO_LEN)) { - AGGR_LACP_DBG(("trunk link (%s): Malformed LACPDU: " - " Terminator Length = %d \n", portp->lp_devname, + AGGR_LACP_DBG(("trunk link (%d): Malformed LACPDU: " + " Terminator Length = %d \n", portp->lp_linkid, lacp->terminator_len)); return (B_FALSE); } @@ -1677,8 +1673,8 @@ current_while_timer_pop(void *data) AGGR_LACP_LOCK(portp->lp_grp); - AGGR_LACP_DBG(("trunk link:(%s): current_while_timer " - "pop id=%p\n", portp->lp_devname, + AGGR_LACP_DBG(("trunk link:(%d): current_while_timer " + "pop id=%p\n", portp->lp_linkid, portp->lp_lacp.current_while_timer.id)); portp->lp_lacp.current_while_timer.id = 0; @@ -1765,8 +1761,8 @@ record_PDU(aggr_port_t *portp, lacp_t *lacp) } if (save_sync != pl->PartnerOperPortState.bit.sync) { - AGGR_LACP_DBG(("record_PDU:(%s): partner sync " - "%d -->%d\n", portp->lp_devname, save_sync, + AGGR_LACP_DBG(("record_PDU:(%d): partner sync " + "%d -->%d\n", portp->lp_linkid, save_sync, pl->PartnerOperPortState.bit.sync)); return (B_TRUE); } else { @@ -1797,8 +1793,8 @@ update_selected(aggr_port_t *portp, lacp_t *lacp) (pl->PartnerOperKey != ntohs(lacp->actor_info.key)) || (pl->PartnerOperPortState.bit.aggregation != lacp->actor_info.state.bit.aggregation)) { - AGGR_LACP_DBG(("update_selected:(%s): " - "selected %d-->%d\n", portp->lp_devname, pl->sm.selected, + AGGR_LACP_DBG(("update_selected:(%d): " + "selected %d-->%d\n", portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED)); lacp_port_unselect(portp); @@ -1829,8 +1825,8 @@ update_default_selected(aggr_port_t *portp) (pl->PartnerOperPortState.bit.aggregation != pl->PartnerAdminPortState.bit.aggregation)) { - AGGR_LACP_DBG(("update_default_selected:(%s): " - "selected %d-->%d\n", portp->lp_devname, + AGGR_LACP_DBG(("update_default_selected:(%d): " + "selected %d-->%d\n", portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED)); lacp_port_unselect(portp); @@ -1868,8 +1864,8 @@ update_NTT(aggr_port_t *portp, lacp_t *lacp) (pl->ActorOperPortState.bit.aggregation != lacp->partner_info.state.bit.aggregation)) { - AGGR_LACP_DBG(("update_NTT:(%s): NTT %d-->%d\n", - portp->lp_devname, pl->NTT, B_TRUE)); + AGGR_LACP_DBG(("update_NTT:(%d): NTT %d-->%d\n", + portp->lp_linkid, pl->NTT, B_TRUE)); pl->NTT = B_TRUE; } @@ -1926,8 +1922,8 @@ lacp_receive_sm(aggr_port_t *portp, lacp_t *lacp) if (!((lacp && (oldstate == LACP_CURRENT) && (pl->sm.receive_state == LACP_CURRENT)))) { - AGGR_LACP_DBG(("lacp_receive_sm(%s):%s--->%s\n", - portp->lp_devname, lacp_receive_str[oldstate], + AGGR_LACP_DBG(("lacp_receive_sm(%d):%s--->%s\n", + portp->lp_linkid, lacp_receive_str[oldstate], lacp_receive_str[pl->sm.receive_state])); } @@ -2015,8 +2011,8 @@ lacp_receive_sm(aggr_port_t *portp, lacp_t *lacp) if (!lacp) /* no LACPDU so current_while_timer popped */ break; - AGGR_LACP_DBG(("lacp_receive_sm: (%s): LACPDU received:\n", - portp->lp_devname)); + AGGR_LACP_DBG(("lacp_receive_sm: (%d): LACPDU received:\n", + portp->lp_linkid)); /* * Validate Actor_Information_Length, @@ -2024,9 +2020,9 @@ lacp_receive_sm(aggr_port_t *portp, lacp_t *lacp) * and Terminator_Length fields. */ if (!valid_lacp_pdu(portp, lacp)) { - AGGR_LACP_DBG(("lacp_receive_sm (%s): " + AGGR_LACP_DBG(("lacp_receive_sm (%d): " "Invalid LACPDU received\n", - portp->lp_devname)); + portp->lp_linkid)); break; } @@ -2083,8 +2079,8 @@ aggr_set_coll_dist_locked(aggr_port_t *portp, boolean_t enable) { ASSERT(RW_WRITE_HELD(&portp->lp_lock)); - AGGR_LACP_DBG(("AGGR_SET_COLL_DIST_TYPE: (%s) %s\n", - portp->lp_devname, enable ? "ENABLED" : "DISABLED")); + AGGR_LACP_DBG(("AGGR_SET_COLL_DIST_TYPE: (%d) %s\n", + portp->lp_linkid, enable ? "ENABLED" : "DISABLED")); if (!enable) { /* @@ -2126,8 +2122,8 @@ aggr_lacp_rx(aggr_port_t *portp, mblk_t *dmp) switch (lacp->subtype) { case LACP_SUBTYPE: - AGGR_LACP_DBG(("aggr_lacp_rx:(%s): LACPDU received.\n", - portp->lp_devname)); + AGGR_LACP_DBG(("aggr_lacp_rx:(%d): LACPDU received.\n", + portp->lp_linkid)); AGGR_LACP_LOCK(portp->lp_grp); if (!portp->lp_lacp.sm.lacp_on) { @@ -2139,16 +2135,16 @@ aggr_lacp_rx(aggr_port_t *portp, mblk_t *dmp) break; case MARKER_SUBTYPE: - AGGR_LACP_DBG(("aggr_lacp_rx:(%s): Marker Packet received.\n", - portp->lp_devname)); + AGGR_LACP_DBG(("aggr_lacp_rx:(%d): Marker Packet received.\n", + portp->lp_linkid)); (void) receive_marker_pdu(portp, dmp); break; default: - AGGR_LACP_DBG(("aggr_lacp_rx: (%s): " + AGGR_LACP_DBG(("aggr_lacp_rx: (%d): " "Unknown Slow Protocol type %d\n", - portp->lp_devname, lacp->subtype)); + portp->lp_linkid, lacp->subtype)); break; } diff --git a/usr/src/uts/common/io/aggr/aggr_port.c b/usr/src/uts/common/io/aggr/aggr_port.c index 0beb8f364e..bc08874d25 100644 --- a/usr/src/uts/common/io/aggr/aggr_port.c +++ b/usr/src/uts/common/io/aggr/aggr_port.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. */ @@ -48,7 +48,6 @@ #include <sys/stat.h> #include <sys/sdt.h> #include <sys/dlpi.h> - #include <sys/aggr.h> #include <sys/aggr_impl.h> @@ -88,7 +87,7 @@ aggr_port_init(void) /* * Allocate a id space to manage port identification. The range of * the arena will be from 1 to UINT16_MAX, because the LACP protocol - * uses it to be a 16 bits unique identfication. + * specifies 16-bit unique identification. */ aggr_portids = id_space_create("aggr_portids", 1, UINT16_MAX); ASSERT(aggr_portids != NULL); @@ -127,35 +126,67 @@ aggr_port_init_callbacks(aggr_port_t *port) } int -aggr_port_create(const char *name, aggr_port_t **pp) +aggr_port_create(const datalink_id_t linkid, boolean_t force, aggr_port_t **pp) { int err; mac_handle_t mh; aggr_port_t *port; uint16_t portid; uint_t i; + boolean_t no_link_update = B_FALSE; const mac_info_t *mip; + uint32_t note; + uint32_t margin; *pp = NULL; - if ((err = mac_open(name, &mh)) != 0) + if ((err = mac_open_by_linkid(linkid, &mh)) != 0) return (err); mip = mac_info(mh); if (mip->mi_media != DL_ETHER || mip->mi_nativemedia != DL_ETHER) { - mac_close(mh); - return (EINVAL); + err = EINVAL; + goto fail; + } + + /* + * If the underlying MAC does not support link update notification, it + * can only be aggregated if `force' is set. This is because aggr + * depends on link notifications to attach ports whose link is up. + */ + note = mac_no_notification(mh); + if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) { + no_link_update = B_TRUE; + if (!force) { + /* + * We borrow this error code to indicate that link + * notification is not supported. + */ + err = ENETDOWN; + goto fail; + } } if ((portid = (uint16_t)id_alloc(aggr_portids)) == 0) { - mac_close(mh); - return (ENOMEM); + err = ENOMEM; + goto fail; + } + + /* + * As the underlying mac's current margin size is used to determine + * the margin size of the aggregation itself, request the underlying + * mac not to change to a smaller size. + */ + if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) { + id_free(aggr_portids, portid); + goto fail; } if (!mac_active_set(mh)) { + VERIFY(mac_margin_remove(mh, margin) == 0); id_free(aggr_portids, portid); - mac_close(mh); - return (EBUSY); + err = EBUSY; + goto fail; } port = kmem_cache_alloc(aggr_port_cache, KM_SLEEP); @@ -164,7 +195,7 @@ aggr_port_create(const char *name, aggr_port_t **pp) port->lp_next = NULL; port->lp_mh = mh; port->lp_mip = mip; - (void) strlcpy(port->lp_devname, name, sizeof (port->lp_devname)); + port->lp_linkid = linkid; port->lp_closing = 0; /* get the port's original MAC address */ @@ -181,12 +212,14 @@ aggr_port_create(const char *name, aggr_port_t **pp) port->lp_started = B_FALSE; port->lp_tx_enabled = B_FALSE; port->lp_promisc_on = B_FALSE; + port->lp_no_link_update = no_link_update; port->lp_portid = portid; + port->lp_margin = margin; /* * Save the current statistics of the port. They will be used - * later by aggr_m_stats() when aggregating the stastics of - * the consistituent ports. + * later by aggr_m_stats() when aggregating the statistics of + * the constituent ports. */ for (i = 0; i < MAC_NSTAT; i++) { port->lp_stat[i] = @@ -202,11 +235,16 @@ aggr_port_create(const char *name, aggr_port_t **pp) *pp = port; return (0); + +fail: + mac_close(mh); + return (err); } void aggr_port_delete(aggr_port_t *port) { + VERIFY(mac_margin_remove(port->lp_mh, port->lp_margin) == 0); mac_rx_remove_wait(port->lp_mh); mac_resource_set(port->lp_mh, NULL, NULL); mac_notify_remove(port->lp_mh, port->lp_mnh); @@ -237,7 +275,7 @@ aggr_port_free(aggr_port_t *port) /* * Invoked upon receiving a MAC_NOTE_LINK notification for - * one of the consistuent ports. + * one of the constituent ports. */ boolean_t aggr_port_notify_link(aggr_grp_t *grp, aggr_port_t *port, boolean_t dolock) @@ -259,8 +297,12 @@ aggr_port_notify_link(aggr_grp_t *grp, aggr_port_t *port, boolean_t dolock) rw_enter(&port->lp_lock, RW_WRITER); - /* link state change? */ - link_state = mac_link_get(port->lp_mh); + /* + * link state change? For links that do not support link state + * notification, always assume the link is up. + */ + link_state = port->lp_no_link_update ? LINK_STATE_UP : + mac_link_get(port->lp_mh); if (port->lp_link_state != link_state) { if (link_state == LINK_STATE_UP) do_attach = (port->lp_link_state != LINK_STATE_UP); @@ -303,7 +345,6 @@ aggr_port_notify_link(aggr_grp_t *grp, aggr_port_t *port, boolean_t dolock) rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); } - return (link_state_changed); } @@ -321,7 +362,6 @@ aggr_port_notify_unicst(aggr_grp_t *grp, aggr_port_t *port, ASSERT(mac_addr_changedp != NULL); ASSERT(link_state_changedp != NULL); - AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); diff --git a/usr/src/uts/common/io/aggr/aggr_recv.c b/usr/src/uts/common/io/aggr/aggr_recv.c index 6e409e4b89..bf98e65ee3 100644 --- a/usr/src/uts/common/io/aggr/aggr_recv.c +++ b/usr/src/uts/common/io/aggr/aggr_recv.c @@ -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. */ @@ -46,7 +46,7 @@ aggr_recv_lacp(aggr_port_t *port, mblk_t *mp) { aggr_grp_t *grp = port->lp_grp; - /* in promiscous mode, send copy of packet up */ + /* in promiscuous mode, send copy of packet up */ if (grp->lg_promisc) { mblk_t *nmp = copymsg(mp); @@ -67,6 +67,17 @@ aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp) aggr_port_t *port = (aggr_port_t *)arg; aggr_grp_t *grp = port->lp_grp; + /* + * If this message is looped back from the legacy devices, drop + * it as the Nemo framework will be responsible for looping it + * back by the mac_txloop() function. + */ + if (mp->b_flag & MSGNOLOOP) { + ASSERT(mp->b_next == NULL); + freemsg(mp); + return; + } + if (grp->lg_lacp_mode == AGGR_LACP_OFF) { mac_rx(grp->lg_mh, mrh, mp); } else { diff --git a/usr/src/uts/common/io/bge/bge_main2.c b/usr/src/uts/common/io/bge/bge_main2.c index 088d0a5aaf..f80a750652 100644 --- a/usr/src/uts/common/io/bge/bge_main2.c +++ b/usr/src/uts/common/io/bge/bge_main2.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. */ @@ -2860,6 +2860,7 @@ bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) macp->m_callbacks = &bge_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); + macp->m_margin = VLAN_TAGSZ; /* * Finally, we're ready to register ourselves with the MAC layer * interface; if this succeeds, we're all ready to start() diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c index ad3440e2d8..2b394c051d 100644 --- a/usr/src/uts/common/io/dld/dld_drv.c +++ b/usr/src/uts/common/io/dld/dld_drv.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,9 +34,11 @@ #include <sys/modctl.h> #include <sys/stat.h> #include <sys/strsun.h> +#include <sys/vlan.h> #include <sys/dld.h> #include <sys/dld_impl.h> #include <sys/dls_impl.h> +#include <sys/softmac.h> #include <sys/vlan.h> #include <inet/common.h> @@ -83,6 +85,10 @@ dev_info_t *dld_dip; /* dev_info_t for the driver */ uint32_t dld_opt = 0; /* Global options */ static vmem_t *dld_ctl_vmem; /* for control minor numbers */ +#define NAUTOPUSH 32 +static mod_hash_t *dld_ap_hashp; +static krwlock_t dld_ap_hash_lock; + static struct module_info drv_info = { 0, /* mi_idnum */ DLD_DRIVER_NAME, /* mi_idname */ @@ -185,18 +191,46 @@ drv_init(void) NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); drv_secobj_init(); dld_str_init(); + /* + * Create a hash table for autopush configuration. + */ + dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", + NAUTOPUSH, mod_hash_null_valdtor); + + ASSERT(dld_ap_hashp != NULL); + rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); +} + +/* ARGSUSED */ +static uint_t +drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + boolean_t *pexist = arg; + + *pexist = B_TRUE; + return (MH_WALK_TERMINATE); } static int drv_fini(void) { - int err; + int err; + boolean_t exist = B_FALSE; + + rw_enter(&dld_ap_hash_lock, RW_READER); + mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); + rw_exit(&dld_ap_hash_lock); + + if (exist) + return (EBUSY); if ((err = dld_str_fini()) != 0) return (err); drv_secobj_fini(); vmem_destroy(dld_ctl_vmem); + mod_hash_destroy_idhash(dld_ap_hashp); + rw_destroy(&dld_ap_hash_lock); return (0); } @@ -373,241 +407,472 @@ drv_close(queue_t *rq) } /* - * DLDIOCATTR + * DLDIOC_ATTR */ static void drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) { - dld_ioc_attr_t *diap; - dls_vlan_t *dvp = NULL; - dls_link_t *dlp = NULL; - int err; - queue_t *q = ctls->cs_wq; + dld_ioc_attr_t *diap; + dls_dl_handle_t dlh; + dls_vlan_t *dvp; + int err; + queue_t *q = ctls->cs_wq; if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) goto failed; diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; - diap->dia_name[IFNAMSIZ - 1] = '\0'; - if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) { - err = ENOENT; + if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) goto failed; - } - dlp = dvp->dv_dlp; - (void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev)); - diap->dia_vid = dvp->dv_id; - diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max; + if ((err = dls_vlan_hold(dls_devnet_mac(dlh), + dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { + dls_devnet_rele_tmp(dlh); + goto failed; + } + diap->dia_max_sdu = dvp->dv_dlp->dl_mip->mi_sdu_max; dls_vlan_rele(dvp); + dls_devnet_rele_tmp(dlh); + miocack(q, mp, sizeof (dld_ioc_attr_t), 0); return; failed: ASSERT(err != 0); - if (err == ENOENT) { - char devname[MAXNAMELEN]; - uint_t instance; - major_t major; + miocnak(q, mp, 0, err); +} + +/* + * DLDIOC_PHYS_ATTR + */ +static void +drv_ioc_phys_attr(dld_ctl_str_t *ctls, mblk_t *mp) +{ + dld_ioc_phys_attr_t *dipp; + int err; + dls_dl_handle_t dlh; + dls_dev_handle_t ddh; + dev_t phydev; + queue_t *q = ctls->cs_wq; + + if ((err = miocpullup(mp, sizeof (dld_ioc_phys_attr_t))) != 0) + goto failed; + + dipp = (dld_ioc_phys_attr_t *)mp->b_cont->b_rptr; + /* + * Every physical link should have its physical dev_t kept in the + * daemon. If not, it is not a valid physical link. + */ + if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) { + err = EINVAL; + goto failed; + } + + /* + * Although this is a valid physical link, it might already be removed + * by DR or during system shutdown. softmac_hold_device() would return + * ENOENT in this case. + */ + if ((err = softmac_hold_device(phydev, &ddh)) != 0) + goto failed; + + if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { /* - * Try to detect if the specified device is gldv3 - * and return ENODEV if it is not. + * Although this is an active physical link, its link type is + * not supported by GLDv3, and therefore it does not have + * vanity naming support. */ - if (ddi_parse(diap->dia_name, devname, &instance) == 0 && - (major = ddi_name_to_major(devname)) != (major_t)-1 && - !GLDV3_DRV(major)) - err = ENODEV; + dipp->dip_novanity = B_TRUE; + } else { + dipp->dip_novanity = B_FALSE; + dls_devnet_rele_tmp(dlh); } + /* + * Get the physical device name from the major number and the instance + * number derived from phydev. + */ + (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", + ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); + + softmac_rele_device(ddh); + + miocack(q, mp, sizeof (dld_ioc_phys_attr_t), 0); + return; + +failed: miocnak(q, mp, 0, err); } - /* - * DLDIOCVLAN + * DLDIOC_CREATE_VLAN */ -typedef struct dld_ioc_vlan_state { - uint_t bytes_left; - dld_ioc_vlan_t *divp; - dld_vlan_info_t *vlanp; -} dld_ioc_vlan_state_t; - -static int -drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg) +static void +drv_ioc_create_vlan(dld_ctl_str_t *ctls, mblk_t *mp) { - dld_ioc_vlan_state_t *statep = arg; + dld_ioc_create_vlan_t *dicp; + int err; + queue_t *q = ctls->cs_wq; - /* - * passed buffer space is limited to 65536 bytes. So - * copy only the vlans associated with the passed link. - */ - if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 && - dvp->dv_id != 0) { - if (statep->bytes_left < sizeof (dld_vlan_info_t)) - return (ENOSPC); - - (void) strlcpy(statep->vlanp->dvi_name, - dvp->dv_name, IFNAMSIZ); - statep->divp->div_count++; - statep->bytes_left -= sizeof (dld_vlan_info_t); - statep->vlanp += 1; + if ((err = miocpullup(mp, sizeof (dld_ioc_create_vlan_t))) != 0) + goto failed; + + dicp = (dld_ioc_create_vlan_t *)mp->b_cont->b_rptr; + + if ((err = dls_devnet_create_vlan(dicp->dic_vlanid, + dicp->dic_linkid, dicp->dic_vid, dicp->dic_force)) != 0) { + goto failed; } - return (0); + + miocack(q, mp, 0, 0); + return; + +failed: + miocnak(q, mp, 0, err); } +/* + * DLDIOC_DELETE_VLAN + */ static void -drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp) +drv_ioc_delete_vlan(dld_ctl_str_t *ctls, mblk_t *mp) { - dld_ioc_vlan_t *divp; - dld_ioc_vlan_state_t state; - int err = EINVAL; + dld_ioc_delete_vlan_t *didp; + int err; queue_t *q = ctls->cs_wq; - mblk_t *bp; - if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0) - goto failed; + if ((err = miocpullup(mp, sizeof (dld_ioc_delete_vlan_t))) != 0) + goto done; - if ((bp = msgpullup(mp->b_cont, -1)) == NULL) + didp = (dld_ioc_delete_vlan_t *)mp->b_cont->b_rptr; + err = dls_devnet_destroy_vlan(didp->did_linkid); + +done: + if (err == 0) + miocack(q, mp, 0, 0); + else + miocnak(q, mp, 0, err); +} + +/* + * DLDIOC_VLAN_ATTR + */ +static void +drv_ioc_vlan_attr(dld_ctl_str_t *ctls, mblk_t *mp) +{ + dld_ioc_vlan_attr_t *divp; + dls_dl_handle_t dlh; + uint16_t vid; + dls_vlan_t *dvp; + int err; + queue_t *q = ctls->cs_wq; + + if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_attr_t))) != 0) goto failed; - freemsg(mp->b_cont); - mp->b_cont = bp; - divp = (dld_ioc_vlan_t *)bp->b_rptr; - divp->div_count = 0; - state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t); - state.divp = divp; - state.vlanp = (dld_vlan_info_t *)(divp + 1); + divp = (dld_ioc_vlan_attr_t *)mp->b_cont->b_rptr; - err = dls_vlan_walk(drv_ioc_vlan_info, &state); + /* + * Hold this link to prevent it from being deleted. + */ + err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh); if (err != 0) goto failed; - miocack(q, mp, sizeof (dld_ioc_vlan_t) + - state.divp->div_count * sizeof (dld_vlan_info_t), 0); + if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) { + dls_devnet_rele_tmp(dlh); + err = EINVAL; + goto failed; + } + + err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE); + if (err != 0) { + dls_devnet_rele_tmp(dlh); + err = EINVAL; + goto failed; + } + + divp->div_linkid = dls_devnet_linkid(dlh); + divp->div_implicit = !dls_devnet_is_explicit(dlh); + divp->div_vid = vid; + divp->div_force = dvp->dv_force; + + dls_vlan_rele(dvp); + dls_devnet_rele_tmp(dlh); + miocack(q, mp, sizeof (dld_ioc_vlan_attr_t), 0); return; failed: - ASSERT(err != 0); miocnak(q, mp, 0, err); } /* - * DLDIOCHOLDVLAN + * DLDIOC_RENAME. + * + * This function handles two cases of link renaming. See more in comments above + * dls_datalink_rename(). + */ +static void +drv_ioc_rename(dld_ctl_str_t *ctls, mblk_t *mp) +{ + dld_ioc_rename_t *dir; + mod_hash_key_t key; + mod_hash_val_t val; + int err; + queue_t *q = ctls->cs_wq; + + if ((err = miocpullup(mp, sizeof (dld_ioc_rename_t))) != 0) + goto done; + + dir = (dld_ioc_rename_t *)mp->b_cont->b_rptr; + if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, + dir->dir_link)) != 0) { + goto done; + } + + if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) + goto done; + + /* + * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this + * renaming request is to rename a valid physical link (dir_linkid1) + * to a "removed" physical link (dir_linkid2, which is removed by DR + * or during system shutdown). In this case, the link (specified by + * dir_linkid1) would inherit all the configuration of dir_linkid2, + * and dir_linkid1 and its configuration would be lost. + * + * Remove per-link autopush configuration of dir_linkid1 in this case. + */ + key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; + rw_enter(&dld_ap_hash_lock, RW_WRITER); + if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { + rw_exit(&dld_ap_hash_lock); + goto done; + } + + VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); + kmem_free(val, sizeof (dld_ap_t)); + rw_exit(&dld_ap_hash_lock); + +done: + if (err == 0) + miocack(q, mp, 0, 0); + else + miocnak(q, mp, 0, err); +} + +/* + * DLDIOC_SETAUTOPUSH */ static void -drv_hold_vlan(dld_ctl_str_t *ctls, mblk_t *mp) +drv_ioc_setap(dld_ctl_str_t *ctls, mblk_t *mp) { + dld_ioc_ap_t *diap; + dld_ap_t *dap; + int i, err; queue_t *q = ctls->cs_wq; - dld_hold_vlan_t *dhv; - mblk_t *nmp; - int err = EINVAL; - dls_vlan_t *dvp; - char mac[MAXNAMELEN]; - dev_info_t *dip = NULL; - major_t major; - uint_t index; - - nmp = mp->b_cont; - if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) + mod_hash_key_t key; + + if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) goto failed; - dhv = (dld_hold_vlan_t *)nmp->b_rptr; + diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; + if (diap->dia_npush == 0 || diap->dia_npush > MAXAPUSH) { + err = EINVAL; + goto failed; + } /* - * When a device instance without opens is detached, its - * dls_vlan_t will be destroyed. A subsequent DLDIOCHOLDVLAN - * invoked on this device instance will fail because - * dls_vlan_hold() does not create non-tagged vlans on demand. - * To handle this problem, we must force the creation of the - * dls_vlan_t (if it doesn't already exist) by calling - * ddi_hold_devi_by_instance() before calling dls_vlan_hold(). + * Validate that the specified list of modules exist. */ - if (ddi_parse(dhv->dhv_name, mac, &index) != DDI_SUCCESS) - goto failed; + for (i = 0; i < diap->dia_npush; i++) { + if (fmodsw_find(diap->dia_aplist[i], FMODSW_LOAD) == NULL) { + err = EINVAL; + goto failed; + } + } - if (DLS_PPA2VID(index) == VLAN_ID_NONE && strcmp(mac, "aggr") != 0) { - if ((major = ddi_name_to_major(mac)) == (major_t)-1 || - (dip = ddi_hold_devi_by_instance(major, - DLS_PPA2INST(index), 0)) == NULL) + key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid; + + rw_enter(&dld_ap_hash_lock, RW_WRITER); + if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { + dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); + if (dap == NULL) { + rw_exit(&dld_ap_hash_lock); + err = ENOMEM; goto failed; + } + + dap->da_linkid = diap->dia_linkid; + err = mod_hash_insert(dld_ap_hashp, key, (mod_hash_val_t)dap); + ASSERT(err == 0); } - err = dls_vlan_hold(dhv->dhv_name, &dvp, B_TRUE); - if (dip != NULL) - ddi_release_devi(dip); + /* + * Update the configuration. + */ + dap->da_anchor = diap->dia_anchor; + dap->da_npush = diap->dia_npush; + for (i = 0; i < diap->dia_npush; i++) { + (void) strlcpy(dap->da_aplist[i], diap->dia_aplist[i], + FMNAMESZ + 1); + } + rw_exit(&dld_ap_hash_lock); - if (err != 0) + miocack(q, mp, 0, 0); + return; + +failed: + miocnak(q, mp, 0, err); +} + +/* + * DLDIOC_GETAUTOPUSH + */ +static void +drv_ioc_getap(dld_ctl_str_t *ctls, mblk_t *mp) +{ + dld_ioc_ap_t *diap; + dld_ap_t *dap; + int i, err; + queue_t *q = ctls->cs_wq; + + if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) goto failed; - if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid, - dhv->dhv_docheck)) != 0) { - dls_vlan_rele(dvp); + diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; + + rw_enter(&dld_ap_hash_lock, RW_READER); + if (mod_hash_find(dld_ap_hashp, + (mod_hash_key_t)(uintptr_t)diap->dia_linkid, + (mod_hash_val_t *)&dap) != 0) { + err = ENOENT; + rw_exit(&dld_ap_hash_lock); goto failed; - } else { - miocack(q, mp, 0, 0); - return; } + + /* + * Retrieve the configuration. + */ + diap->dia_anchor = dap->da_anchor; + diap->dia_npush = dap->da_npush; + for (i = 0; i < dap->da_npush; i++) { + (void) strlcpy(diap->dia_aplist[i], dap->da_aplist[i], + FMNAMESZ + 1); + } + rw_exit(&dld_ap_hash_lock); + + miocack(q, mp, sizeof (dld_ioc_ap_t), 0); + return; + failed: miocnak(q, mp, 0, err); } /* - * DLDIOCRELEVLAN + * DLDIOC_CLRAUTOPUSH */ static void -drv_rele_vlan(dld_ctl_str_t *ctls, mblk_t *mp) +drv_ioc_clrap(dld_ctl_str_t *ctls, mblk_t *mp) { - queue_t *q = ctls->cs_wq; - dld_hold_vlan_t *dhv; - mblk_t *nmp; + dld_ioc_ap_t *diap; + mod_hash_val_t val; + mod_hash_key_t key; int err; + queue_t *q = ctls->cs_wq; - nmp = mp->b_cont; - if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) { - err = EINVAL; - miocnak(q, mp, 0, err); - return; - } - dhv = (dld_hold_vlan_t *)nmp->b_rptr; + if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0) + goto done; - if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid, - dhv->dhv_docheck)) != 0) { - miocnak(q, mp, 0, err); - return; - } + diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr; + key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid; - if ((err = dls_vlan_rele_by_name(dhv->dhv_name)) != 0) { - miocnak(q, mp, 0, err); - return; + rw_enter(&dld_ap_hash_lock, RW_WRITER); + if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { + rw_exit(&dld_ap_hash_lock); + goto done; } - miocack(q, mp, 0, 0); + VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); + kmem_free(val, sizeof (dld_ap_t)); + rw_exit(&dld_ap_hash_lock); + +done: + if (err == 0) + miocack(q, mp, 0, 0); + else + miocnak(q, mp, 0, err); } /* - * DLDIOCZIDGET + * DLDIOC_DOORSERVER */ static void -drv_ioc_zid_get(dld_ctl_str_t *ctls, mblk_t *mp) +drv_ioc_doorserver(dld_ctl_str_t *ctls, mblk_t *mp) { queue_t *q = ctls->cs_wq; - dld_hold_vlan_t *dhv; - mblk_t *nmp; + dld_ioc_door_t *did; int err; - nmp = mp->b_cont; - if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) { - err = EINVAL; + if ((err = miocpullup(mp, sizeof (dld_ioc_door_t))) != 0) + goto done; + + did = (dld_ioc_door_t *)mp->b_cont->b_rptr; + err = dls_mgmt_door_set(did->did_start_door); + +done: + if (err == 0) + miocack(q, mp, 0, 0); + else miocnak(q, mp, 0, err); - return; - } - dhv = (dld_hold_vlan_t *)nmp->b_rptr; +} + +/* + * DLDIOC_SETZID + */ +static void +drv_ioc_setzid(dld_ctl_str_t *ctls, mblk_t *mp) +{ + queue_t *q = ctls->cs_wq; + dld_ioc_setzid_t *dis; + int err; + + if ((err = miocpullup(mp, sizeof (dld_ioc_setzid_t))) != 0) + goto done; - if ((err = dls_vlan_getzoneid(dhv->dhv_name, &dhv->dhv_zid)) != 0) + dis = (dld_ioc_setzid_t *)mp->b_cont->b_rptr; + err = dls_devnet_setzid(dis->dis_link, dis->dis_zid); + +done: + if (err == 0) + miocack(q, mp, 0, 0); + else miocnak(q, mp, 0, err); +} + +/* + * DLDIOC_GETZID + */ +static void +drv_ioc_getzid(dld_ctl_str_t *ctls, mblk_t *mp) +{ + queue_t *q = ctls->cs_wq; + dld_ioc_getzid_t *dig; + int err; + + if ((err = miocpullup(mp, sizeof (dld_ioc_getzid_t))) != 0) + goto done; + + dig = (dld_ioc_getzid_t *)mp->b_cont->b_rptr; + err = dls_devnet_getzid(dig->dig_linkid, &dig->dig_zid); + +done: + if (err == 0) + miocack(q, mp, sizeof (dld_ioc_getzid_t), 0); else - miocack(q, mp, sizeof (dld_hold_vlan_t), 0); + miocnak(q, mp, 0, err); } /* @@ -620,29 +885,50 @@ drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; switch (cmd) { - case DLDIOCATTR: + case DLDIOC_ATTR: drv_ioc_attr(ctls, mp); return; - case DLDIOCVLAN: - drv_ioc_vlan(ctls, mp); + case DLDIOC_PHYS_ATTR: + drv_ioc_phys_attr(ctls, mp); return; - case DLDIOCSECOBJSET: + case DLDIOC_SECOBJ_SET: drv_ioc_secobj_set(ctls, mp); return; - case DLDIOCSECOBJGET: + case DLDIOC_SECOBJ_GET: drv_ioc_secobj_get(ctls, mp); return; - case DLDIOCSECOBJUNSET: + case DLDIOC_SECOBJ_UNSET: drv_ioc_secobj_unset(ctls, mp); return; - case DLDIOCHOLDVLAN: - drv_hold_vlan(ctls, mp); + case DLDIOC_CREATE_VLAN: + drv_ioc_create_vlan(ctls, mp); + return; + case DLDIOC_DELETE_VLAN: + drv_ioc_delete_vlan(ctls, mp); + return; + case DLDIOC_VLAN_ATTR: + drv_ioc_vlan_attr(ctls, mp); + return; + case DLDIOC_SETAUTOPUSH: + drv_ioc_setap(ctls, mp); + return; + case DLDIOC_GETAUTOPUSH: + drv_ioc_getap(ctls, mp); + return; + case DLDIOC_CLRAUTOPUSH: + drv_ioc_clrap(ctls, mp); return; - case DLDIOCRELEVLAN: - drv_rele_vlan(ctls, mp); + case DLDIOC_DOORSERVER: + drv_ioc_doorserver(ctls, mp); return; - case DLDIOCZIDGET: - drv_ioc_zid_get(ctls, mp); + case DLDIOC_SETZID: + drv_ioc_setzid(ctls, mp); + return; + case DLDIOC_GETZID: + drv_ioc_getzid(ctls, mp); + return; + case DLDIOC_RENAME: + drv_ioc_rename(ctls, mp); return; default: miocnak(ctls->cs_wq, mp, 0, ENOTSUP); @@ -681,6 +967,55 @@ drv_uw_srv(queue_t *q) } /* + * Check for GLDv3 autopush information. There are three cases: + * + * 1. If devp points to a GLDv3 datalink and it has autopush configuration, + * fill dlap in with that information and return 0. + * + * 2. If devp points to a GLDv3 datalink but it doesn't have autopush + * configuration, then replace devp with the physical device (if one + * exists) and return 1. This allows stropen() to find the old-school + * per-driver autopush configuration. (For softmac, the result is that + * the softmac dev_t is replaced with the legacy device's dev_t). + * + * 3. If neither of the above apply, don't touch the args and return -1. + */ +int +dld_autopush(dev_t *devp, struct dlautopush *dlap) +{ + dld_ap_t *dap; + datalink_id_t linkid; + dev_t phydev; + + if (!GLDV3_DRV(getmajor(*devp))) + return (-1); + + /* + * Find the linkid by the link's dev_t. + */ + if (dls_devnet_dev2linkid(*devp, &linkid) != 0) + return (-1); + + /* + * Find the autopush configuration associated with the linkid. + */ + rw_enter(&dld_ap_hash_lock, RW_READER); + if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, + (mod_hash_val_t *)&dap) == 0) { + *dlap = dap->da_ap; + rw_exit(&dld_ap_hash_lock); + return (0); + } + rw_exit(&dld_ap_hash_lock); + + if (dls_devnet_phydev(linkid, &phydev) != 0) + return (-1); + + *devp = phydev; + return (1); +} + +/* * Secure objects implementation */ diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c index 3eb892ac71..78543294d4 100644 --- a/usr/src/uts/common/io/dld/dld_proto.c +++ b/usr/src/uts/common/io/dld/dld_proto.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,13 +54,10 @@ static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req, proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req, proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req, proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req, - proto_notify_req, proto_unitdata_req, proto_passive_req; + proto_notify_req, proto_passive_req; static void proto_poll_disable(dld_str_t *); static boolean_t proto_poll_enable(dld_str_t *, dl_capab_dls_t *); -static boolean_t proto_capability_advertise(dld_str_t *, mblk_t *); - -static task_func_t proto_process_unbind_req, proto_process_detach_req; static void proto_soft_ring_disable(dld_str_t *); static boolean_t proto_soft_ring_enable(dld_str_t *, dl_capab_dls_t *); @@ -82,15 +79,12 @@ static void proto_change_soft_ring_fanout(dld_str_t *, int); * by the above primitives. */ void -dld_proto(dld_str_t *dsp, mblk_t *mp) +dld_wput_proto_nondata(dld_str_t *dsp, mblk_t *mp) { union DL_primitives *udlp; t_uscalar_t prim; - if (MBLKL(mp) < sizeof (t_uscalar_t)) { - freemsg(mp); - return; - } + ASSERT(MBLKL(mp) >= sizeof (t_uscalar_t)); udlp = (union DL_primitives *)mp->b_rptr; prim = udlp->dl_primitive; @@ -105,9 +99,6 @@ dld_proto(dld_str_t *dsp, mblk_t *mp) case DL_UNBIND_REQ: (void) proto_unbind_req(dsp, udlp, mp); break; - case DL_UNITDATA_REQ: - (void) proto_unitdata_req(dsp, udlp, mp); - break; case DL_UDQOS_REQ: (void) proto_udqos_req(dsp, udlp, mp); break; @@ -150,28 +141,6 @@ dld_proto(dld_str_t *dsp, mblk_t *mp) } } -/* - * Finish any pending operations. - * Requests that need to be processed asynchronously will be handled - * by a separate thread. After this function returns, other threads - * will be allowed to enter dld; they will not be able to do anything - * until ds_dlstate transitions to a non-pending state. - */ -void -dld_finish_pending_ops(dld_str_t *dsp) -{ - task_func_t *op = NULL; - - ASSERT(MUTEX_HELD(&dsp->ds_thr_lock)); - ASSERT(dsp->ds_thr == 0); - - op = dsp->ds_pending_op; - dsp->ds_pending_op = NULL; - mutex_exit(&dsp->ds_thr_lock); - if (op != NULL) - (void) taskq_dispatch(system_taskq, op, dsp, TQ_SLEEP); -} - #define NEG(x) -(x) typedef struct dl_info_ack_wrapper { @@ -411,30 +380,6 @@ failed: return (B_FALSE); } -/* - * DL_DETACH_REQ - */ -static void -proto_process_detach_req(void *arg) -{ - dld_str_t *dsp = arg; - mblk_t *mp; - - /* - * We don't need to hold locks because no other thread - * would manipulate dsp while it is in a PENDING state. - */ - ASSERT(dsp->ds_pending_req != NULL); - ASSERT(dsp->ds_dlstate == DL_DETACH_PENDING); - - mp = dsp->ds_pending_req; - dsp->ds_pending_req = NULL; - dld_str_detach(dsp); - dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); - - DLD_WAKEUP(dsp); -} - /*ARGSUSED*/ static boolean_t proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) @@ -460,18 +405,10 @@ proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) } dsp->ds_dlstate = DL_DETACH_PENDING; + dld_str_detach(dsp); - /* - * Complete the detach when the driver is single-threaded. - */ - mutex_enter(&dsp->ds_thr_lock); - ASSERT(dsp->ds_pending_req == NULL); - dsp->ds_pending_req = mp; - dsp->ds_pending_op = proto_process_detach_req; - dsp->ds_pending_cnt++; - mutex_exit(&dsp->ds_thr_lock); rw_exit(&dsp->ds_lock); - + dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); return (B_TRUE); failed: rw_exit(&dsp->ds_lock); @@ -493,8 +430,11 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) t_scalar_t sap; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); - + /* + * Because control message processing is serialized, we don't need + * to hold any locks to read any fields of dsp; we only need ds_lock + * to update the ds_dlstate, ds_sap and ds_passivestate fields. + */ if (MBLKL(mp) < sizeof (dl_bind_req_t)) { dl_err = DL_BADPRIM; goto failed; @@ -522,7 +462,6 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - dsp->ds_dlstate = DL_BIND_PENDING; /* * Set the receive callback. */ @@ -532,8 +471,8 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Bind the channel such that it can receive packets. */ - sap = dsp->ds_sap = dlp->dl_sap; - err = dls_bind(dsp->ds_dc, dlp->dl_sap); + sap = dlp->dl_sap; + err = dls_bind(dsp->ds_dc, sap); if (err != 0) { switch (err) { case EINVAL: @@ -544,7 +483,7 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dl_err = DL_SYSERR; break; } - dsp->ds_dlstate = DL_UNBOUND; + if (dsp->ds_passivestate == DLD_UNINITIALIZED) dls_active_clear(dsp->ds_dc); @@ -560,19 +499,27 @@ proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Copy in the SAP. */ - *(uint16_t *)(dlsap_addr + dlsap_addr_length) = dsp->ds_sap; + *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap; dlsap_addr_length += sizeof (uint16_t); + rw_enter(&dsp->ds_lock, RW_WRITER); + dsp->ds_dlstate = DL_IDLE; if (dsp->ds_passivestate == DLD_UNINITIALIZED) dsp->ds_passivestate = DLD_ACTIVE; + dsp->ds_sap = sap; + + if (dsp->ds_mode == DLD_FASTPATH) + dsp->ds_tx = str_mdata_fastpath_put; + else if (dsp->ds_mode == DLD_RAW) + dsp->ds_tx = str_mdata_raw_put; + dsp->ds_unitdata_tx = dld_wput_proto_data; rw_exit(&dsp->ds_lock); dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -581,18 +528,21 @@ failed: * DL_UNBIND_REQ */ /*ARGSUSED*/ -static void -proto_process_unbind_req(void *arg) +static boolean_t +proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { - dld_str_t *dsp = arg; - mblk_t *mp; + queue_t *q = dsp->ds_wq; + t_uscalar_t dl_err; - /* - * We don't need to hold locks because no other thread - * would manipulate dsp while it is in a PENDING state. - */ - ASSERT(dsp->ds_pending_req != NULL); - ASSERT(dsp->ds_dlstate == DL_UNBIND_PENDING); + if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { + dl_err = DL_BADPRIM; + goto failed; + } + + if (dsp->ds_dlstate != DL_IDLE) { + dl_err = DL_OUTSTATE; + goto failed; + } /* * Flush any remaining packets scheduled for transmission. @@ -605,76 +555,40 @@ proto_process_unbind_req(void *arg) dls_unbind(dsp->ds_dc); /* + * Clear the receive callback. + */ + dls_rx_set(dsp->ds_dc, NULL, NULL); + + rw_enter(&dsp->ds_lock, RW_WRITER); + + /* * Disable polling mode, if it is enabled. */ proto_poll_disable(dsp); /* - * Clear LSO flags. + * If soft rings were enabled, the workers should be quiesced. */ - dsp->ds_lso = B_FALSE; - dsp->ds_lso_max = 0; + dls_soft_ring_disable(dsp->ds_dc); /* - * Clear the receive callback. + * Clear LSO flags. */ - dls_rx_set(dsp->ds_dc, NULL, NULL); + dsp->ds_lso = B_FALSE; + dsp->ds_lso_max = 0; /* * Set the mode back to the default (unitdata). */ dsp->ds_mode = DLD_UNITDATA; - - /* - * If soft rings were enabled, the workers - * should be quiesced. We cannot check for - * ds_soft_ring flag because - * proto_soft_ring_disable() called from - * proto_capability_req() would have reset it. - */ - if (dls_soft_ring_workers(dsp->ds_dc)) - dls_soft_ring_disable(dsp->ds_dc); - - mp = dsp->ds_pending_req; - dsp->ds_pending_req = NULL; dsp->ds_dlstate = DL_UNBOUND; - dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ); - - DLD_WAKEUP(dsp); -} - -/*ARGSUSED*/ -static boolean_t -proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) -{ - queue_t *q = dsp->ds_wq; - t_uscalar_t dl_err; - - rw_enter(&dsp->ds_lock, RW_WRITER); - - if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { - dl_err = DL_BADPRIM; - goto failed; - } - - if (dsp->ds_dlstate != DL_IDLE) { - dl_err = DL_OUTSTATE; - goto failed; - } - - dsp->ds_dlstate = DL_UNBIND_PENDING; - - mutex_enter(&dsp->ds_thr_lock); - ASSERT(dsp->ds_pending_req == NULL); - dsp->ds_pending_req = mp; - dsp->ds_pending_op = proto_process_unbind_req; - dsp->ds_pending_cnt++; - mutex_exit(&dsp->ds_thr_lock); + DLD_TX_QUIESCE(dsp); rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_UNBIND_REQ); + return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); return (B_FALSE); } @@ -688,11 +602,14 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; int err = 0; t_uscalar_t dl_err; - uint32_t promisc_saved; + uint32_t promisc; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); - + /* + * Because control message processing is serialized, we don't need + * to hold any locks to read any fields of dsp; we only need ds_lock + * to update the ds_promisc and ds_passivestate fields. + */ if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { dl_err = DL_BADPRIM; goto failed; @@ -704,20 +621,16 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: - dsp->ds_promisc |= DLS_PROMISC_SAP; + promisc = DLS_PROMISC_SAP; break; - case DL_PROMISC_MULTI: - dsp->ds_promisc |= DLS_PROMISC_MULTI; + promisc = DLS_PROMISC_MULTI; break; - case DL_PROMISC_PHYS: - dsp->ds_promisc |= DLS_PROMISC_PHYS; + promisc = DLS_PROMISC_PHYS; break; - default: dl_err = DL_NOTSUPPORTED; goto failed; @@ -725,7 +638,6 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) if (dsp->ds_passivestate == DLD_UNINITIALIZED && !dls_active_set(dsp->ds_dc)) { - dsp->ds_promisc = promisc_saved; dl_err = DL_SYSERR; err = EBUSY; goto failed; @@ -734,24 +646,24 @@ proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Adjust channel promiscuity. */ - err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); + promisc = (dsp->ds_promisc | promisc); + err = dls_promisc(dsp->ds_dc, promisc); if (err != 0) { dl_err = DL_SYSERR; - dsp->ds_promisc = promisc_saved; if (dsp->ds_passivestate == DLD_UNINITIALIZED) dls_active_clear(dsp->ds_dc); - goto failed; } + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_passivestate == DLD_UNINITIALIZED) dsp->ds_passivestate = DLD_ACTIVE; - + dsp->ds_promisc = promisc; rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_PROMISCON_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -765,11 +677,14 @@ proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; int err = 0; t_uscalar_t dl_err; - uint32_t promisc_saved; + uint32_t promisc; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); - + /* + * Because control messages processing is serialized, we don't need + * to hold any lock to read any field of dsp; we hold ds_lock to + * update the ds_promisc field. + */ if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { dl_err = DL_BADPRIM; goto failed; @@ -781,52 +696,40 @@ proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: - if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) { - dl_err = DL_NOTENAB; - goto failed; - } - dsp->ds_promisc &= ~DLS_PROMISC_SAP; + promisc = DLS_PROMISC_SAP; break; - case DL_PROMISC_MULTI: - if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) { - dl_err = DL_NOTENAB; - goto failed; - } - dsp->ds_promisc &= ~DLS_PROMISC_MULTI; + promisc = DLS_PROMISC_MULTI; break; - case DL_PROMISC_PHYS: - if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) { - dl_err = DL_NOTENAB; - goto failed; - } - dsp->ds_promisc &= ~DLS_PROMISC_PHYS; + promisc = DLS_PROMISC_PHYS; break; - default: dl_err = DL_NOTSUPPORTED; goto failed; } - /* - * Adjust channel promiscuity. - */ - err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); + if (!(dsp->ds_promisc & promisc)) { + dl_err = DL_NOTENAB; + goto failed; + } + + promisc = (dsp->ds_promisc & ~promisc); + err = dls_promisc(dsp->ds_dc, promisc); if (err != 0) { - dsp->ds_promisc = promisc_saved; dl_err = DL_SYSERR; goto failed; } + rw_enter(&dsp->ds_lock, RW_WRITER); + dsp->ds_promisc = promisc; rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_PROMISCOFF_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -842,8 +745,11 @@ proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); - + /* + * Because control messages processing is serialized, we don't need + * to hold any lock to read any field of dsp; we hold ds_lock to + * update the ds_passivestate field. + */ if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; @@ -879,20 +785,21 @@ proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dl_err = DL_SYSERR; break; } + if (dsp->ds_passivestate == DLD_UNINITIALIZED) dls_active_clear(dsp->ds_dc); goto failed; } + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_passivestate == DLD_UNINITIALIZED) dsp->ds_passivestate = DLD_ACTIVE; - rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_ENABMULTI_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -908,8 +815,10 @@ proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_READER); - + /* + * Because control messages processing is serialized, we don't need + * to hold any lock to read any field of dsp. + */ if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; @@ -925,17 +834,15 @@ proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); if (err != 0) { - switch (err) { + switch (err) { case EINVAL: dl_err = DL_BADADDR; err = 0; break; - case ENOENT: dl_err = DL_NOTENAB; err = 0; break; - default: dl_err = DL_SYSERR; break; @@ -943,11 +850,9 @@ proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - rw_exit(&dsp->ds_lock); dlokack(q, mp, DL_DISABMULTI_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -1019,8 +924,11 @@ proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); - + /* + * Because control message processing is serialized, we don't need + * to hold any locks to read any fields of dsp; we only need ds_lock + * to update the ds_passivestate field. + */ if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; @@ -1053,19 +961,21 @@ proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dl_err = DL_SYSERR; break; } + if (dsp->ds_passivestate == DLD_UNINITIALIZED) dls_active_clear(dsp->ds_dc); goto failed; } + + rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_passivestate == DLD_UNINITIALIZED) dsp->ds_passivestate = DLD_ACTIVE; - rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); return (B_FALSE); } @@ -1085,8 +995,6 @@ proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) off = dlp->dl_qos_offset; len = dlp->dl_qos_length; - rw_enter(&dsp->ds_lock, RW_WRITER); - if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { dl_err = DL_BADPRIM; goto failed; @@ -1104,13 +1012,19 @@ proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - dsp->ds_pri = selp->dl_priority; + if (dsp->ds_dlstate == DL_UNATTACHED || + DL_ACK_PENDING(dsp->ds_dlstate)) { + dl_err = DL_OUTSTATE; + goto failed; + } + rw_enter(&dsp->ds_lock, RW_WRITER); + dsp->ds_pri = selp->dl_priority; rw_exit(&dsp->ds_lock); + dlokack(q, mp, DL_UDQOS_REQ); return (B_TRUE); failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); return (B_FALSE); } @@ -1142,9 +1056,8 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) offset_t off, end; t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; - boolean_t upgraded; - rw_enter(&dsp->ds_lock, RW_READER); + rw_enter(&dsp->ds_lock, RW_WRITER); if (MBLKL(mp) < sizeof (dl_capability_req_t)) { dl_err = DL_BADPRIM; @@ -1180,7 +1093,6 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Walk the list of capabilities to be enabled. */ - upgraded = B_FALSE; for (end = off + len; off < end; ) { sp = (dl_capability_sub_t *)(mp->b_rptr + off); size = sizeof (dl_capability_sub_t) + sp->dl_length; @@ -1239,24 +1151,6 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) */ bcopy(pollp, &poll, sizeof (dl_capab_dls_t)); - /* - * We need to become writer before enabling and/or - * disabling the polling interface. If we couldn' - * upgrade, check state again after re-acquiring the - * lock to make sure we can proceed. - */ - if (!upgraded && !rw_tryupgrade(&dsp->ds_lock)) { - rw_exit(&dsp->ds_lock); - rw_enter(&dsp->ds_lock, RW_WRITER); - - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dl_err = DL_OUTSTATE; - goto failed; - } - } - upgraded = B_TRUE; - switch (poll.dls_flags) { default: /*FALLTHRU*/ @@ -1273,12 +1167,15 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) proto_poll_disable(dsp); /* - * Now attempt enable it. + * Note that only IP should enable POLL. */ if (check_ip_above(dsp->ds_rq) && proto_poll_enable(dsp, &poll)) { bzero(&poll, sizeof (dl_capab_dls_t)); poll.dls_flags = POLL_ENABLE; + } else { + bzero(&poll, sizeof (dl_capab_dls_t)); + poll.dls_flags = POLL_DISABLE; } break; } @@ -1298,24 +1195,6 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) bcopy(soft_ringp, &soft_ring, sizeof (dl_capab_dls_t)); - /* - * We need to become writer before enabling and/or - * disabling the soft_ring interface. If we couldn' - * upgrade, check state again after re-acquiring the - * lock to make sure we can proceed. - */ - if (!upgraded && !rw_tryupgrade(&dsp->ds_lock)) { - rw_exit(&dsp->ds_lock); - rw_enter(&dsp->ds_lock, RW_WRITER); - - if (dsp->ds_dlstate == DL_UNATTACHED || - DL_ACK_PENDING(dsp->ds_dlstate)) { - dl_err = DL_OUTSTATE; - goto failed; - } - } - upgraded = B_TRUE; - switch (soft_ring.dls_flags) { default: /*FALLTHRU*/ @@ -1331,19 +1210,17 @@ proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) proto_soft_ring_disable(dsp); /* - * Now attempt enable it. + * Note that only IP can enable soft ring. */ if (check_ip_above(dsp->ds_rq) && proto_soft_ring_enable(dsp, &soft_ring)) { bzero(&soft_ring, sizeof (dl_capab_dls_t)); - soft_ring.dls_flags = - SOFT_RING_ENABLE; + soft_ring.dls_flags = SOFT_RING_ENABLE; } else { bzero(&soft_ring, sizeof (dl_capab_dls_t)); - soft_ring.dls_flags = - SOFT_RING_DISABLE; + soft_ring.dls_flags = SOFT_RING_DISABLE; } break; } @@ -1399,6 +1276,8 @@ proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } + note &= ~(mac_no_notification(dsp->ds_mh)); + /* * Cache the notifications that are being enabled. */ @@ -1428,13 +1307,13 @@ failed: } /* - * DL_UINTDATA_REQ + * DL_UNITDATA_REQ */ -static boolean_t -proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) +void +dld_wput_proto_data(dld_str_t *dsp, mblk_t *mp) { queue_t *q = dsp->ds_wq; - dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)udlp; + dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr; off_t off; size_t len, size; const uint8_t *addr; @@ -1444,17 +1323,11 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) uint32_t start, stuff, end, value, flags; t_uscalar_t dl_err; - rw_enter(&dsp->ds_lock, RW_READER); - if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { dl_err = DL_BADPRIM; goto failed; } - if (dsp->ds_dlstate != DL_IDLE) { - dl_err = DL_OUTSTATE; - goto failed; - } addr_length = dsp->ds_mip->mi_addr_length; off = dlp->dl_dest_addr_offset; @@ -1514,25 +1387,14 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) */ ASSERT(bp->b_cont == NULL); bp->b_cont = payload; - - /* - * No lock can be held across putnext, which can be called - * from here in dld_tx_single(). The config is held constant - * by the DLD_ENTER done in dld_wput()/dld_wsrv until all - * sending threads are done. - */ - rw_exit(&dsp->ds_lock); dld_tx_single(dsp, bp); - return (B_TRUE); + return; failed: - rw_exit(&dsp->ds_lock); dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0); - return (B_FALSE); + return; baddata: - rw_exit(&dsp->ds_lock); dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); - return (B_FALSE); } /* @@ -1544,7 +1406,12 @@ proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) { t_uscalar_t dl_err; - rw_enter(&dsp->ds_lock, RW_WRITER); + /* + * READER lock is enough because ds_passivestate can only be changed + * as the result of non-data message processing. + */ + rw_enter(&dsp->ds_lock, RW_READER); + /* * If we've already become active by issuing an active primitive, * then it's too late to try to become passive. @@ -1569,7 +1436,6 @@ failed: return (B_FALSE); } - /* * Catch-all handler. */ @@ -1585,7 +1451,7 @@ proto_poll_disable(dld_str_t *dsp) { mac_handle_t mh; - ASSERT(dsp->ds_pending_req != NULL || RW_WRITE_HELD(&dsp->ds_lock)); + ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); if (!dsp->ds_polling) return; @@ -1606,7 +1472,7 @@ proto_poll_disable(dld_str_t *dsp) * Set receive function back to default. */ dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? - dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp); + dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); /* * Note that polling is disabled. @@ -1636,10 +1502,11 @@ proto_poll_enable(dld_str_t *dsp, dl_capab_dls_t *pollp) */ mac_resource_set(mh, (mac_resource_add_t)pollp->dls_ring_add, (void *)pollp->dls_rx_handle); + mac_resources(mh); /* - * Set the receive function. + * Set the upstream receive function. */ dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->dls_rx, (void *)pollp->dls_rx_handle); @@ -1694,15 +1561,14 @@ proto_soft_ring_enable(dld_str_t *dsp, dl_capab_dls_t *soft_ringp) static void proto_change_soft_ring_fanout(dld_str_t *dsp, int type) { - dls_rx_t rx; + dls_channel_t dc = dsp->ds_dc; if (type == SOFT_RING_NONE) { - rx = (dsp->ds_mode == DLD_FASTPATH) ? - dld_str_rx_fastpath : dld_str_rx_unitdata; - } else { - rx = (dls_rx_t)dls_soft_ring_fanout; + dls_rx_set(dc, (dsp->ds_mode == DLD_FASTPATH) ? + dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); + } else if (type != SOFT_RING_NONE) { + dls_rx_set(dc, (dls_rx_t)dls_soft_ring_fanout, dc); } - dls_soft_ring_rx_set(dsp->ds_dc, rx, dsp, type); } /* @@ -1720,14 +1586,17 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) dl_capab_lso_t lso; dl_capab_zerocopy_t zcopy; uint8_t *ptr; - boolean_t cksum_cap; - boolean_t poll_cap; - boolean_t lso_cap; - mac_capab_lso_t mac_lso; queue_t *q = dsp->ds_wq; mblk_t *mp1; + boolean_t is_vlan = (dsp->ds_vid != VLAN_ID_NONE); + boolean_t poll_capable = B_FALSE; + boolean_t soft_ring_capable = B_FALSE; + boolean_t hcksum_capable = B_FALSE; + boolean_t zcopy_capable = B_FALSE; + boolean_t lso_capable = B_FALSE; + mac_capab_lso_t mac_lso; - ASSERT(RW_READ_HELD(&dsp->ds_lock)); + ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); /* * Initially assume no capabilities. @@ -1735,10 +1604,17 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) subsize = 0; /* - * Advertize soft ring capability unless it has been explicitly - * disabled. + * Check if soft ring can be enabled on this interface. Note that we + * do not enable softring on any legacy drivers, because doing that + * would hurt the performance if the legacy driver has its own taskq + * implementation. Further, most high-performance legacy drivers do + * have their own taskq implementation. + * + * If advertising DL_CAPAB_SOFT_RING has not been explicitly disabled, + * reserve space for that capability. */ - if (!(dld_opt & DLD_OPT_NO_SOFTRING)) { + if (!mac_is_legacy(dsp->ds_mh) && !(dld_opt & DLD_OPT_NO_SOFTRING)) { + soft_ring_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_dls_t); } @@ -1748,37 +1624,48 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) * If advertising DL_CAPAB_POLL has not been explicitly disabled * then reserve space for that capability. */ - poll_cap = (mac_capab_get(dsp->ds_mh, MAC_CAPAB_POLL, NULL) && - !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE)); - if (poll_cap) { + if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_POLL, NULL) && + !(dld_opt & DLD_OPT_NO_POLL) && !is_vlan) { + poll_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_dls_t); } /* - * If the MAC interface supports checksum offload then reserve - * space for the DL_CAPAB_HCKSUM capability. + * Check if checksum offload is supported on this MAC. Don't + * advertise DL_CAPAB_HCKSUM if the underlying MAC is VLAN incapable, + * since it might not be able to do the hardware checksum offload + * with the correct offset. */ - if (cksum_cap = mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM, + bzero(&hcksum, sizeof (dl_capab_hcksum_t)); + if ((!is_vlan || (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_NATIVEVLAN, + NULL))) && mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM, &hcksum.hcksum_txflags)) { - subsize += sizeof (dl_capability_sub_t) + - sizeof (dl_capab_hcksum_t); + if (hcksum.hcksum_txflags != 0) { + hcksum_capable = B_TRUE; + subsize += sizeof (dl_capability_sub_t) + + sizeof (dl_capab_hcksum_t); + } } /* - * If LSO is usable for MAC, reserve space for the DL_CAPAB_LSO - * capability. + * Check if LSO is supported on this MAC, then reserve space for + * the DL_CAPAB_LSO capability. */ - if (lso_cap = mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) { + if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) { + lso_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_lso_t); } /* - * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then - * reserve space for it. + * Check if zerocopy is supported on this interface. + * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled + * then reserve space for that capability. */ - if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { + if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) && + !(dld_opt & DLD_OPT_NO_ZEROCOPY)) { + zcopy_capable = B_TRUE; subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_zerocopy_t); } @@ -1807,60 +1694,32 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) /* * IP polling interface. */ - if (poll_cap) { + if (poll_capable) { /* * Attempt to disable just in case this is a re-negotiation; - * we need to become writer before doing so. - */ - if (!rw_tryupgrade(&dsp->ds_lock)) { - rw_exit(&dsp->ds_lock); - rw_enter(&dsp->ds_lock, RW_WRITER); - } - - /* - * Check if polling state has changed after we re-acquired - * the lock above, so that we don't mis-advertise it. + * READER lock is enough because ds_polling can only be + * changed as the result of non-data message processing. */ - poll_cap = !(dld_opt & DLD_OPT_NO_POLL) && - (dsp->ds_vid == VLAN_ID_NONE); - - if (!poll_cap) { - int poll_capab_size; - - rw_downgrade(&dsp->ds_lock); - - poll_capab_size = sizeof (dl_capability_sub_t) + - sizeof (dl_capab_dls_t); - - mp->b_wptr -= poll_capab_size; - subsize -= poll_capab_size; - dlap->dl_sub_length = subsize; - } else { - proto_poll_disable(dsp); - - rw_downgrade(&dsp->ds_lock); - - dlsp = (dl_capability_sub_t *)ptr; + proto_poll_disable(dsp); - dlsp->dl_cap = DL_CAPAB_POLL; - dlsp->dl_length = sizeof (dl_capab_dls_t); - ptr += sizeof (dl_capability_sub_t); + dlsp = (dl_capability_sub_t *)ptr; - bzero(&poll, sizeof (dl_capab_dls_t)); - poll.dls_version = POLL_VERSION_1; - poll.dls_flags = POLL_CAPABLE; - poll.dls_tx_handle = (uintptr_t)dsp; - poll.dls_tx = (uintptr_t)str_mdata_fastpath_put; + dlsp->dl_cap = DL_CAPAB_POLL; + dlsp->dl_length = sizeof (dl_capab_dls_t); + ptr += sizeof (dl_capability_sub_t); - dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); - bcopy(&poll, ptr, sizeof (dl_capab_dls_t)); - ptr += sizeof (dl_capab_dls_t); - } + bzero(&poll, sizeof (dl_capab_dls_t)); + poll.dls_version = POLL_VERSION_1; + poll.dls_flags = POLL_CAPABLE; + poll.dls_tx_handle = (uintptr_t)dsp; + poll.dls_tx = (uintptr_t)str_mdata_fastpath_put; + dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); + bcopy(&poll, ptr, sizeof (dl_capab_dls_t)); + ptr += sizeof (dl_capab_dls_t); } - ASSERT(RW_READ_HELD(&dsp->ds_lock)); - if (!(dld_opt & DLD_OPT_NO_SOFTRING)) { + if (soft_ring_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_SOFT_RING; @@ -1885,7 +1744,7 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) /* * TCP/IP checksum offload. */ - if (cksum_cap) { + if (hcksum_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_HCKSUM; @@ -1901,7 +1760,7 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) /* * Large segment offload. (LSO) */ - if (lso_cap) { + if (lso_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_LSO; @@ -1927,7 +1786,7 @@ proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) /* * Zero copy */ - if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { + if (zcopy_capable) { dlsp = (dl_capability_sub_t *)ptr; dlsp->dl_cap = DL_CAPAB_ZEROCOPY; diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c index 75d0d6e08c..f89e4a5f94 100644 --- a/usr/src/uts/common/io/dld/dld_str.c +++ b/usr/src/uts/common/io/dld/dld_str.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. */ @@ -33,7 +33,8 @@ #include <sys/strsun.h> #include <sys/strsubr.h> #include <sys/atomic.h> -#include <sys/mkdev.h> +#include <sys/disp.h> +#include <sys/callb.h> #include <sys/vlan.h> #include <sys/dld.h> #include <sys/dld_impl.h> @@ -53,22 +54,35 @@ static void str_notify_speed(dld_str_t *, uint32_t); static void str_notify(void *, mac_notify_type_t); static void ioc_native(dld_str_t *, mblk_t *); +static void ioc_margin(dld_str_t *, mblk_t *); static void ioc_raw(dld_str_t *, mblk_t *); static void ioc_fast(dld_str_t *, mblk_t *); static void ioc(dld_str_t *, mblk_t *); -static void dld_ioc(dld_str_t *, mblk_t *); -static void str_mdata_raw_put(dld_str_t *, mblk_t *); +static void dld_tx_enqueue(dld_str_t *, mblk_t *, mblk_t *, boolean_t, + uint_t, uint_t); +static void dld_wput_nondata(dld_str_t *, mblk_t *); +static void dld_wput_nondata_task(void *); +static void dld_flush_nondata(dld_str_t *); static mblk_t *i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t); static mblk_t *i_dld_ether_header_strip_tag(mblk_t *); static uint32_t str_count; static kmem_cache_t *str_cachep; -static uint32_t minor_count; +static taskq_t *dld_disp_taskq = NULL; static mod_hash_t *str_hashp; #define STR_HASHSZ 64 #define STR_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)(key)) +static inline uint_t mp_getsize(mblk_t *); + +/* + * Interval to count the TX queued depth. Default is 1s (1000000us). + * Count the queue depth immediately (not by timeout) if this is set to 0. + * See more details above dld_tx_enqueue(). + */ +uint_t tx_qdepth_interval = 1000000; + /* * Some notes on entry points, flow-control, queueing and locking: * @@ -162,33 +176,19 @@ i_dld_str_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) ASSERT(statep->ds_minor != 0); /* - * Access to ds_ppa and ds_mh need to be protected by ds_lock. + * Access to ds_mh needs to be protected by ds_lock. */ rw_enter(&dsp->ds_lock, RW_READER); - if (statep->ds_minor <= DLD_MAX_MINOR) { - /* - * Style 1: minor can be derived from the ppa. we - * continue to walk until we find a matching stream - * in attached state. - */ - if (statep->ds_minor == DLS_PPA2MINOR(dsp->ds_ppa) && - dsp->ds_mh != NULL) { - statep->ds_dip = mac_devinfo_get(dsp->ds_mh); - rw_exit(&dsp->ds_lock); - return (MH_WALK_TERMINATE); - } - } else { + if (statep->ds_minor == dsp->ds_minor) { /* * Clone: a clone minor is unique. we can terminate the * walk if we find a matching stream -- even if we fail * to obtain the devinfo. */ - if (statep->ds_minor == dsp->ds_minor) { - if (dsp->ds_mh != NULL) - statep->ds_dip = mac_devinfo_get(dsp->ds_mh); - rw_exit(&dsp->ds_lock); - return (MH_WALK_TERMINATE); - } + if (dsp->ds_mh != NULL) + statep->ds_dip = mac_devinfo_get(dsp->ds_mh); + rw_exit(&dsp->ds_lock); + return (MH_WALK_TERMINATE); } rw_exit(&dsp->ds_lock); return (MH_WALK_CONTINUE); @@ -197,21 +197,24 @@ i_dld_str_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) static dev_info_t * dld_finddevinfo(dev_t dev) { + dev_info_t *dip; i_dld_str_state_t state; + if (getminor(dev) == 0) + return (NULL); + + /* + * See if it's a minor node of a link + */ + if ((dip = dls_finddevinfo(dev)) != NULL) + return (dip); + state.ds_minor = getminor(dev); state.ds_major = getmajor(dev); state.ds_dip = NULL; - if (state.ds_minor == 0) - return (NULL); - mod_hash_walk(str_hashp, i_dld_str_walker, &state); - if (state.ds_dip != NULL || state.ds_minor <= DLD_MAX_MINOR) - return (state.ds_dip); - - /* See if it's a minor node of a VLAN */ - return (dls_finddevinfo(dev)); + return (state.ds_dip); } /* @@ -233,10 +236,10 @@ dld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) } break; case DDI_INFO_DEVT2INSTANCE: - if (minor > 0 && minor <= DLD_MAX_MINOR) { + if (minor > 0 && minor <= DLS_MAX_MINOR) { *resp = (void *)(uintptr_t)DLS_MINOR2INST(minor); rc = DDI_SUCCESS; - } else if (minor > DLD_MAX_MINOR && + } else if (minor > DLS_MAX_MINOR && (devinfo = dld_finddevinfo((dev_t)arg)) != NULL) { *resp = (void *)(uintptr_t)ddi_get_instance(devinfo); rc = DDI_SUCCESS; @@ -286,12 +289,7 @@ dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) /* * Style 1 open */ - t_uscalar_t ppa; - - if ((err = dls_ppa_from_minor(minor, &ppa)) != 0) - goto failed; - - if ((err = dld_str_attach(dsp, ppa)) != 0) + if ((err = dld_str_attach(dsp, (t_uscalar_t)minor - 1)) != 0) goto failed; ASSERT(dsp->ds_dlstate == DL_UNBOUND); } else { @@ -323,28 +321,11 @@ dld_close(queue_t *rq) dld_str_t *dsp = rq->q_ptr; /* - * Wait until pending requests are processed. - */ - mutex_enter(&dsp->ds_thr_lock); - while (dsp->ds_pending_cnt > 0) - cv_wait(&dsp->ds_pending_cv, &dsp->ds_thr_lock); - mutex_exit(&dsp->ds_thr_lock); - - /* * Disable the queue srv(9e) routine. */ qprocsoff(rq); - /* - * At this point we can not be entered by any threads via STREAMS - * or the direct call interface, which is available only to IP. - * After the interface is unplumbed, IP wouldn't have any reference - * to this instance, and therefore we are now effectively single - * threaded and don't require any lock protection. Flush all - * pending packets which are sitting in the transmit queue. - */ - ASSERT(dsp->ds_thr == 0); - dld_tx_flush(dsp); + dld_finish_pending_task(dsp); /* * This stream was open to a provider node. Check to see @@ -369,41 +350,57 @@ dld_close(queue_t *rq) void dld_wput(queue_t *wq, mblk_t *mp) { - dld_str_t *dsp = (dld_str_t *)wq->q_ptr; - - DLD_ENTER(dsp); + dld_str_t *dsp = wq->q_ptr; switch (DB_TYPE(mp)) { - case M_DATA: - /* - * State is held constant by the DLD_ENTER done above - * until all sending threads are done. Mode can change - * due to ioctl, however locks must not be held across - * calls to putnext(), which can be called from here - * via dld_tx_single(). - */ - rw_enter(&dsp->ds_lock, RW_READER); - if (dsp->ds_dlstate != DL_IDLE || - dsp->ds_mode == DLD_UNITDATA) { - rw_exit(&dsp->ds_lock); + case M_DATA: { + dld_tx_t tx; + + DLD_TX_ENTER(dsp); + if ((tx = dsp->ds_tx) != NULL) + tx(dsp, mp); + else freemsg(mp); - } else if (dsp->ds_mode == DLD_FASTPATH) { - rw_exit(&dsp->ds_lock); - str_mdata_fastpath_put(dsp, mp); - } else if (dsp->ds_mode == DLD_RAW) { - rw_exit(&dsp->ds_lock); - str_mdata_raw_put(dsp, mp); - } + DLD_TX_EXIT(dsp); break; + } case M_PROTO: - case M_PCPROTO: - dld_proto(dsp, mp); + case M_PCPROTO: { + t_uscalar_t prim; + dld_tx_t tx; + + if (MBLKL(mp) < sizeof (t_uscalar_t)) { + freemsg(mp); + return; + } + + prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; + if (prim != DL_UNITDATA_REQ) { + /* Control path */ + dld_wput_nondata(dsp, mp); + break; + } + + /* Data path */ + DLD_TX_ENTER(dsp); + if ((tx = dsp->ds_unitdata_tx) != NULL) + tx(dsp, mp); + else + dlerrorack(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); + DLD_TX_EXIT(dsp); break; + } case M_IOCTL: - dld_ioc(dsp, mp); + case M_IOCDATA: + /* Control path */ + dld_wput_nondata(dsp, mp); break; case M_FLUSH: + /* + * Flush both the data messages and the control messages. + */ if (*mp->b_rptr & FLUSHW) { + dld_flush_nondata(dsp); dld_tx_flush(dsp); *mp->b_rptr &= ~FLUSHW; } @@ -418,8 +415,17 @@ dld_wput(queue_t *wq, mblk_t *mp) freemsg(mp); break; } +} - DLD_EXIT(dsp); +/* + * Called by GLDv3 control node to process the ioctls. It will start + * a taskq to allow the ioctl processing to block. This is a temporary + * solution, and will be replaced by a more graceful approach afterwards. + */ +void +dld_ioctl(queue_t *wq, mblk_t *mp) +{ + dld_wput_nondata(wq->q_ptr, mp); } /* @@ -428,10 +434,11 @@ dld_wput(queue_t *wq, mblk_t *mp) void dld_wsrv(queue_t *wq) { - mblk_t *mp; + mblk_t *mp, *head, *tail; dld_str_t *dsp = wq->q_ptr; + uint_t cnt, msgcnt; + timeout_id_t tid = 0; - DLD_ENTER(dsp); rw_enter(&dsp->ds_lock, RW_READER); /* * Grab all packets (chained via b_next) off our transmit queue @@ -453,10 +460,13 @@ dld_wsrv(queue_t *wq) ASSERT(dsp->ds_tx_msgcnt == 0); mutex_exit(&dsp->ds_tx_list_lock); rw_exit(&dsp->ds_lock); - DLD_EXIT(dsp); return; } + head = mp; + tail = dsp->ds_tx_list_tail; dsp->ds_tx_list_head = dsp->ds_tx_list_tail = NULL; + cnt = dsp->ds_tx_cnt; + msgcnt = dsp->ds_tx_msgcnt; dsp->ds_tx_cnt = dsp->ds_tx_msgcnt = 0; mutex_exit(&dsp->ds_tx_list_lock); @@ -466,7 +476,7 @@ dld_wsrv(queue_t *wq) * because regardless of the mode all transmit will end up in * dld_tx_single() where the packets may be queued. */ - ASSERT(DB_TYPE(mp) == M_DATA); + ASSERT((DB_TYPE(mp) == M_DATA) || (DB_TYPE(mp) == M_MULTIDATA)); if (dsp->ds_dlstate != DL_IDLE) { freemsgchain(mp); goto done; @@ -477,8 +487,27 @@ dld_wsrv(queue_t *wq) * send them all, re-queue the packet(s) at the beginning of * the transmit queue to avoid any re-ordering. */ - if ((mp = dls_tx(dsp->ds_dc, mp)) != NULL) - dld_tx_enqueue(dsp, mp, B_TRUE); + mp = dls_tx(dsp->ds_dc, mp); + if (mp == head) { + /* + * No message was sent out. Take the saved the queue depth + * as the input, so that dld_tx_enqueue() need not to + * calculate it again. + */ + dld_tx_enqueue(dsp, mp, tail, B_TRUE, msgcnt, cnt); + } else if (mp != NULL) { + /* + * Some but not all messages were sent out. dld_tx_enqueue() + * needs to start the timer to calculate the queue depth if + * timer has not been started. + * + * Note that a timer is used to calculate the queue depth + * to improve network performance, especially for TCP, in + * which case packets are sent without canput() being checked, + * and mostly end up in dld_tx_enqueue() under heavy load. + */ + dld_tx_enqueue(dsp, mp, tail, B_TRUE, 0, 0); + } done: /* @@ -492,11 +521,19 @@ done: dsp->ds_tx_flow_mp = getq(wq); ASSERT(dsp->ds_tx_flow_mp != NULL); dsp->ds_tx_qbusy = B_FALSE; + if ((tid = dsp->ds_tx_qdepth_tid) != 0) + dsp->ds_tx_qdepth_tid = 0; } mutex_exit(&dsp->ds_tx_list_lock); + /* + * Note that ds_tx_list_lock (which is acquired by the timeout + * callback routine) cannot be held across the call to untimeout(). + */ + if (tid != 0) + (void) untimeout(tid); + rw_exit(&dsp->ds_lock); - DLD_EXIT(dsp); } void @@ -566,6 +603,12 @@ dld_str_init(void) ASSERT(str_cachep != NULL); /* + * Create taskq to process DLPI requests. + */ + dld_disp_taskq = taskq_create("dld_disp_taskq", 1024, MINCLSYSPRI, 2, + INT_MAX, TASKQ_DYNAMIC | TASKQ_PREPOPULATE); + + /* * Create a hash table for maintaining dld_str_t's. * The ds_minor field (the clone minor number) of a dld_str_t * is used as a key for this hash table because this number is @@ -587,11 +630,9 @@ dld_str_fini(void) if (str_count != 0) return (EBUSY); - /* - * Check to see if there are any minor numbers still in use. - */ - if (minor_count != 0) - return (EBUSY); + ASSERT(dld_disp_taskq != NULL); + taskq_destroy(dld_disp_taskq); + dld_disp_taskq = NULL; /* * Destroy object cache. @@ -628,6 +669,7 @@ dld_str_create(queue_t *rq, uint_t type, major_t major, t_uscalar_t style) dsp->ds_type = type; dsp->ds_major = major; dsp->ds_style = style; + dsp->ds_tx = dsp->ds_unitdata_tx = NULL; /* * Initialize the queue pointers. @@ -649,6 +691,20 @@ dld_str_create(queue_t *rq, uint_t type, major_t major, t_uscalar_t style) return (dsp); } +void +dld_finish_pending_task(dld_str_t *dsp) +{ + /* + * Wait until the pending requests are processed by the worker thread. + */ + mutex_enter(&dsp->ds_disp_lock); + dsp->ds_closing = B_TRUE; + while (dsp->ds_tid != NULL) + cv_wait(&dsp->ds_disp_cv, &dsp->ds_disp_lock); + dsp->ds_closing = B_FALSE; + mutex_exit(&dsp->ds_disp_lock); +} + /* * Destroy a dld_str_t object. */ @@ -674,11 +730,14 @@ dld_str_destroy(dld_str_t *dsp) ASSERT(dsp->ds_tx_list_tail == NULL); ASSERT(dsp->ds_tx_cnt == 0); ASSERT(dsp->ds_tx_msgcnt == 0); + ASSERT(dsp->ds_tx_qdepth_tid == 0); ASSERT(!dsp->ds_tx_qbusy); - ASSERT(MUTEX_NOT_HELD(&dsp->ds_thr_lock)); - ASSERT(dsp->ds_thr == 0); - ASSERT(dsp->ds_pending_req == NULL); + ASSERT(MUTEX_NOT_HELD(&dsp->ds_disp_lock)); + ASSERT(dsp->ds_pending_head == NULL); + ASSERT(dsp->ds_pending_tail == NULL); + ASSERT(dsp->ds_tx == NULL); + ASSERT(dsp->ds_unitdata_tx == NULL); /* * Reinitialize all the flags. @@ -720,22 +779,20 @@ str_constructor(void *buf, void *cdrarg, int kmflags) /* * Allocate a new minor number. */ - atomic_add_32(&minor_count, 1); - if ((dsp->ds_minor = dls_minor_hold(kmflags == KM_SLEEP)) == 0) { - atomic_add_32(&minor_count, -1); + if ((dsp->ds_minor = mac_minor_hold(kmflags == KM_SLEEP)) == 0) return (-1); - } /* * Initialize the DLPI state machine. */ dsp->ds_dlstate = DL_UNATTACHED; - dsp->ds_ppa = (t_uscalar_t)-1; - mutex_init(&dsp->ds_thr_lock, NULL, MUTEX_DRIVER, NULL); rw_init(&dsp->ds_lock, NULL, RW_DRIVER, NULL); mutex_init(&dsp->ds_tx_list_lock, NULL, MUTEX_DRIVER, NULL); - cv_init(&dsp->ds_pending_cv, NULL, CV_DRIVER, NULL); + mutex_init(&dsp->ds_disp_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&dsp->ds_disp_cv, NULL, CV_DRIVER, NULL); + mutex_init(&dsp->ds_tx_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&dsp->ds_tx_cv, NULL, CV_DRIVER, NULL); return (0); } @@ -759,6 +816,10 @@ str_destructor(void *buf, void *cdrarg) */ ASSERT(dsp->ds_mh == NULL); ASSERT(dsp->ds_dc == NULL); + ASSERT(dsp->ds_tx == NULL); + ASSERT(dsp->ds_unitdata_tx == NULL); + ASSERT(dsp->ds_intx_cnt == 0); + ASSERT(dsp->ds_detaching == B_FALSE); /* * Make sure enabled notifications are cleared. @@ -773,8 +834,7 @@ str_destructor(void *buf, void *cdrarg) /* * Release the minor number. */ - dls_minor_rele(dsp->ds_minor); - atomic_add_32(&minor_count, -1); + mac_minor_rele(dsp->ds_minor); ASSERT(!RW_LOCK_HELD(&dsp->ds_lock)); rw_destroy(&dsp->ds_lock); @@ -782,27 +842,26 @@ str_destructor(void *buf, void *cdrarg) ASSERT(MUTEX_NOT_HELD(&dsp->ds_tx_list_lock)); mutex_destroy(&dsp->ds_tx_list_lock); ASSERT(dsp->ds_tx_flow_mp == NULL); + ASSERT(dsp->ds_pending_head == NULL); + ASSERT(dsp->ds_pending_tail == NULL); + ASSERT(!dsp->ds_closing); + + ASSERT(MUTEX_NOT_HELD(&dsp->ds_disp_lock)); + mutex_destroy(&dsp->ds_disp_lock); + cv_destroy(&dsp->ds_disp_cv); - ASSERT(MUTEX_NOT_HELD(&dsp->ds_thr_lock)); - mutex_destroy(&dsp->ds_thr_lock); - ASSERT(dsp->ds_pending_req == NULL); - ASSERT(dsp->ds_pending_op == NULL); - ASSERT(dsp->ds_pending_cnt == 0); - cv_destroy(&dsp->ds_pending_cv); + ASSERT(MUTEX_NOT_HELD(&dsp->ds_tx_lock)); + mutex_destroy(&dsp->ds_tx_lock); + cv_destroy(&dsp->ds_tx_cv); } -/* - * M_DATA put. Note that mp is a single message, not a chained message. - */ void dld_tx_single(dld_str_t *dsp, mblk_t *mp) { /* - * This function can be called from within dld or from an upper - * layer protocol (currently only tcp). If we are in the busy - * mode enqueue the packet(s) and return. Otherwise hand them - * over to the MAC driver for transmission; any remaining one(s) - * which didn't get sent will be queued. + * If we are busy enqueue the packet and return. + * Otherwise hand them over to the MAC driver for transmission. + * If the message didn't get sent it will be queued. * * Note here that we don't grab the list lock prior to checking * the busy flag. This is okay, because a missed transition @@ -812,13 +871,14 @@ dld_tx_single(dld_str_t *dsp, mblk_t *mp) * thread to run; the flag is only cleared by the service thread * when there is no more packet to be transmitted. */ - if (dsp->ds_tx_qbusy || (mp = dls_tx(dsp->ds_dc, mp)) != NULL) - dld_tx_enqueue(dsp, mp, B_FALSE); + + if (dsp->ds_tx_qbusy || ((mp = dls_tx(dsp->ds_dc, mp)) != NULL)) + dld_tx_enqueue(dsp, mp, mp, B_FALSE, 1, mp_getsize(mp)); } /* * Update the priority bits and VID (may need to insert tag if mp points - * to an untagged packet. + * to an untagged packet). * If vid is VLAN_ID_NONE, use the VID encoded in the packet. */ static mblk_t * @@ -881,7 +941,7 @@ i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid) /* * Free the original message if it's now empty. Link the - * rest of messages to the header message. + * rest of the messages to the header message. */ if (MBLKL(mp) == 0) { hmp->b_cont = mp->b_cont; @@ -901,7 +961,11 @@ i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid) } /* - * M_DATA put (IP fast-path mode) + * M_DATA put + * + * The poll callback function for DLS clients which are not in the per-stream + * mode. This function is called from an upper layer protocol (currently only + * tcp and udp). */ void str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) @@ -934,9 +998,9 @@ discard: } /* - * M_DATA put (DLIOCRAW mode) + * M_DATA put (DLIOCRAW mode). */ -static void +void str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) { boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); @@ -1032,29 +1096,50 @@ discard: int dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa) { - int err; - const char *drvname; - char name[MAXNAMELEN]; - dls_channel_t dc; - uint_t addr_length; + dev_t dev; + int err; + const char *drvname; + dls_channel_t dc; + uint_t addr_length; + boolean_t qassociated = B_FALSE; ASSERT(dsp->ds_dc == NULL); if ((drvname = ddi_major_to_name(dsp->ds_major)) == NULL) return (EINVAL); - (void) snprintf(name, MAXNAMELEN, "%s%u", drvname, ppa); - - if (strcmp(drvname, "aggr") != 0 && strcmp(drvname, "vnic") != 0 && - qassociate(dsp->ds_wq, DLS_PPA2INST(ppa)) != 0) - return (EINVAL); + /* + * /dev node access. This will still be supported for backward + * compatibility reason. + */ + if ((dsp->ds_style == DL_STYLE2) && (strcmp(drvname, "aggr") != 0) && + (strcmp(drvname, "vnic") != 0)) { + if (qassociate(dsp->ds_wq, DLS_PPA2INST(ppa)) != 0) + return (EINVAL); + qassociated = B_TRUE; + } /* * Open a channel. */ - if ((err = dls_open(name, &dc)) != 0) { - (void) qassociate(dsp->ds_wq, -1); - return (err); + if (dsp->ds_style == DL_STYLE2 && ppa > DLS_MAX_PPA) { + /* + * style-2 VLAN open, this is a /dev VLAN ppa open + * which might result in a newly created dls_vlan_t. + */ + err = dls_open_style2_vlan(dsp->ds_major, ppa, &dc); + if (err != 0) { + if (qassociated) + (void) qassociate(dsp->ds_wq, -1); + return (err); + } + } else { + dev = makedevice(dsp->ds_major, (minor_t)ppa + 1); + if ((err = dls_open_by_dev(dev, &dc)) != 0) { + if (qassociated) + (void) qassociate(dsp->ds_wq, -1); + return (err); + } } /* @@ -1085,7 +1170,6 @@ dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa) */ dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, (void *)dsp); - dsp->ds_ppa = ppa; dsp->ds_dc = dc; dsp->ds_dlstate = DL_UNBOUND; @@ -1099,8 +1183,6 @@ dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa) void dld_str_detach(dld_str_t *dsp) { - ASSERT(dsp->ds_thr == 0); - /* * Remove the notify function. */ @@ -1114,21 +1196,25 @@ dld_str_detach(dld_str_t *dsp) dld_capabilities_disable(dsp); dsp->ds_promisc = 0; + DLD_TX_QUIESCE(dsp); + + /* + * Flush all pending packets which are sitting in the transmit queue. + */ + dld_tx_flush(dsp); + /* * Clear LSO flags. */ dsp->ds_lso = B_FALSE; dsp->ds_lso_max = 0; - /* - * Close the channel. - */ dls_close(dsp->ds_dc); - dsp->ds_ppa = (t_uscalar_t)-1; dsp->ds_dc = NULL; dsp->ds_mh = NULL; - (void) qassociate(dsp->ds_wq, -1); + if (dsp->ds_style == DL_STYLE2) + (void) qassociate(dsp->ds_wq, -1); /* * Re-initialize the DLPI state machine. @@ -1775,53 +1861,127 @@ str_notify(void *arg, mac_notify_type_t type) str_notify_fastpath_flush(dsp); break; + case MAC_NOTE_MARGIN: + break; default: ASSERT(B_FALSE); break; } } +static inline uint_t +mp_getsize(mblk_t *mp) +{ + ASSERT(DB_TYPE(mp) == M_DATA); + return ((mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp)); +} + /* - * Enqueue one or more messages to the transmit queue. - * Caller specifies the insertion position (head/tail). + * Calculate the dld queue depth, free the messages that exceed the threshold. */ -void -dld_tx_enqueue(dld_str_t *dsp, mblk_t *mp, boolean_t head_insert) +static void +dld_tx_qdepth_timer(void *arg) { - mblk_t *tail; - queue_t *q = dsp->ds_wq; - uint_t cnt, msgcnt; - uint_t tot_cnt, tot_msgcnt; + dld_str_t *dsp = (dld_str_t *)arg; + mblk_t *prev, *mp; + uint_t cnt, msgcnt, size; + + mutex_enter(&dsp->ds_tx_list_lock); - ASSERT(DB_TYPE(mp) == M_DATA); /* Calculate total size and count of the packet(s) */ - for (tail = mp, cnt = msgdsize(mp), msgcnt = 1; - tail->b_next != NULL; tail = tail->b_next) { - ASSERT(DB_TYPE(tail->b_next) == M_DATA); - cnt += msgdsize(tail->b_next); + cnt = msgcnt = 0; + for (prev = NULL, mp = dsp->ds_tx_list_head; mp != NULL; + prev = mp, mp = mp->b_next) { + size = mp_getsize(mp); + cnt += size; msgcnt++; + if (cnt >= dld_max_q_count || msgcnt >= dld_max_q_count) { + ASSERT(dsp->ds_tx_qbusy); + dsp->ds_tx_list_tail = prev; + if (prev == NULL) + dsp->ds_tx_list_head = NULL; + else + prev->b_next = NULL; + freemsgchain(mp); + cnt -= size; + msgcnt--; + break; + } } + dsp->ds_tx_cnt = cnt; + dsp->ds_tx_msgcnt = msgcnt; + dsp->ds_tx_qdepth_tid = 0; + mutex_exit(&dsp->ds_tx_list_lock); +} + +/* + * Enqueue one or more messages on the transmit queue. Caller specifies: + * - the insertion position (head/tail). + * - the message count and the total message size of messages to be queued + * if they are known to the caller; or 0 if they are not known. + * + * If the caller does not know the message size information, this usually + * means that dld_wsrv() managed to send some but not all of the queued + * messages. For performance reasons, we do not calculate the queue depth + * every time. Instead, a timer is started to calculate the queue depth + * every 1 second (can be changed by tx_qdepth_interval). + */ +static void +dld_tx_enqueue(dld_str_t *dsp, mblk_t *mp, mblk_t *tail, boolean_t head_insert, + uint_t msgcnt, uint_t cnt) +{ + queue_t *q = dsp->ds_wq; + uint_t tot_cnt, tot_msgcnt; + mblk_t *next; mutex_enter(&dsp->ds_tx_list_lock); + + /* + * Simply enqueue the message and calculate the queue depth via + * timer if: + * + * - the current queue depth is incorrect, and the timer is already + * started; or + * + * - the given message size is unknown and it is allowed to start the + * timer; + */ + if ((dsp->ds_tx_qdepth_tid != 0) || + (msgcnt == 0 && tx_qdepth_interval != 0)) { + goto enqueue; + } + /* + * The timer is not allowed, so calculate the message size now. + */ + if (msgcnt == 0) { + for (next = mp; next != NULL; next = next->b_next) { + cnt += mp_getsize(next); + msgcnt++; + } + } + + /* + * Grow the queue depth using the input messesge size. + * * If the queue depth would exceed the allowed threshold, drop * new packet(s) and drain those already in the queue. */ tot_cnt = dsp->ds_tx_cnt + cnt; tot_msgcnt = dsp->ds_tx_msgcnt + msgcnt; - if (!head_insert && - (tot_cnt >= dld_max_q_count || tot_msgcnt >= dld_max_q_count)) { + if (!head_insert && (tot_cnt >= dld_max_q_count || + tot_msgcnt >= dld_max_q_count)) { ASSERT(dsp->ds_tx_qbusy); mutex_exit(&dsp->ds_tx_list_lock); freemsgchain(mp); goto done; } - /* Update the queue size parameters */ dsp->ds_tx_cnt = tot_cnt; dsp->ds_tx_msgcnt = tot_msgcnt; +enqueue: /* * If the transmit queue is currently empty and we are * about to deposit the packet(s) there, switch mode to @@ -1848,6 +2008,17 @@ dld_tx_enqueue(dld_str_t *dsp, mblk_t *mp, boolean_t head_insert) dsp->ds_tx_list_tail = tail; dsp->ds_tx_list_head = mp; } + + if (msgcnt == 0 && dsp->ds_tx_qdepth_tid == 0 && + tx_qdepth_interval != 0) { + /* + * The message size is not given so that we need to start + * the timer to calculate the queue depth. + */ + dsp->ds_tx_qdepth_tid = timeout(dld_tx_qdepth_timer, dsp, + drv_usectohz(tx_qdepth_interval)); + ASSERT(dsp->ds_tx_qdepth_tid != NULL); + } mutex_exit(&dsp->ds_tx_list_lock); done: /* Schedule service thread to drain the transmit queue */ @@ -1858,6 +2029,8 @@ done: void dld_tx_flush(dld_str_t *dsp) { + timeout_id_t tid = 0; + mutex_enter(&dsp->ds_tx_list_lock); if (dsp->ds_tx_list_head != NULL) { freemsgchain(dsp->ds_tx_list_head); @@ -1868,34 +2041,156 @@ dld_tx_flush(dld_str_t *dsp) ASSERT(dsp->ds_tx_flow_mp != NULL); dsp->ds_tx_qbusy = B_FALSE; } + if ((tid = dsp->ds_tx_qdepth_tid) != 0) + dsp->ds_tx_qdepth_tid = 0; } mutex_exit(&dsp->ds_tx_list_lock); + + /* + * Note that ds_tx_list_lock (which is acquired by the timeout + * callback routine) cannot be held across the call to untimeout(). + */ + if (tid != 0) + (void) untimeout(tid); } /* - * Process an M_IOCTL message. + * Process a non-data message. */ static void -dld_ioc(dld_str_t *dsp, mblk_t *mp) +dld_wput_nondata(dld_str_t *dsp, mblk_t *mp) { - uint_t cmd; + ASSERT((dsp->ds_type == DLD_DLPI && dsp->ds_ioctl == NULL) || + (dsp->ds_type == DLD_CONTROL && dsp->ds_ioctl != NULL)); - cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; - ASSERT(dsp->ds_type == DLD_DLPI); + mutex_enter(&dsp->ds_disp_lock); - switch (cmd) { - case DLIOCNATIVE: - ioc_native(dsp, mp); - break; - case DLIOCRAW: - ioc_raw(dsp, mp); + /* + * The processing of the message might block. Enqueue the + * message for later processing. + */ + if (dsp->ds_pending_head == NULL) { + dsp->ds_pending_head = dsp->ds_pending_tail = mp; + } else { + dsp->ds_pending_tail->b_next = mp; + dsp->ds_pending_tail = mp; + } + + /* + * If there is no task pending, kick off the task. + */ + if (dsp->ds_tid == NULL) { + dsp->ds_tid = taskq_dispatch(dld_disp_taskq, + dld_wput_nondata_task, dsp, TQ_SLEEP); + ASSERT(dsp->ds_tid != NULL); + } + mutex_exit(&dsp->ds_disp_lock); +} + +/* + * The worker thread which processes non-data messages. Note we only process + * one message at one time in order to be able to "flush" the queued message + * and serialize the processing. + */ +static void +dld_wput_nondata_task(void *arg) +{ + dld_str_t *dsp = (dld_str_t *)arg; + mblk_t *mp; + + mutex_enter(&dsp->ds_disp_lock); + ASSERT(dsp->ds_pending_head != NULL); + ASSERT(dsp->ds_tid != NULL); + + if (dsp->ds_closing) + goto closing; + + mp = dsp->ds_pending_head; + if ((dsp->ds_pending_head = mp->b_next) == NULL) + dsp->ds_pending_tail = NULL; + mp->b_next = NULL; + + mutex_exit(&dsp->ds_disp_lock); + + switch (DB_TYPE(mp)) { + case M_PROTO: + case M_PCPROTO: + ASSERT(dsp->ds_type == DLD_DLPI); + dld_wput_proto_nondata(dsp, mp); break; - case DLIOCHDRINFO: - ioc_fast(dsp, mp); + case M_IOCTL: { + uint_t cmd; + + if (dsp->ds_type == DLD_CONTROL) { + ASSERT(dsp->ds_ioctl != NULL); + dsp->ds_ioctl(dsp->ds_wq, mp); + break; + } + + cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; + + switch (cmd) { + case DLIOCNATIVE: + ioc_native(dsp, mp); + break; + case DLIOCMARGININFO: + ioc_margin(dsp, mp); + break; + case DLIOCRAW: + ioc_raw(dsp, mp); + break; + case DLIOCHDRINFO: + ioc_fast(dsp, mp); + break; + default: + ioc(dsp, mp); + break; + } break; - default: + } + case M_IOCDATA: + ASSERT(dsp->ds_type == DLD_DLPI); ioc(dsp, mp); + break; } + + mutex_enter(&dsp->ds_disp_lock); + + if (dsp->ds_closing) + goto closing; + + if (dsp->ds_pending_head != NULL) { + dsp->ds_tid = taskq_dispatch(dld_disp_taskq, + dld_wput_nondata_task, dsp, TQ_SLEEP); + ASSERT(dsp->ds_tid != NULL); + } else { + dsp->ds_tid = NULL; + } + mutex_exit(&dsp->ds_disp_lock); + return; + + /* + * If the stream is closing, flush all queued messages and inform + * the stream once it is done. + */ +closing: + freemsgchain(dsp->ds_pending_head); + dsp->ds_pending_head = dsp->ds_pending_tail = NULL; + dsp->ds_tid = NULL; + cv_signal(&dsp->ds_disp_cv); + mutex_exit(&dsp->ds_disp_lock); +} + +/* + * Flush queued non-data messages. + */ +static void +dld_flush_nondata(dld_str_t *dsp) +{ + mutex_enter(&dsp->ds_disp_lock); + freemsgchain(dsp->ds_pending_head); + dsp->ds_pending_head = dsp->ds_pending_tail = NULL; + mutex_exit(&dsp->ds_disp_lock); } /* @@ -1925,6 +2220,32 @@ ioc_native(dld_str_t *dsp, mblk_t *mp) } /* + * DLIOCMARGININFO + */ +static void +ioc_margin(dld_str_t *dsp, mblk_t *mp) +{ + queue_t *q = dsp->ds_wq; + uint32_t margin; + int err; + + if (dsp->ds_dlstate == DL_UNATTACHED) { + err = EINVAL; + goto failed; + } + if ((err = miocpullup(mp, sizeof (uint32_t))) != 0) + goto failed; + + mac_margin_get(dsp->ds_mh, &margin); + *((uint32_t *)mp->b_cont->b_rptr) = margin; + miocack(q, mp, sizeof (uint32_t), 0); + return; + +failed: + miocnak(q, mp, 0, err); +} + +/* * DLIOCRAW */ static void @@ -1932,25 +2253,20 @@ ioc_raw(dld_str_t *dsp, mblk_t *mp) { queue_t *q = dsp->ds_wq; - rw_enter(&dsp->ds_lock, RW_WRITER); if (dsp->ds_polling || dsp->ds_soft_ring) { - rw_exit(&dsp->ds_lock); miocnak(q, mp, 0, EPROTO); return; } - if (dsp->ds_mode != DLD_RAW && dsp->ds_dlstate == DL_IDLE) { + rw_enter(&dsp->ds_lock, RW_WRITER); + if ((dsp->ds_mode != DLD_RAW) && (dsp->ds_dlstate == DL_IDLE)) { /* * Set the receive callback. */ - dls_rx_set(dsp->ds_dc, dld_str_rx_raw, (void *)dsp); + dls_rx_set(dsp->ds_dc, dld_str_rx_raw, dsp); + dsp->ds_tx = str_mdata_raw_put; } - - /* - * Note that raw mode is enabled. - */ dsp->ds_mode = DLD_RAW; - rw_exit(&dsp->ds_lock); miocack(q, mp, 0, 0); } @@ -1971,7 +2287,6 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp) uint_t addr_length; queue_t *q = dsp->ds_wq; int err; - dls_channel_t dc; if (dld_opt & DLD_OPT_NO_FASTPATH) { err = ENOTSUP; @@ -2003,62 +2318,41 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp) goto failed; } - rw_enter(&dsp->ds_lock, RW_READER); + /* + * We don't need to hold any locks to access ds_dlstate, because + * control message prossessing (which updates this field) is + * serialized. + */ if (dsp->ds_dlstate != DL_IDLE) { - rw_exit(&dsp->ds_lock); err = ENOTSUP; goto failed; } addr_length = dsp->ds_mip->mi_addr_length; if (len != addr_length + sizeof (uint16_t)) { - rw_exit(&dsp->ds_lock); err = EINVAL; goto failed; } addr = nmp->b_rptr + off; sap = *(uint16_t *)(nmp->b_rptr + off + addr_length); - dc = dsp->ds_dc; - if ((hmp = dls_header(dc, addr, sap, 0, NULL)) == NULL) { - rw_exit(&dsp->ds_lock); + if ((hmp = dls_header(dsp->ds_dc, addr, sap, 0, NULL)) == NULL) { err = ENOMEM; goto failed; } - /* - * This is a performance optimization. We originally entered - * as reader and only become writer upon transitioning into - * the DLD_FASTPATH mode for the first time. Otherwise we - * stay as reader and return the fast-path header to IP. - */ + rw_enter(&dsp->ds_lock, RW_WRITER); + ASSERT(dsp->ds_dlstate == DL_IDLE); if (dsp->ds_mode != DLD_FASTPATH) { - if (!rw_tryupgrade(&dsp->ds_lock)) { - rw_exit(&dsp->ds_lock); - rw_enter(&dsp->ds_lock, RW_WRITER); - - /* - * State may have changed before we re-acquired - * the writer lock in case the upgrade failed. - */ - if (dsp->ds_dlstate != DL_IDLE) { - rw_exit(&dsp->ds_lock); - err = ENOTSUP; - goto failed; - } - } - - /* - * Set the receive callback (unless polling is enabled). - */ - if (!dsp->ds_polling && !dsp->ds_soft_ring) - dls_rx_set(dc, dld_str_rx_fastpath, (void *)dsp); - /* - * Note that fast-path mode is enabled. + * Set the receive callback (unless polling or + * soft-ring is enabled). */ dsp->ds_mode = DLD_FASTPATH; + if (!dsp->ds_polling && !dsp->ds_soft_ring) + dls_rx_set(dsp->ds_dc, dld_str_rx_fastpath, dsp); + dsp->ds_tx = str_mdata_fastpath_put; } rw_exit(&dsp->ds_lock); @@ -2071,23 +2365,17 @@ failed: miocnak(q, mp, 0, err); } -/* - * Catch-all handler. - */ static void ioc(dld_str_t *dsp, mblk_t *mp) { queue_t *q = dsp->ds_wq; mac_handle_t mh; - rw_enter(&dsp->ds_lock, RW_READER); if (dsp->ds_dlstate == DL_UNATTACHED) { - rw_exit(&dsp->ds_lock); miocnak(q, mp, 0, EINVAL); return; } mh = dsp->ds_mh; ASSERT(mh != NULL); - rw_exit(&dsp->ds_lock); mac_ioctl(mh, q, mp); } diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c index 0e9089dff0..2002e994bf 100644 --- a/usr/src/uts/common/io/dls/dls.c +++ b/usr/src/uts/common/io/dls/dls.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 <sys/strsun.h> #include <sys/sysmacros.h> #include <sys/atomic.h> +#include <sys/stat.h> #include <sys/dlpi.h> #include <sys/vlan.h> #include <sys/ethernet.h> @@ -53,6 +54,8 @@ struct dls_kstats dls_kstat = { "soft_ring_pkt_drop", KSTAT_DATA_UINT32 }, }; +static int dls_open(dls_vlan_t *, dls_dl_handle_t ddh, dls_channel_t *); + /* * Private functions. */ @@ -78,6 +81,7 @@ i_dls_destructor(void *buf, void *arg) ASSERT(dip->di_dvp == NULL); ASSERT(dip->di_mnh == NULL); ASSERT(dip->di_dmap == NULL); + ASSERT(!dip->di_local); ASSERT(!dip->di_bound); ASSERT(dip->di_rx == NULL); ASSERT(dip->di_txinfo == NULL); @@ -164,47 +168,109 @@ dls_fini(void) } /* - * Client function. + * Client functions. */ +/* + * /dev node style-2 VLAN PPA access. This might result in a newly created + * dls_vlan_t. Note that this dls_vlan_t is different from others, in that + * this VLAN might not have a link name that is managed by dlmgmtd (we cannot + * use its VLAN ppa hack name as it might conflict with a vanity name). + */ int -dls_create(const char *linkname, const char *macname) +dls_open_style2_vlan(major_t major, uint_t ppa, dls_channel_t *dcp) { - return (dls_vlan_create(linkname, macname, 0)); + dev_t dev = makedevice(major, DLS_PPA2INST(ppa) + 1); + uint_t vid = DLS_PPA2VID(ppa); + dls_vlan_t *lndvp, *dvp; + int err; + + /* + * First find the dls_vlan_t this VLAN is created on. This must be + * a GLDv3 driver based device. + */ + if ((err = dls_vlan_hold_by_dev(dev, &lndvp)) != 0) + return (err); + + if (vid > VLAN_ID_MAX) + return (ENOENT); + + err = dls_vlan_hold(lndvp->dv_dlp->dl_name, vid, &dvp, B_FALSE, B_TRUE); + if (err != 0) + goto done; + + if ((err = dls_open(dvp, NULL, dcp)) != 0) + dls_vlan_rele(dvp); + +done: + dls_vlan_rele(lndvp); + return (err); } int -dls_destroy(const char *name) +dls_open_by_dev(dev_t dev, dls_channel_t *dcp) { - return (dls_vlan_destroy(name)); + dls_dl_handle_t ddh; + dls_vlan_t *dvp; + int err; + + /* + * Get a reference to the given dls_vlan_t. + */ + if ((err = dls_devnet_open_by_dev(dev, &dvp, &ddh)) != 0) + return (err); + + if ((err = dls_open(dvp, ddh, dcp)) != 0) { + if (ddh != NULL) + dls_devnet_close(ddh); + else + dls_vlan_rele(dvp); + } + + return (err); } -int -dls_open(const char *name, dls_channel_t *dcp) +static int +dls_open(dls_vlan_t *dvp, dls_dl_handle_t ddh, dls_channel_t *dcp) { dls_impl_t *dip; - dls_vlan_t *dvp; dls_link_t *dlp; int err; + zoneid_t zid = getzoneid(); + boolean_t local; /* - * Get a reference to the named dls_vlan_t. - * Tagged vlans get created automatically. + * Check whether this client belongs to the zone of this dvp. Note that + * a global zone client is allowed to open a local zone dvp. */ - if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) + mutex_enter(&dvp->dv_lock); + if (zid != GLOBAL_ZONEID && dvp->dv_zid != zid) { + mutex_exit(&dvp->dv_lock); + return (ENOENT); + } + local = (zid == dvp->dv_zid); + dvp->dv_zone_ref += (local ? 1 : 0); + mutex_exit(&dvp->dv_lock); + + dlp = dvp->dv_dlp; + if ((err = mac_start(dlp->dl_mh)) != 0) { + mutex_enter(&dvp->dv_lock); + dvp->dv_zone_ref -= (local ? 1 : 0); + mutex_exit(&dvp->dv_lock); return (err); + } /* * Allocate a new dls_impl_t. */ dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); dip->di_dvp = dvp; + dip->di_ddh = ddh; /* * Cache a copy of the MAC interface handle, a pointer to the * immutable MAC info and a copy of the current MAC address. */ - dlp = dvp->dv_dlp; dip->di_mh = dlp->dl_mh; dip->di_mip = dlp->dl_mip; @@ -216,9 +282,11 @@ dls_open(const char *name, dls_channel_t *dcp) dip->di_txinfo = mac_tx_get(dip->di_mh); /* - * Add a notification function so that we get updates from the MAC. + * Add a notification function so that we get updates from + * the MAC. */ - dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); + dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, + (void *)dip); /* * Bump the kmem_cache count to make sure it is not prematurely @@ -226,16 +294,7 @@ dls_open(const char *name, dls_channel_t *dcp) */ atomic_add_32(&i_dls_impl_count, 1); - /* - * Set the di_zid to the zone id of current zone - */ - dip->di_zid = getzoneid(); - - /* - * Add this dls_impl_t to the list of the "opened stream" - * list of the corresponding dls_vlan_t - */ - dls_vlan_add_impl(dvp, dip); + dip->di_local = local; /* * Hand back a reference to the dls_impl_t. @@ -248,15 +307,22 @@ void dls_close(dls_channel_t dc) { dls_impl_t *dip = (dls_impl_t *)dc; - dls_vlan_t *dvp; - dls_link_t *dlp; + dls_vlan_t *dvp = dip->di_dvp; + dls_link_t *dlp = dvp->dv_dlp; dls_multicst_addr_t *p; dls_multicst_addr_t *nextp; + dls_dl_handle_t ddh = dip->di_ddh; + + if (dip->di_local) { + mutex_enter(&dvp->dv_lock); + dvp->dv_zone_ref--; + mutex_exit(&dvp->dv_lock); + } + dip->di_local = B_FALSE; dls_active_clear(dc); rw_enter(&(dip->di_lock), RW_WRITER); - /* * Remove the notify function. */ @@ -266,9 +332,6 @@ dls_close(dls_channel_t dc) /* * If the dls_impl_t is bound then unbind it. */ - dvp = dip->di_dvp; - dlp = dvp->dv_dlp; - if (dip->di_bound) { rw_exit(&(dip->di_lock)); dls_link_remove(dlp, dip); @@ -276,11 +339,9 @@ dls_close(dls_channel_t dc) dip->di_bound = B_FALSE; } - dip->di_rx = NULL; - dip->di_rx_arg = NULL; - /* - * Walk the list of multicast addresses, disabling each at the MAC. + * Walk the list of multicast addresses, disabling each at + * the MAC. */ for (p = dip->di_dmap; p != NULL; p = nextp) { (void) mac_multicst_remove(dip->di_mh, p->dma_addr); @@ -289,23 +350,19 @@ dls_close(dls_channel_t dc) } dip->di_dmap = NULL; - /* - * Remove this dls_impl_t from the list of the "open streams" - * list of the corresponding dls_vlan_t - */ - dls_vlan_remove_impl(dvp, dip); - + dip->di_rx = NULL; + dip->di_rx_arg = NULL; rw_exit(&(dip->di_lock)); /* * If the MAC has been set in promiscuous mode then disable it. */ (void) dls_promisc(dc, 0); + dip->di_txinfo = NULL; /* * Free the dls_impl_t back to the cache. */ - dip->di_dvp = NULL; dip->di_txinfo = NULL; if (dip->di_soft_ring_list != NULL) { @@ -315,20 +372,27 @@ dls_close(dls_channel_t dc) } dip->di_soft_ring_size = 0; - kmem_cache_free(i_dls_impl_cachep, dip); - /* * Decrement the reference count to allow the cache to be destroyed * if there are no more dls_impl_t. */ atomic_add_32(&i_dls_impl_count, -1); + dip->di_dvp = NULL; + + kmem_cache_free(i_dls_impl_cachep, dip); + + mac_stop(dvp->dv_dlp->dl_mh); + /* * Release our reference to the dls_vlan_t allowing that to be * destroyed if there are no more dls_impl_t. An unreferenced tagged - * vlan gets destroyed automatically. + * (non-persistent) vlan gets destroyed automatically. */ - dls_vlan_rele(dvp); + if (ddh != NULL) + dls_devnet_close(ddh); + else + dls_vlan_rele(dvp); } mac_handle_t @@ -492,6 +556,7 @@ multi: err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); if (err != 0) goto done; + dip->di_promisc |= DLS_PROMISC_PHYS; dlp->dl_npromisc++; } @@ -500,6 +565,7 @@ multi: err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); if (err != 0) goto done; + dip->di_promisc &= ~DLS_PROMISC_PHYS; dlp->dl_npromisc--; } @@ -753,6 +819,13 @@ dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, if (dip->di_promisc & DLS_PROMISC_PHYS) goto accept; + /* + * For non-promiscs-phys streams, filter out the packets looped back + * from the underlying driver because of promiscuous setting. + */ + if (mhip->mhi_prom_looped) + goto refuse; + switch (mhip->mhi_dsttype) { case MAC_ADDRTYPE_UNICAST: /* @@ -839,6 +912,33 @@ accept: } boolean_t +dls_mac_active_set(dls_link_t *dlp) +{ + mutex_enter(&dlp->dl_lock); + + /* + * If this is the first active client on this link, notify + * the mac that we're becoming an active client. + */ + if (dlp->dl_nactive == 0 && !mac_active_shareable_set(dlp->dl_mh)) { + mutex_exit(&dlp->dl_lock); + return (B_FALSE); + } + dlp->dl_nactive++; + mutex_exit(&dlp->dl_lock); + return (B_TRUE); +} + +void +dls_mac_active_clear(dls_link_t *dlp) +{ + mutex_enter(&dlp->dl_lock); + if (--dlp->dl_nactive == 0) + mac_active_clear(dlp->dl_mh); + mutex_exit(&dlp->dl_lock); +} + +boolean_t dls_active_set(dls_channel_t dc) { dls_impl_t *dip = (dls_impl_t *)dc; @@ -852,18 +952,11 @@ dls_active_set(dls_channel_t dc) return (B_TRUE); } - /* - * If this is the first active client on this link, notify - * the mac that we're becoming an active client. - */ - if (dlp->dl_nactive == 0 && !mac_active_shareable_set(dlp->dl_mh)) { + if (!dls_mac_active_set(dlp)) { rw_exit(&dip->di_lock); return (B_FALSE); } dip->di_active = B_TRUE; - mutex_enter(&dlp->dl_lock); - dlp->dl_nactive++; - mutex_exit(&dlp->dl_lock); rw_exit(&dip->di_lock); return (B_TRUE); } @@ -880,22 +973,8 @@ dls_active_clear(dls_channel_t dc) goto out; dip->di_active = B_FALSE; - mutex_enter(&dlp->dl_lock); - if (--dlp->dl_nactive == 0) - mac_active_clear(dip->di_mh); - mutex_exit(&dlp->dl_lock); + dls_mac_active_clear(dlp); + out: rw_exit(&dip->di_lock); } - -dev_info_t * -dls_finddevinfo(dev_t dev) -{ - return (dls_vlan_finddevinfo(dev)); -} - -int -dls_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) -{ - return (dls_vlan_ppa_from_minor(minor, ppa)); -} diff --git a/usr/src/uts/common/io/dls/dls_link.c b/usr/src/uts/common/io/dls/dls_link.c index e342c95955..759fb97f0a 100644 --- a/usr/src/uts/common/io/dls/dls_link.c +++ b/usr/src/uts/common/io/dls/dls_link.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. */ @@ -90,7 +90,7 @@ i_dls_link_constructor(void *buf, void *arg, int kmflag) bzero(buf, sizeof (dls_link_t)); - (void) sprintf(name, "dls_link_t_%p_hash", buf); + (void) snprintf(name, MAXNAMELEN, "dls_link_t_%p_hash", buf); dlp->dl_impl_hash = mod_hash_create_idhash(name, IMPL_HASHSZ, mod_hash_null_valdtor); @@ -190,12 +190,13 @@ i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, const mac_header_info_t *mhip, prevp->b_next = mp; /* - * The source, destination, sap, and vlan id must all match - * in a given subchain. + * The source, destination, sap, vlan id and the MSGNOLOOP + * flag must all match in a given subchain. */ if (memcmp(mhip->mhi_daddr, cmhi.mhi_daddr, addr_size) != 0 || memcmp(mhip->mhi_saddr, cmhi.mhi_saddr, addr_size) != 0 || - mhip->mhi_bindsap != cmhi.mhi_bindsap) { + mhip->mhi_bindsap != cmhi.mhi_bindsap || + mhip->mhi_prom_looped != cmhi.mhi_prom_looped) { /* * Note that we don't need to restore the padding. */ @@ -700,7 +701,7 @@ dls_link_txloop(void *arg, mblk_t *mp) static uint_t i_dls_link_walk(mod_hash_key_t key, mod_hash_val_t *val, void *arg) { - boolean_t *promiscp = arg; + boolean_t *promiscp = arg; uint32_t sap = KEY_SAP(key); if (sap == DLS_SAP_PROMISC) { @@ -833,7 +834,7 @@ dls_link_hold(const char *name, dls_link_t **dlpp) /* * Insert the dls_link_t. */ - err = mod_hash_insert(i_dls_link_hash, (mod_hash_key_t)name, + err = mod_hash_insert(i_dls_link_hash, (mod_hash_key_t)dlp->dl_name, (mod_hash_val_t)dlp); ASSERT(err == 0); @@ -841,6 +842,7 @@ dls_link_hold(const char *name, dls_link_t **dlpp) ASSERT(i_dls_link_count != 0); done: + /* * Bump the reference count and hand back the reference. */ @@ -884,26 +886,24 @@ done: int dls_mac_hold(dls_link_t *dlp) { + mac_handle_t mh; int err = 0; + err = mac_open(dlp->dl_name, &mh); + mutex_enter(&dlp->dl_lock); ASSERT(IMPLY(dlp->dl_macref != 0, dlp->dl_mh != NULL)); ASSERT(IMPLY(dlp->dl_macref == 0, dlp->dl_mh == NULL)); - - if (dlp->dl_macref == 0) { - /* - * First reference; hold open the MAC interface. - */ - err = mac_open(dlp->dl_name, &dlp->dl_mh); - if (err != 0) - goto done; - - dlp->dl_mip = mac_info(dlp->dl_mh); + if (err == 0) { + ASSERT(dlp->dl_mh == NULL || dlp->dl_mh == mh); + if (dlp->dl_mh == NULL) { + dlp->dl_mh = mh; + dlp->dl_mip = mac_info(mh); + } + dlp->dl_macref++; } - dlp->dl_macref++; -done: mutex_exit(&dlp->dl_lock); return (err); } @@ -914,9 +914,9 @@ dls_mac_rele(dls_link_t *dlp) mutex_enter(&dlp->dl_lock); ASSERT(dlp->dl_mh != NULL); + mac_close(dlp->dl_mh); + if (--dlp->dl_macref == 0) { - mac_rx_remove_wait(dlp->dl_mh); - mac_close(dlp->dl_mh); dlp->dl_mh = NULL; dlp->dl_mip = NULL; } @@ -997,7 +997,7 @@ dls_link_add(dls_link_t *dlp, uint32_t sap, dls_impl_t *dip) /* Replace the existing receive function if there is one. */ if (dlp->dl_mrh != NULL) - mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_FALSE); + mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_TRUE); dlp->dl_mrh = mac_active_rx_add(dlp->dl_mh, rx, (void *)dlp); mutex_exit(&dlp->dl_lock); } @@ -1073,7 +1073,7 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) */ if (dlp->dl_impl_count == 0) { rw_exit(&dlp->dl_impl_lock); - mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_FALSE); + mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_TRUE); dlp->dl_mrh = NULL; } else { boolean_t promisc = B_FALSE; @@ -1095,7 +1095,7 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) else rx = i_dls_link_rx; - mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_FALSE); + mac_rx_remove(dlp->dl_mh, dlp->dl_mrh, B_TRUE); dlp->dl_mrh = mac_active_rx_add(dlp->dl_mh, rx, (void *)dlp); } mutex_exit(&dlp->dl_lock); @@ -1152,5 +1152,11 @@ dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip) mhip->mhi_istagged = B_FALSE; mhip->mhi_tci = 0; } + + /* + * The messsage is looped back from the underlying driver. + */ + mhip->mhi_prom_looped = (mp->b_flag & MSGNOLOOP); + return (0); } diff --git a/usr/src/uts/common/io/dls/dls_mgmt.c b/usr/src/uts/common/io/dls/dls_mgmt.c new file mode 100644 index 0000000000..aff6ba26b1 --- /dev/null +++ b/usr/src/uts/common/io/dls/dls_mgmt.c @@ -0,0 +1,1562 @@ +/* + * 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" + +/* + * Datalink management routines. + */ + +#include <sys/types.h> +#include <sys/door.h> +#include <sys/zone.h> +#include <sys/modctl.h> +#include <sys/file.h> +#include <sys/modhash.h> +#include <sys/kstat.h> +#include <sys/vnode.h> +#include <sys/cmn_err.h> +#include <sys/vlan.h> +#include <sys/softmac.h> +#include <sys/dls.h> +#include <sys/dls_impl.h> + +static kmem_cache_t *i_dls_devnet_cachep; +static kmutex_t i_dls_mgmt_lock; +static krwlock_t i_dls_devnet_lock; +static mod_hash_t *i_dls_devnet_id_hash; +static mod_hash_t *i_dls_devnet_hash; + +boolean_t devnet_need_rebuild; + +#define VLAN_HASHSZ 67 /* prime */ + +/* Upcall door handle */ +static door_handle_t dls_mgmt_dh = NULL; + +/* + * This structure is used to keep the <linkid, macname, vid> mapping. + */ +typedef struct dls_devnet_s { + datalink_id_t dd_vlanid; + datalink_id_t dd_linkid; + char dd_mac[MAXNAMELEN]; + uint16_t dd_vid; + char dd_spa[MAXSPALEN]; + boolean_t dd_explicit; + kstat_t *dd_ksp; + + uint32_t dd_ref; + + kmutex_t dd_mutex; + kcondvar_t dd_cv; + uint32_t dd_tref; + + kmutex_t dd_zid_mutex; + zoneid_t dd_zid; +} dls_devnet_t; + +/*ARGSUSED*/ +static int +i_dls_devnet_constructor(void *buf, void *arg, int kmflag) +{ + dls_devnet_t *ddp = buf; + + bzero(buf, sizeof (dls_devnet_t)); + mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&ddp->dd_zid_mutex, NULL, MUTEX_DEFAULT, NULL); + cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL); + return (0); +} + +/*ARGSUSED*/ +static void +i_dls_devnet_destructor(void *buf, void *arg) +{ + dls_devnet_t *ddp = buf; + + ASSERT(ddp->dd_ksp == NULL); + ASSERT(ddp->dd_ref == 0); + ASSERT(ddp->dd_tref == 0); + ASSERT(!ddp->dd_explicit); + mutex_destroy(&ddp->dd_mutex); + mutex_destroy(&ddp->dd_zid_mutex); + cv_destroy(&ddp->dd_cv); +} + +/* + * Module initialization and finalization functions. + */ +void +dls_mgmt_init(void) +{ + mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL); + rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL); + + /* + * Create a kmem_cache of dls_devnet_t structures. + */ + i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache", + sizeof (dls_devnet_t), 0, i_dls_devnet_constructor, + i_dls_devnet_destructor, NULL, NULL, NULL, 0); + ASSERT(i_dls_devnet_cachep != NULL); + + /* + * Create a hash table, keyed by dd_vlanid, of dls_devnet_t. + */ + i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash", + VLAN_HASHSZ, mod_hash_null_valdtor); + + /* + * Create a hash table, keyed by dd_spa. + */ + i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash", + VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, + mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + + devnet_need_rebuild = B_FALSE; +} + +void +dls_mgmt_fini(void) +{ + mod_hash_destroy_hash(i_dls_devnet_hash); + mod_hash_destroy_hash(i_dls_devnet_id_hash); + kmem_cache_destroy(i_dls_devnet_cachep); + rw_destroy(&i_dls_devnet_lock); + mutex_destroy(&i_dls_mgmt_lock); +} + +int +dls_mgmt_door_set(boolean_t start) +{ + int err; + + /* handle daemon restart */ + mutex_enter(&i_dls_mgmt_lock); + if (dls_mgmt_dh != NULL) { + door_ki_rele(dls_mgmt_dh); + dls_mgmt_dh = NULL; + } + + if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) { + mutex_exit(&i_dls_mgmt_lock); + return (err); + } + + mutex_exit(&i_dls_mgmt_lock); + + /* + * Create and associate <link name, linkid> mapping for network devices + * which are already attached before the daemon is started. + */ + if (start) + softmac_recreate(); + return (0); +} + +static boolean_t +i_dls_mgmt_door_revoked(door_handle_t dh) +{ + struct door_info info; + extern int sys_shutdown; + + ASSERT(dh != NULL); + + if (sys_shutdown) { + cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n"); + return (B_TRUE); + } + + if (door_ki_info(dh, &info) != 0) + return (B_TRUE); + + return ((info.di_attributes & DOOR_REVOKED) != 0); +} + +/* + * Upcall to the datalink management daemon (dlmgmtd). + */ +static int +i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t *rsizep) +{ + door_arg_t darg, save_arg; + struct dlmgmt_null_retval_s *retvalp; + door_handle_t dh; + int err = EINVAL; + int retry = 0; + +#define MAXRETRYNUM 3 + + ASSERT(arg); + darg.data_ptr = arg; + darg.data_size = asize; + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = rbuf; + darg.rsize = *rsizep; + save_arg = darg; + +retry: + mutex_enter(&i_dls_mgmt_lock); + dh = dls_mgmt_dh; + if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) { + mutex_exit(&i_dls_mgmt_lock); + return (EBADF); + } + door_ki_hold(dh); + mutex_exit(&i_dls_mgmt_lock); + + for (;;) { + retry++; + if ((err = door_ki_upcall(dh, &darg)) == 0) + break; + + /* + * handle door call errors + */ + darg = save_arg; + switch (err) { + case EINTR: + /* + * If the operation which caused this door upcall gets + * interrupted, return directly. + */ + goto done; + case EAGAIN: + /* + * Repeat upcall if the maximum attempt limit has not + * been reached. + */ + if (retry < MAXRETRYNUM) { + delay(2 * hz); + break; + } + cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); + goto done; + default: + /* A fatal door error */ + if (i_dls_mgmt_door_revoked(dh)) { + cmn_err(CE_NOTE, + "dls: dlmgmtd door service revoked\n"); + + if (retry < MAXRETRYNUM) { + door_ki_rele(dh); + goto retry; + } + } + cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); + goto done; + } + } + + if (darg.rbuf != rbuf) { + /* + * The size of the input rbuf was not big enough, so the + * upcall allocated the rbuf itself. If this happens, assume + * that this was an invalid door call request. + */ + kmem_free(darg.rbuf, darg.rsize); + err = ENOSPC; + goto done; + } + + if (darg.rsize > *rsizep || darg.rsize < sizeof (uint_t)) { + err = EINVAL; + goto done; + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + retvalp = (struct dlmgmt_null_retval_s *)darg.rbuf; + if (retvalp->lr_err != 0) { + err = retvalp->lr_err; + goto done; + } + + *rsizep = darg.rsize; + +done: + door_ki_rele(dh); + return (err); +} + +/* + * Request the datalink management daemon to create a link with the attributes + * below. Upon success, zero is returned and linkidp contains the linkid for + * the new link; otherwise, an errno is returned. + * + * - dev physical dev_t. required for all physical links, + * including GLDv3 links. It will be used to force the + * attachment of a physical device, hence the + * registration of its mac + * - class datalink class + * - media type media type; DL_OTHER means unknown + * - vid VLAN ID (for VLANs) + * - persist whether to persist the datalink + */ +int +dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class, + uint32_t media, boolean_t persist, datalink_id_t *linkidp) +{ + dlmgmt_upcall_arg_create_t create; + dlmgmt_create_retval_t retval; + size_t rsize; + int err; + + create.ld_cmd = DLMGMT_CMD_DLS_CREATE; + create.ld_class = class; + create.ld_media = media; + create.ld_phymaj = getmajor(dev); + create.ld_phyinst = getminor(dev); + create.ld_persist = persist; + if (strlcpy(create.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) + return (EINVAL); + + rsize = sizeof (retval); + + err = i_dls_mgmt_upcall(&create, sizeof (create), &retval, &rsize); + if (err == 0) + *linkidp = retval.lr_linkid; + return (err); +} + +/* + * Request the datalink management daemon to destroy the specified link. + * Returns zero upon success, or an errno upon failure. + */ +int +dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist) +{ + dlmgmt_upcall_arg_destroy_t destroy; + dlmgmt_destroy_retval_t retval; + size_t rsize; + + destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY; + destroy.ld_linkid = linkid; + destroy.ld_persist = persist; + rsize = sizeof (retval); + + return (i_dls_mgmt_upcall(&destroy, sizeof (destroy), &retval, &rsize)); +} + +/* + * Request the datalink management daemon to verify/update the information + * for a physical link. Upon success, get its linkid. + * + * - media type media type + * - novanity whether this physical datalink supports vanity naming. + * physical links that do not use the GLDv3 MAC plugin + * cannot suport vanity naming + * + * This function could fail with ENOENT or EEXIST. Two cases return EEXIST: + * + * 1. A link with devname already exists, but the media type does not match. + * In this case, mediap will bee set to the media type of the existing link. + * 2. A link with devname already exists, but its link name does not match + * the device name, although this link does not support vanity naming. + */ +int +dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity, + uint32_t *mediap, datalink_id_t *linkidp) +{ + dlmgmt_upcall_arg_update_t update; + dlmgmt_update_retval_t retval; + size_t rsize; + int err; + + update.ld_cmd = DLMGMT_CMD_DLS_UPDATE; + + if (strlcpy(update.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) + return (EINVAL); + + update.ld_media = media; + update.ld_novanity = novanity; + rsize = sizeof (retval); + + err = i_dls_mgmt_upcall(&update, sizeof (update), &retval, &rsize); + if (err == EEXIST) { + *linkidp = retval.lr_linkid; + *mediap = retval.lr_media; + } else if (err == 0) { + *linkidp = retval.lr_linkid; + } + + return (err); +} + +/* + * Request the datalink management daemon to get the information for a link. + * Returns zero upon success, or an errno upon failure. + * + * Only fills in information for argument pointers that are non-NULL. + * Note that the link argument is expected to be MAXLINKNAMELEN bytes. + */ +int +dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link, + datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp) +{ + dlmgmt_door_getname_t getname; + dlmgmt_getname_retval_t retval; + size_t rsize; + int err, len; + + getname.ld_cmd = DLMGMT_CMD_GETNAME; + getname.ld_linkid = linkid; + rsize = sizeof (retval); + + err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval, &rsize); + if (err != 0) + return (err); + + len = strlen(retval.lr_link); + if (len <= 1 || len >= MAXLINKNAMELEN) + return (EINVAL); + + if (link != NULL) + (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN); + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + if (flagsp != NULL) + *flagsp = retval.lr_flags; + return (0); +} + +/* + * Request the datalink management daemon to get the linkid for a link. + * Returns a non-zero error code on failure. The linkid argument is only + * set on success (when zero is returned.) + */ +int +dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid) +{ + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_getlinkid_retval_t retval; + size_t rsize; + int err; + + getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; + (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval, + &rsize); + if (err == 0) + *linkid = retval.lr_linkid; + return (err); +} + +datalink_id_t +dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class, + datalink_media_t dmedia, uint32_t flags) +{ + dlmgmt_door_getnext_t getnext; + dlmgmt_getnext_retval_t retval; + size_t rsize; + + getnext.ld_cmd = DLMGMT_CMD_GETNEXT; + getnext.ld_class = class; + getnext.ld_dmedia = dmedia; + getnext.ld_flags = flags; + getnext.ld_linkid = linkid; + rsize = sizeof (retval); + + if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval, &rsize) != 0) + return (DATALINK_INVALID_LINKID); + + return (retval.lr_linkid); +} + +static int +i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr, + void *attrval, size_t *attrszp) +{ + dlmgmt_upcall_arg_getattr_t getattr; + dlmgmt_getattr_retval_t *retvalp; + size_t oldsize, size; + int err; + + getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR; + getattr.ld_linkid = linkid; + (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); + + oldsize = size = *attrszp + sizeof (dlmgmt_getattr_retval_t) - 1; + retvalp = kmem_zalloc(oldsize, KM_SLEEP); + + err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), retvalp, &size); + if (err == 0) { + ASSERT(size <= oldsize); + *attrszp = size + 1 - sizeof (dlmgmt_getattr_retval_t); + bcopy(retvalp->lr_attr, attrval, *attrszp); + } + + kmem_free(retvalp, oldsize); + return (err); +} + +/* + * Note that this function can only get devp successfully for non-VLAN link. + */ +int +dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp) +{ + uint64_t maj, inst; + size_t attrsz = sizeof (uint64_t); + + if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 || + attrsz != sizeof (uint64_t) || + i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 || + attrsz != sizeof (uint64_t)) { + return (EINVAL); + } + + *devp = makedevice((major_t)maj, (minor_t)inst); + return (0); +} + +/* + * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to + * delete the dls_devnet_t will wait until the temporary reference is released. + */ +int +dls_devnet_hold_tmp(datalink_id_t linkid, dls_dl_handle_t *ddhp) +{ + dls_devnet_t *ddp; + dls_dev_handle_t ddh = NULL; + dev_t phydev = 0; + int err; + + /* + * Hold this link to prevent it being detached (if physical link). + */ + if (dls_mgmt_get_phydev(linkid, &phydev) == 0) + (void) softmac_hold_device(phydev, &ddh); + + rw_enter(&i_dls_devnet_lock, RW_READER); + if ((err = mod_hash_find(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); + rw_exit(&i_dls_devnet_lock); + softmac_rele_device(ddh); + return (ENOENT); + } + + /* + * At least one reference was held when this datalink was created. + */ + ASSERT(ddp->dd_ref > 0); + mutex_enter(&ddp->dd_mutex); + ddp->dd_tref++; + mutex_exit(&ddp->dd_mutex); + rw_exit(&i_dls_devnet_lock); + softmac_rele_device(ddh); + +done: + *ddhp = ddp; + return (0); +} + +void +dls_devnet_rele_tmp(dls_dl_handle_t dlh) +{ + dls_devnet_t *ddp = dlh; + + mutex_enter(&ddp->dd_mutex); + ASSERT(ddp->dd_tref != 0); + if (--ddp->dd_tref == 0) + cv_signal(&ddp->dd_cv); + mutex_exit(&ddp->dd_mutex); +} + +/* + * "link" kstats related functions. + */ + +/* + * Query the "link" kstats. + */ +static int +dls_devnet_stat_update(kstat_t *ksp, int rw) +{ + dls_devnet_t *ddp = ksp->ks_private; + dls_vlan_t *dvp; + int err; + + err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_FALSE); + if (err != 0) + return (err); + + err = dls_stat_update(ksp, dvp, rw); + dls_vlan_rele(dvp); + return (err); +} + +/* + * Create the "link" kstats. + */ +static void +dls_devnet_stat_create(dls_devnet_t *ddp) +{ + char link[MAXLINKNAMELEN]; + kstat_t *ksp; + + if ((dls_mgmt_get_linkinfo(ddp->dd_vlanid, link, + NULL, NULL, NULL)) != 0) { + return; + } + + if (dls_stat_create("link", 0, link, dls_devnet_stat_update, + ddp, &ksp) != 0) { + return; + } + + ASSERT(ksp != NULL); + ddp->dd_ksp = ksp; +} + +/* + * Destroy the "link" kstats. + */ +static void +dls_devnet_stat_destroy(dls_devnet_t *ddp) +{ + if (ddp->dd_ksp == NULL) + return; + + kstat_delete(ddp->dd_ksp); + ddp->dd_ksp = NULL; +} + +/* + * The link has been renamed. Destroy the old non-legacy kstats ("link kstats") + * and create the new set using the new name. + */ +static void +dls_devnet_stat_rename(dls_devnet_t *ddp, const char *link) +{ + kstat_t *ksp; + + if (ddp->dd_ksp != NULL) { + kstat_delete(ddp->dd_ksp); + ddp->dd_ksp = NULL; + } + + if (dls_stat_create("link", 0, link, dls_devnet_stat_update, + ddp, &ksp) != 0) { + return; + } + + ASSERT(ksp != NULL); + ddp->dd_ksp = ksp; +} + +/* + * Associate a linkid with a given link (identified by <macname/vid>) + * + * Several cases: + * a. implicit VLAN creation: (non-NULL "vlan") + * b. explicit VLAN creation: (NULL "vlan") + * c. explicit non-VLAN creation: + * (NULL "vlan" and linkid could be INVALID_LINKID if the physical device + * was created before the daemon was started) + */ +static int +dls_devnet_set(const char *macname, uint16_t vid, + datalink_id_t vlan_linkid, datalink_id_t linkid, const char *vlan, + dls_devnet_t **ddpp) +{ + dls_devnet_t *ddp = NULL; + char spa[MAXSPALEN]; + boolean_t explicit = (vlan == NULL); + datalink_class_t class; + int err; + + ASSERT(vid != VLAN_ID_NONE || explicit); + ASSERT(vlan_linkid != DATALINK_INVALID_LINKID || !explicit || + vid == VLAN_ID_NONE); + + (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); + rw_enter(&i_dls_devnet_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_devnet_hash, + (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) == 0) { + char link[MAXLINKNAMELEN]; + + if (explicit) { + if ((vid != VLAN_ID_NONE) || + (ddp->dd_vlanid != DATALINK_INVALID_LINKID)) { + err = EEXIST; + goto done; + } + + /* + * This might be a physical link that has already + * been created, but which does not have a vlan_linkid + * because dlmgmtd was not running when it was created. + */ + if ((err = dls_mgmt_get_linkinfo(vlan_linkid, NULL, + &class, NULL, NULL)) != 0) { + goto done; + } + + if (class != DATALINK_CLASS_PHYS) { + err = EINVAL; + goto done; + } + + goto newphys; + } + + /* + * Implicit VLAN, but the same name has already + * been associated with another linkid. Check if the name + * of that link matches the given VLAN name. + */ + ASSERT(vid != VLAN_ID_NONE); + if ((err = dls_mgmt_get_linkinfo(ddp->dd_vlanid, link, + NULL, NULL, NULL)) != 0) { + goto done; + } + + if (strcmp(link, vlan) != 0) { + err = EEXIST; + goto done; + } + + /* + * This is not an implicit created VLAN any more, return + * this existing datalink. + */ + ASSERT(ddp->dd_ref > 0); + ddp->dd_ref++; + goto done; + } + + /* + * Request the daemon to create a new vlan_linkid for this implicitly + * created vlan. + */ + if (!explicit && ((err = dls_mgmt_create(vlan, 0, + DATALINK_CLASS_VLAN, DL_ETHER, B_FALSE, &vlan_linkid)) != 0)) { + goto done; + } + + ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP); + ddp->dd_vid = vid; + ddp->dd_explicit = explicit; + ddp->dd_tref = 0; + ddp->dd_ref++; + ddp->dd_zid = GLOBAL_ZONEID; + (void) strncpy(ddp->dd_mac, macname, MAXNAMELEN); + (void) snprintf(ddp->dd_spa, MAXSPALEN, "%s/%d", macname, vid); + VERIFY(mod_hash_insert(i_dls_devnet_hash, + (mod_hash_key_t)ddp->dd_spa, (mod_hash_val_t)ddp) == 0); + +newphys: + + ddp->dd_vlanid = vlan_linkid; + if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) { + ddp->dd_linkid = linkid; + + VERIFY(mod_hash_insert(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)vlan_linkid, + (mod_hash_val_t)ddp) == 0); + devnet_need_rebuild = B_TRUE; + dls_devnet_stat_create(ddp); + } + err = 0; +done: + rw_exit(&i_dls_devnet_lock); + if (err == 0 && ddpp != NULL) + *ddpp = ddp; + return (err); +} + +static void +dls_devnet_unset_common(dls_devnet_t *ddp) +{ + mod_hash_val_t val; + + ASSERT(RW_WRITE_HELD(&i_dls_devnet_lock)); + + ASSERT(ddp->dd_ref == 0); + + /* + * Remove this dls_devnet_t from the hash table. + */ + VERIFY(mod_hash_remove(i_dls_devnet_hash, + (mod_hash_key_t)ddp->dd_spa, &val) == 0); + + if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) { + VERIFY(mod_hash_remove(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, &val) == 0); + + dls_devnet_stat_destroy(ddp); + devnet_need_rebuild = B_TRUE; + } + + /* + * Wait until all temporary references are released. + */ + mutex_enter(&ddp->dd_mutex); + while (ddp->dd_tref != 0) + cv_wait(&ddp->dd_cv, &ddp->dd_mutex); + mutex_exit(&ddp->dd_mutex); + + if (!ddp->dd_explicit) { + ASSERT(ddp->dd_vid != VLAN_ID_NONE); + ASSERT(ddp->dd_vlanid != DATALINK_INVALID_LINKID); + (void) dls_mgmt_destroy(ddp->dd_vlanid, B_FALSE); + } + + ddp->dd_vlanid = DATALINK_INVALID_LINKID; + ddp->dd_zid = GLOBAL_ZONEID; + ddp->dd_explicit = B_FALSE; + kmem_cache_free(i_dls_devnet_cachep, ddp); +} + +/* + * Disassociate a linkid with a given link (identified by <macname/vid>) + */ +static int +dls_devnet_unset(const char *macname, uint16_t vid, datalink_id_t *id) +{ + dls_devnet_t *ddp; + char spa[MAXSPALEN]; + int err; + + (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); + + rw_enter(&i_dls_devnet_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_devnet_hash, + (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); + rw_exit(&i_dls_devnet_lock); + return (ENOENT); + } + + ASSERT(ddp->dd_ref != 0); + + if (ddp->dd_ref != 1) { + rw_exit(&i_dls_devnet_lock); + return (EBUSY); + } + + ddp->dd_ref--; + + if (id != NULL) + *id = ddp->dd_vlanid; + + dls_devnet_unset_common(ddp); + rw_exit(&i_dls_devnet_lock); + return (0); +} + +static int +dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp) +{ + dls_devnet_t *ddp; + dev_t phydev = 0; + dls_dev_handle_t ddh = NULL; + int err; + + /* + * Hold this link to prevent it being detached in case of a + * physical link. + */ + if (dls_mgmt_get_phydev(linkid, &phydev) == 0) + (void) softmac_hold_device(phydev, &ddh); + + rw_enter(&i_dls_devnet_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); + rw_exit(&i_dls_devnet_lock); + softmac_rele_device(ddh); + return (ENOENT); + } + + ASSERT(ddp->dd_ref > 0); + ddp->dd_ref++; + rw_exit(&i_dls_devnet_lock); + softmac_rele_device(ddh); + +done: + *ddpp = ddp; + return (0); +} + +/* + * This funtion is called when a DLS client tries to open a device node. + * This dev_t could a result of a /dev/net node access (returned by + * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access. + * In both cases, this function returns 0. In the first case, bump the + * reference count of the dls_devnet_t structure, so that it will not be + * freed when devnet_inactive_callback->dls_devnet_close() is called + * (Note that devnet_inactive_callback() is called right after dld_open, + * not when the /dev/net access is done). In the second case, ddhp would + * be NULL. + * + * To undo this function, call dls_devnet_close() in the first case, and call + * dls_vlan_rele() in the second case. + */ +int +dls_devnet_open_by_dev(dev_t dev, dls_vlan_t **dvpp, dls_dl_handle_t *ddhp) +{ + dls_dev_handle_t ddh = NULL; + char spa[MAXSPALEN]; + dls_devnet_t *ddp; + dls_vlan_t *dvp; + int err; + + /* + * Hold this link to prevent it being detached in case of a + * GLDv3 physical link. + */ + if (getminor(dev) - 1 < MAC_MAX_MINOR) + (void) softmac_hold_device(dev, &ddh); + + /* + * Found the dls_vlan_t with the given dev. + */ + err = dls_vlan_hold_by_dev(dev, &dvp); + softmac_rele_device(ddh); + + if (err != 0) + return (err); + + (void) snprintf(spa, MAXSPALEN, "%s/%d", + dvp->dv_dlp->dl_name, dvp->dv_id); + + rw_enter(&i_dls_devnet_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_devnet_hash, + (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); + rw_exit(&i_dls_devnet_lock); + *ddhp = NULL; + *dvpp = dvp; + return (0); + } + + ASSERT(ddp->dd_ref > 0); + ddp->dd_ref++; + rw_exit(&i_dls_devnet_lock); + *ddhp = ddp; + *dvpp = dvp; + return (0); +} + +static void +dls_devnet_rele(dls_devnet_t *ddp) +{ + rw_enter(&i_dls_devnet_lock, RW_WRITER); + ASSERT(ddp->dd_ref != 0); + if (--ddp->dd_ref != 0) { + rw_exit(&i_dls_devnet_lock); + return; + } + /* + * This should only happen for implicitly-created VLAN. + */ + ASSERT(ddp->dd_vid != VLAN_ID_NONE); + dls_devnet_unset_common(ddp); + rw_exit(&i_dls_devnet_lock); +} + +static int +dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp, zoneid_t zid) +{ + char link_under[MAXLINKNAMELEN]; + char drv[MAXLINKNAMELEN]; + uint_t ppa; + major_t major; + dev_t phy_dev, tmp_dev; + uint_t vid; + datalink_id_t linkid; + dls_devnet_t *ddp; + dls_dev_handle_t ddh; + int err; + + if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0) + return (dls_devnet_hold(linkid, ddpp)); + + /* + * If we failed to get the link's linkid because the dlmgmtd daemon + * has not been started, return ENOENT so that the application can + * fallback to open the /dev node. + */ + if (err == EBADF) + return (ENOENT); + + if (err != ENOENT) + return (err); + + if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS) + return (ENOENT); + + if ((vid = DLS_PPA2VID(ppa)) > VLAN_ID_MAX) + return (ENOENT); + + ppa = (uint_t)DLS_PPA2INST(ppa); + (void) snprintf(link_under, sizeof (link_under), "%s%d", drv, ppa); + + if (vid != VLAN_ID_NONE) { + /* + * Only global zone can implicitly create a VLAN. + */ + if (zid != GLOBAL_ZONEID) + return (ENOENT); + + /* + * This is potentially an implicitly-created VLAN. Hold the + * link this VLAN is created on. + */ + if (dls_mgmt_get_linkid(link_under, &linkid) == 0 && + dls_devnet_hold_tmp(linkid, &ddp) == 0) { + if (ddp->dd_vid != VLAN_ID_NONE) { + dls_devnet_rele_tmp(ddp); + return (ENOENT); + } + goto implicit; + } + } + + /* + * If this link (or the link that an implicit vlan is created on) + * (a) is a physical device, (b) this is the first boot, (c) the MAC + * is not registered yet, and (d) we cannot find its linkid, then the + * linkname is the same as the devname. + * + * First filter out invalid names. + */ + if ((major = ddi_name_to_major(drv)) == (major_t)-1) + return (ENOENT); + + phy_dev = makedevice(major, (minor_t)ppa + 1); + if (softmac_hold_device(phy_dev, &ddh) != 0) + return (ENOENT); + + /* + * At this time, the MAC should be registered, check its phy_dev using + * the given name. + */ + if ((err = dls_mgmt_get_linkid(link_under, &linkid)) != 0 || + (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) { + softmac_rele_device(ddh); + return (err); + } + if (tmp_dev != phy_dev) { + softmac_rele_device(ddh); + return (ENOENT); + } + + if (vid == VLAN_ID_NONE) { + /* + * For non-VLAN, we are done. + */ + err = dls_devnet_hold(linkid, ddpp); + softmac_rele_device(ddh); + return (err); + } + + /* + * If this is an implicit VLAN, temporarily hold this non-VLAN. + */ + VERIFY(dls_devnet_hold_tmp(linkid, &ddp) == 0); + softmac_rele_device(ddh); + ASSERT(ddp->dd_vid == VLAN_ID_NONE); + + /* + * Again, this is potentially an implicitly-created VLAN. + */ + +implicit: + ASSERT(vid != VLAN_ID_NONE); + err = dls_devnet_set(ddp->dd_mac, vid, DATALINK_INVALID_LINKID, + linkid, link, ddpp); + dls_devnet_rele_tmp(ddp); + return (err); +} + +/* + * Get linkid for the given dev. + */ +int +dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp) +{ + dls_vlan_t *dvp; + dls_devnet_t *ddp; + char spa[MAXSPALEN]; + int err; + + if ((err = dls_vlan_hold_by_dev(dev, &dvp)) != 0) + return (err); + + (void) snprintf(spa, MAXSPALEN, "%s/%d", + dvp->dv_dlp->dl_name, dvp->dv_id); + + rw_enter(&i_dls_devnet_lock, RW_READER); + if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)spa, + (mod_hash_val_t *)&ddp) != 0) { + rw_exit(&i_dls_devnet_lock); + dls_vlan_rele(dvp); + return (ENOENT); + } + + *linkidp = ddp->dd_vlanid; + rw_exit(&i_dls_devnet_lock); + dls_vlan_rele(dvp); + return (0); +} + +/* + * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the + * link this VLAN is created on. + */ +int +dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp) +{ + dls_devnet_t *ddp; + int err; + + if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0) + return (err); + + err = dls_mgmt_get_phydev(ddp->dd_linkid, devp); + dls_devnet_rele_tmp(ddp); + return (err); +} + +/* + * Handle the renaming requests. There are two rename cases: + * + * 1. Request to rename a valid link (id1) to an non-existent link name + * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether + * id1 is held by any applications. + * + * In this case, the link's kstats need to be updated using the given name. + * + * 2. Request to rename a valid link (id1) to the name of a REMOVED + * physical link (id2). In this case, check htat id1 and its associated + * mac is not held by any application, and update the link's linkid to id2. + * + * This case does not change the <link name, linkid> mapping, so the link's + * kstats need to be updated with using name associated the given id2. + */ +int +dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link) +{ + dls_dev_handle_t ddh = NULL; + char linkname[MAXLINKNAMELEN]; + int err = 0; + dev_t phydev = 0; + dls_devnet_t *ddp; + mac_handle_t mh; + mod_hash_val_t val; + + /* + * In the second case, id2 must be a REMOVED physical link. + */ + if ((id2 != DATALINK_INVALID_LINKID) && + (dls_mgmt_get_phydev(id2, &phydev) == 0) && + softmac_hold_device(phydev, &ddh) == 0) { + softmac_rele_device(ddh); + return (EEXIST); + } + + /* + * Hold id1 to prevent it from being detached (if a physical link). + */ + if (dls_mgmt_get_phydev(id1, &phydev) == 0) + (void) softmac_hold_device(phydev, &ddh); + + rw_enter(&i_dls_devnet_lock, RW_WRITER); + if ((err = mod_hash_find(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); + err = ENOENT; + goto done; + } + + /* + * Return EBUSY if any applications have this link open. + */ + if ((ddp->dd_explicit && ddp->dd_ref > 1) || + (!ddp->dd_explicit && ddp->dd_ref > 0)) { + err = EBUSY; + goto done; + } + + if (id2 == DATALINK_INVALID_LINKID) { + (void) strlcpy(linkname, link, sizeof (linkname)); + goto done; + } + + /* + * The second case, check whether the MAC is used by any MAC + * user. This must be a physical link so ddh must not be NULL. + */ + if (ddh == NULL) { + err = EINVAL; + goto done; + } + + if ((err = mac_open(ddp->dd_mac, &mh)) != 0) + goto done; + + /* + * We release the reference of the MAC which mac_open() is + * holding. Note that this mac will not be unregistered + * because the physical device is hold. + */ + mac_close(mh); + + /* + * Check if there is any other MAC clients, if not, hold this mac + * exclusively until we are done. + */ + if ((err = mac_hold_exclusive(mh)) != 0) + goto done; + + /* + * Update the link's linkid. + */ + if ((err = mod_hash_find(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) { + mac_rele_exclusive(mh); + err = EEXIST; + goto done; + } + + err = dls_mgmt_get_linkinfo(id2, linkname, NULL, NULL, NULL); + if (err != 0) { + mac_rele_exclusive(mh); + goto done; + } + + (void) mod_hash_remove(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)id1, &val); + + ddp->dd_vlanid = id2; + (void) mod_hash_insert(i_dls_devnet_id_hash, + (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, (mod_hash_val_t)ddp); + + mac_rele_exclusive(mh); + +done: + /* + * Change the name of the kstat based on the new link name. + */ + if (err == 0) + dls_devnet_stat_rename(ddp, linkname); + + rw_exit(&i_dls_devnet_lock); + softmac_rele_device(ddh); + return (err); +} + +int +dls_devnet_setzid(const char *link, zoneid_t zid) +{ + dls_devnet_t *ddp; + int err; + zoneid_t old_zid; + + if ((err = dls_devnet_hold_by_name(link, &ddp, GLOBAL_ZONEID)) != 0) + return (err); + + mutex_enter(&ddp->dd_zid_mutex); + if ((old_zid = ddp->dd_zid) == zid) { + mutex_exit(&ddp->dd_zid_mutex); + dls_devnet_rele(ddp); + return (0); + } + + if ((err = dls_vlan_setzid(ddp->dd_mac, ddp->dd_vid, zid)) != 0) { + mutex_exit(&ddp->dd_zid_mutex); + dls_devnet_rele(ddp); + return (err); + } + + ddp->dd_zid = zid; + devnet_need_rebuild = B_TRUE; + mutex_exit(&ddp->dd_zid_mutex); + + /* + * Keep this open reference only if it belonged to the global zone + * and is now assigned to a non-global zone. + */ + if (old_zid != GLOBAL_ZONEID || zid == GLOBAL_ZONEID) + dls_devnet_rele(ddp); + + /* + * Then release this link if it belonged to an non-global zone + * but is now assigned back to the global zone. + */ + if (old_zid != GLOBAL_ZONEID && zid == GLOBAL_ZONEID) + dls_devnet_rele(ddp); + + return (0); +} + +int +dls_devnet_getzid(datalink_id_t linkid, zoneid_t *zidp) +{ + dls_devnet_t *ddp; + int err; + + if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0) + return (err); + + mutex_enter(&ddp->dd_zid_mutex); + *zidp = ddp->dd_zid; + mutex_exit(&ddp->dd_zid_mutex); + + dls_devnet_rele_tmp(ddp); + return (0); +} + +/* + * Access a vanity naming node. + */ +int +dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp) +{ + dls_devnet_t *ddp; + dls_vlan_t *dvp; + zoneid_t zid = getzoneid(); + int err; + + if ((err = dls_devnet_hold_by_name(link, &ddp, zid)) != 0) + return (err); + + /* + * Opening a link that does not belong to the current non-global zone + * is not allowed. + */ + if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) { + dls_devnet_rele(ddp); + return (ENOENT); + } + + err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_TRUE); + if (err != 0) { + dls_devnet_rele(ddp); + return (err); + } + + *dhp = ddp; + *devp = dvp->dv_dev; + return (0); +} + +/* + * Close access to a vanity naming node. + */ +void +dls_devnet_close(dls_dl_handle_t dlh) +{ + dls_devnet_t *ddp = dlh; + dls_vlan_t *dvp; + + /* + * The VLAN is hold in dls_open_devnet_link(). + */ + VERIFY((dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, + B_FALSE)) == 0); + dls_vlan_rele(dvp); + dls_vlan_rele(dvp); + dls_devnet_rele(ddp); +} + +/* + * This is used by /dev/net to rebuild the nodes for readdir(). It is not + * critical and no protection is needed. + */ +boolean_t +dls_devnet_rebuild() +{ + boolean_t updated = devnet_need_rebuild; + + devnet_need_rebuild = B_FALSE; + return (updated); +} + +int +dls_devnet_create(mac_handle_t mh, datalink_id_t linkid) +{ + int err; + + if ((err = dls_vlan_create(mac_name(mh), 0, B_FALSE)) != 0) + return (err); + + err = dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL); + if (err != 0) + (void) dls_vlan_destroy(mac_name(mh), 0); + + return (err); +} + +/* + * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash. + * This is called in the case that the dlmgmtd daemon is started later than + * the physical devices get attached, and the linkid is only known after the + * daemon starts. + */ +int +dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid) +{ + ASSERT(linkid != DATALINK_INVALID_LINKID); + return (dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL)); +} + +int +dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp) +{ + int err; + + *idp = DATALINK_INVALID_LINKID; + err = dls_devnet_unset(mac_name(mh), 0, idp); + if (err != 0 && err != ENOENT) + return (err); + + if ((err = dls_vlan_destroy(mac_name(mh), 0)) == 0) + return (0); + + (void) dls_devnet_set(mac_name(mh), 0, *idp, *idp, NULL, NULL); + return (err); +} + +int +dls_devnet_create_vlan(datalink_id_t vlanid, datalink_id_t linkid, + uint16_t vid, boolean_t force) +{ + dls_devnet_t *lnddp, *ddp; + dls_vlan_t *dvp; + int err; + + /* + * Hold the link the VLAN is being created on (which must not be a + * VLAN). + */ + ASSERT(vid != VLAN_ID_NONE); + if ((err = dls_devnet_hold_tmp(linkid, &lnddp)) != 0) + return (err); + + if (lnddp->dd_vid != VLAN_ID_NONE) { + err = EINVAL; + goto done; + } + + /* + * A new link. + */ + err = dls_devnet_set(lnddp->dd_mac, vid, vlanid, linkid, NULL, &ddp); + if (err != 0) + goto done; + + /* + * Hold the dls_vlan_t (and create it if needed). + */ + err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, force, B_TRUE); + if (err != 0) + VERIFY(dls_devnet_unset(lnddp->dd_mac, vid, NULL) == 0); + +done: + dls_devnet_rele_tmp(lnddp); + return (err); +} + +int +dls_devnet_destroy_vlan(datalink_id_t vlanid) +{ + char macname[MAXNAMELEN]; + uint16_t vid; + dls_devnet_t *ddp; + dls_vlan_t *dvp; + int err; + + if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0) + return (err); + + if (ddp->dd_vid == VLAN_ID_NONE) { + dls_devnet_rele_tmp(ddp); + return (EINVAL); + } + + if (!ddp->dd_explicit) { + dls_devnet_rele_tmp(ddp); + return (EBUSY); + } + + (void) strncpy(macname, ddp->dd_mac, MAXNAMELEN); + vid = ddp->dd_vid; + + /* + * It is safe to release the temporary reference we just held, as the + * reference from VLAN creation is still held. + */ + dls_devnet_rele_tmp(ddp); + + if ((err = dls_devnet_unset(macname, vid, NULL)) != 0) + return (err); + + /* + * This VLAN has already been held as the result of VLAN creation. + */ + VERIFY(dls_vlan_hold(macname, vid, &dvp, B_FALSE, B_FALSE) == 0); + + /* + * Release the reference which was held when this VLAN was created, + * and the reference which was just held. + */ + dls_vlan_rele(dvp); + dls_vlan_rele(dvp); + return (0); +} + +const char * +dls_devnet_mac(dls_dl_handle_t ddh) +{ + return (ddh->dd_mac); +} + +uint16_t +dls_devnet_vid(dls_dl_handle_t ddh) +{ + return (ddh->dd_vid); +} + +datalink_id_t +dls_devnet_linkid(dls_dl_handle_t ddh) +{ + return (ddh->dd_linkid); +} + +boolean_t +dls_devnet_is_explicit(dls_dl_handle_t ddh) +{ + return (ddh->dd_explicit); +} diff --git a/usr/src/uts/common/io/dls/dls_mod.c b/usr/src/uts/common/io/dls/dls_mod.c index 9567d785ba..b93befd45c 100644 --- a/usr/src/uts/common/io/dls/dls_mod.c +++ b/usr/src/uts/common/io/dls/dls_mod.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. */ @@ -58,6 +57,7 @@ i_dls_mod_init(void) dls_init(); dls_vlan_init(); dls_link_init(); + dls_mgmt_init(); } static int @@ -68,6 +68,8 @@ i_dls_mod_fini(void) if ((err = dls_link_fini()) != 0) return (err); + dls_mgmt_fini(); + err = dls_vlan_fini(); ASSERT(err == 0); diff --git a/usr/src/uts/common/io/dls/dls_soft_ring.c b/usr/src/uts/common/io/dls/dls_soft_ring.c index 49d862a860..a1ac10972c 100644 --- a/usr/src/uts/common/io/dls/dls_soft_ring.c +++ b/usr/src/uts/common/io/dls/dls_soft_ring.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. */ @@ -529,33 +529,6 @@ destroy: } void -dls_soft_ring_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg, int type) -{ - dls_impl_t *dip = (dls_impl_t *)dc; - - rw_enter(&(dip->di_lock), RW_WRITER); - dip->di_rx = rx; - if (type == SOFT_RING_NONE) - dip->di_rx_arg = arg; - else - dip->di_rx_arg = (void *)dip; - rw_exit(&(dip->di_lock)); -} - -boolean_t -dls_soft_ring_workers(dls_channel_t dc) -{ - dls_impl_t *dip = (dls_impl_t *)dc; - boolean_t ret = B_FALSE; - - rw_enter(&(dip->di_lock), RW_READER); - if (dip->di_soft_ring_list != NULL) - ret = B_TRUE; - rw_exit(&(dip->di_lock)); - return (ret); -} - -void dls_soft_ring_disable(dls_channel_t dc) { dls_impl_t *dip = (dls_impl_t *)dc; diff --git a/usr/src/uts/common/io/dls/dls_stat.c b/usr/src/uts/common/io/dls/dls_stat.c index daee626df4..99f41d0c7d 100644 --- a/usr/src/uts/common/io/dls/dls_stat.c +++ b/usr/src/uts/common/io/dls/dls_stat.c @@ -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. */ @@ -35,6 +35,7 @@ #include <sys/kstat.h> #include <sys/vlan.h> #include <sys/mac.h> +#include <sys/mac_ether.h> #include <sys/ctype.h> #include <sys/dls.h> #include <sys/dls_impl.h> @@ -57,7 +58,9 @@ static mac_stat_info_t i_dls_si[] = { { MAC_STAT_RBYTES, "rbytes64", KSTAT_DATA_UINT64, 0 }, { MAC_STAT_IPACKETS, "ipackets64", KSTAT_DATA_UINT64, 0 }, { MAC_STAT_OBYTES, "obytes64", KSTAT_DATA_UINT64, 0 }, - { MAC_STAT_OPACKETS, "opackets64", KSTAT_DATA_UINT64, 0 } + { MAC_STAT_OPACKETS, "opackets64", KSTAT_DATA_UINT64, 0 }, + { MAC_STAT_LINK_STATE, "link_state", KSTAT_DATA_UINT32, + (uint64_t)LINK_STATE_UNKNOWN} }; #define STAT_INFO_COUNT (sizeof (i_dls_si) / sizeof (i_dls_si[0])) @@ -67,9 +70,19 @@ static mac_stat_info_t i_dls_si[] = { */ static int -i_dls_stat_update(kstat_t *ksp, int rw) +i_dls_mac_stat_update(kstat_t *ksp, int rw) { dls_vlan_t *dvp = ksp->ks_private; + + return (dls_stat_update(ksp, dvp, rw)); +} + +/* + * Exported functions. + */ +int +dls_stat_update(kstat_t *ksp, dls_vlan_t *dvp, int rw) +{ dls_link_t *dlp = dvp->dv_dlp; kstat_named_t *knp; uint_t i; @@ -100,40 +113,37 @@ i_dls_stat_update(kstat_t *ksp, int rw) knp++; } + /* + * Ethernet specific kstat "link_duplex" + */ + if (dlp->dl_mip->mi_nativemedia != DL_ETHER) { + knp->value.ui32 = LINK_DUPLEX_UNKNOWN; + } else { + val = mac_stat_get(dlp->dl_mh, ETHER_STAT_LINK_DUPLEX); + knp->value.ui32 = (uint32_t)val; + } + knp++; knp->value.ui32 = dlp->dl_unknowns; dls_mac_rele(dlp); return (0); } -/* - * Exported functions. - */ - -void -dls_mac_stat_create(dls_vlan_t *dvp) +int +dls_stat_create(const char *module, int instance, const char *name, + int (*update)(struct kstat *, int), void *private, kstat_t **kspp) { - dls_link_t *dlp = dvp->dv_dlp; - char module[IFNAMSIZ]; - uint_t instance; - kstat_t *ksp; - kstat_named_t *knp; - uint_t i; - int err; - - if (dls_mac_hold(dlp) != 0) - return; - - err = ddi_parse(dvp->dv_name, module, &instance); - ASSERT(err == DDI_SUCCESS); + kstat_t *ksp; + kstat_named_t *knp; + uint_t i; - if ((ksp = kstat_create(module, instance, NULL, "net", - KSTAT_TYPE_NAMED, STAT_INFO_COUNT + 1, 0)) == NULL) - goto done; + if ((ksp = kstat_create(module, instance, name, "net", + KSTAT_TYPE_NAMED, STAT_INFO_COUNT + 2, 0)) == NULL) { + return (EINVAL); + } - ksp->ks_update = i_dls_stat_update; - ksp->ks_private = (void *)dvp; - dvp->dv_ksp = ksp; + ksp->ks_update = update; + ksp->ks_private = private; knp = (kstat_named_t *)ksp->ks_data; for (i = 0; i < STAT_INFO_COUNT; i++) { @@ -142,16 +152,51 @@ dls_mac_stat_create(dls_vlan_t *dvp) knp++; } + kstat_named_init(knp++, "link_duplex", KSTAT_DATA_UINT32); kstat_named_init(knp, "unknowns", KSTAT_DATA_UINT32); - kstat_install(ksp); -done: - dls_mac_rele(dlp); + *kspp = ksp; + return (0); +} + +void +dls_mac_stat_create(dls_vlan_t *dvp) +{ + kstat_t *ksp = NULL; + major_t major; + + /* + * Create the legacy kstats to provide backward compatibility. + * These kstats need to be created even when this link does not + * have a link name, i.e., when the VLAN is accessed using its + * /dev node. + * + * Note that we only need to create the legacy kstats for GLDv3 + * physical links, aggregation links which are created using + * the 'key' option, and any VLAN links created over them. + * This can be determined by checking its dv_ppa. + */ + ASSERT(dvp->dv_ksp == NULL); + if (dvp->dv_ppa >= MAC_MAX_MINOR) + return; + + major = getmajor(dvp->dv_dev); + ASSERT(GLDV3_DRV(major) && (dvp->dv_ksp == NULL)); + + if (dls_stat_create(ddi_major_to_name(major), + dvp->dv_id * 1000 + dvp->dv_ppa, NULL, + i_dls_mac_stat_update, dvp, &ksp) != 0) { + return; + } + ASSERT(ksp != NULL); + dvp->dv_ksp = ksp; } void dls_mac_stat_destroy(dls_vlan_t *dvp) { - kstat_delete(dvp->dv_ksp); - dvp->dv_ksp = NULL; + if (dvp->dv_ksp != NULL) { + kstat_delete(dvp->dv_ksp); + dvp->dv_ksp = NULL; + } } diff --git a/usr/src/uts/common/io/dls/dls_vlan.c b/usr/src/uts/common/io/dls/dls_vlan.c index 2fcf435a3d..9df000e86a 100644 --- a/usr/src/uts/common/io/dls/dls_vlan.c +++ b/usr/src/uts/common/io/dls/dls_vlan.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. */ @@ -31,16 +31,14 @@ #include <sys/types.h> #include <sys/sysmacros.h> -#include <sys/atomic.h> -#include <sys/mkdev.h> #include <sys/modhash.h> +#include <sys/stat.h> #include <sys/kstat.h> #include <sys/vlan.h> #include <sys/mac.h> #include <sys/ctype.h> #include <sys/dls.h> #include <sys/dls_impl.h> -#include <sys/dld.h> static kmem_cache_t *i_dls_vlan_cachep; static mod_hash_t *i_dls_vlan_hash; @@ -48,10 +46,6 @@ static mod_hash_t *i_dls_vlan_dev_hash; static krwlock_t i_dls_vlan_lock; static uint_t i_dls_vlan_count; -static vmem_t *minor_arenap; -#define MINOR_TO_PTR(minor) ((void *)(uintptr_t)(minor)) -#define PTR_TO_MINOR(ptr) ((minor_t)(uintptr_t)(ptr)) - #define VLAN_HASHSZ 67 /* prime */ /* @@ -62,8 +56,10 @@ static vmem_t *minor_arenap; static int i_dls_vlan_constructor(void *buf, void *arg, int kmflag) { - bzero(buf, sizeof (dls_vlan_t)); + dls_vlan_t *dvp = buf; + bzero(buf, sizeof (dls_vlan_t)); + mutex_init(&dvp->dv_lock, NULL, MUTEX_DEFAULT, NULL); return (0); } @@ -71,15 +67,16 @@ i_dls_vlan_constructor(void *buf, void *arg, int kmflag) static void i_dls_vlan_destructor(void *buf, void *arg) { - dls_vlan_t *dvp = (dls_vlan_t *)buf; + dls_vlan_t *dvp = buf; ASSERT(dvp->dv_ref == 0); + ASSERT(dvp->dv_zone_ref == 0); + mutex_destroy(&dvp->dv_lock); } /* * Module initialization functions. */ - void dls_vlan_init(void) { @@ -92,29 +89,20 @@ dls_vlan_init(void) ASSERT(i_dls_vlan_cachep != NULL); /* - * Create a hash table, keyed by name, of dls_vlan_t. + * Create a hash table, keyed by dv_spa, of dls_vlan_t. */ i_dls_vlan_hash = mod_hash_create_extended("dls_vlan_hash", VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + /* - * Create a second hash table, keyed by minor, of dls_vlan_t. - * The number of the hash slots is the same. + * Create a hash table, keyed by dv_dev, of dls_vlan_t. */ - i_dls_vlan_dev_hash = mod_hash_create_idhash("dls_vlan_dev_hash", - VLAN_HASHSZ, mod_hash_null_valdtor); + i_dls_vlan_dev_hash = mod_hash_create_ptrhash("dls_vlan_dev_hash", + VLAN_HASHSZ, mod_hash_null_valdtor, sizeof (dev_t)); + rw_init(&i_dls_vlan_lock, NULL, RW_DEFAULT, NULL); i_dls_vlan_count = 0; - - /* - * Allocate a vmem arena to manage minor numbers. The range of the - * arena will be from DLD_MAX_MINOR + 1 to MAXMIN (maximum legal - * minor number). - */ - minor_arenap = vmem_create("dls_minor_arena", - MINOR_TO_PTR(DLD_MAX_MINOR + 1), MAXMIN, 1, NULL, NULL, NULL, 0, - VM_SLEEP | VMC_IDENTIFIER); - ASSERT(minor_arenap != NULL); } int @@ -134,8 +122,6 @@ dls_vlan_fini(void) * Destroy the kmem_cache. */ kmem_cache_destroy(i_dls_vlan_cachep); - - vmem_destroy(minor_arenap); return (0); } @@ -143,167 +129,268 @@ dls_vlan_fini(void) * Exported functions. */ +/* + * If vid is VLAN_ID_NONE, then the minor_t to access this dls_vlan_t is + * ppa + 1, otherwise, we need to allocate the minor_t in this function. + * + * If ppa is greater than DLS_MAX_PPA, it means that we do not need to create + * the VLAN minor node for this MAC, as this MAC is (a) a legacy device, (b) + * an aggr created without the "key" argument, or (c) a new type of link + * whose ppa is allocated by mac_minor_hold() in mac_register(). + */ int -dls_vlan_create(const char *vlanname, const char *macname, uint16_t vid) +dls_vlan_create(const char *macname, uint16_t vid, boolean_t force) { + char node[MAXPATHLEN]; + char spa[MAXSPALEN]; + char *driver; dls_link_t *dlp; dls_vlan_t *dvp; - int err; - uint_t len; + minor_t minor = 0; + mac_handle_t mh; + int ppa; + dev_info_t *dip; + uint32_t margin = VLAN_TAGSZ; + int err = 0; + + if ((err = mac_open(macname, &mh)) != 0) + return (err); /* - * Check to see the name is legal. It must be less than IFNAMSIZ - * characters in length and must terminate with a digit (before the - * NUL, of course). + * First check whether VLANs are able to be created on this MAC. */ - len = strlen(vlanname); - if (len == 0 || len >= IFNAMSIZ) - return (EINVAL); - - if (!isdigit(vlanname[len - 1])) - return (EINVAL); + if (vid != VLAN_ID_NONE) { + if ((mac_info(mh)->mi_media != DL_ETHER) || + (mac_info(mh)->mi_nativemedia != DL_ETHER)) { + mac_close(mh); + return (EINVAL); + } + if (!force && + ((err = mac_margin_add(mh, &margin, B_FALSE)) != 0)) { + mac_close(mh); + return (err); + } + } /* * Get a reference to a dls_link_t representing the MAC. This call * will create one if necessary. */ - if ((err = dls_link_hold(macname, &dlp)) != 0) + if ((err = dls_link_hold(macname, &dlp)) != 0) { + if (vid != VLAN_ID_NONE && !force) + VERIFY(mac_margin_remove(mh, margin) == 0); + mac_close(mh); return (err); + } + + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + /* + * Try to find this VLAN in i_dls_vlan_hash first. The spa + * is in the <macname/vid> form. + */ + (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); + if ((err = mod_hash_find(i_dls_vlan_hash, + (mod_hash_key_t)spa, (mod_hash_val_t)&dvp)) == 0) { + err = EEXIST; + goto fail; + } + + ppa = mac_minor(mh) - 1; + dip = mac_devinfo_get(mh); + + if (vid == VLAN_ID_NONE) { + /* + * Derives minor number directly from non-VLAN link's PPA. + */ + minor = ppa + 1; + } else if ((minor = mac_minor_hold(B_TRUE)) == 0) { + /* + * Allocate minor number from minor_arenap for VLANs. + */ + err = ENOMEM; + goto fail; + } /* - * Allocate a new dls_vlan_t. + * First create its minor node for non-legacy links, including VLANs + * and non-VLANs. This is for /dev nodes backward compatibility. */ + if (vid != VLAN_ID_NONE && ppa < MAC_MAX_MINOR) { + + driver = (char *)ddi_driver_name(dip); + + /* Create a style-1 DLPI device */ + (void) snprintf(node, MAXPATHLEN, "%s%d", driver, + vid * 1000 + ppa); + if (ddi_create_minor_node(dip, node, S_IFCHR, minor, + DDI_NT_NET, 0) != DDI_SUCCESS) { + err = EINVAL; + goto fail; + } + } + dvp = kmem_cache_alloc(i_dls_vlan_cachep, KM_SLEEP); - (void) strlcpy(dvp->dv_name, vlanname, sizeof (dvp->dv_name)); dvp->dv_id = vid; dvp->dv_dlp = dlp; + dvp->dv_dev = makedevice(ddi_driver_major(dip), minor); + dvp->dv_dip = dip; + dvp->dv_ppa = ppa; + dvp->dv_force = force; + dvp->dv_ref = 0; + dvp->dv_zone_ref = 0; + dvp->dv_zid = GLOBAL_ZONEID; + (void) strlcpy(dvp->dv_spa, spa, MAXSPALEN); + dls_mac_stat_create(dvp); + + err = mod_hash_insert(i_dls_vlan_hash, + (mod_hash_key_t)dvp->dv_spa, (mod_hash_val_t)dvp); + ASSERT(err == 0); + + err = mod_hash_insert(i_dls_vlan_dev_hash, + (mod_hash_key_t)dvp->dv_dev, (mod_hash_val_t)dvp); + ASSERT(err == 0); + + i_dls_vlan_count++; + rw_exit(&i_dls_vlan_lock); /* - * Insert the entry into the table. + * Hold the underlying MAC for VLANs to keep the margin request. + * We cannot hold the mac for non-VLANs, because a reference would + * prevent the device from detaching. */ - rw_enter(&i_dls_vlan_lock, RW_WRITER); + if (vid != VLAN_ID_NONE) + VERIFY(dls_mac_hold(dvp->dv_dlp) == 0); - if ((err = mod_hash_insert(i_dls_vlan_hash, - (mod_hash_key_t)dvp->dv_name, (mod_hash_val_t)dvp)) != 0) { - kmem_cache_free(i_dls_vlan_cachep, dvp); - dls_link_rele(dlp); - err = EEXIST; - goto done; - } - i_dls_vlan_count++; + mac_close(mh); + return (0); -done: +fail: rw_exit(&i_dls_vlan_lock); + if (vid != VLAN_ID_NONE && minor != 0) + mac_minor_rele(minor); + dls_link_rele(dlp); + if (vid != VLAN_ID_NONE && !force) + VERIFY(mac_margin_remove(mh, margin) == 0); + mac_close(mh); return (err); } int -dls_vlan_destroy(const char *name) +dls_vlan_destroy(const char *macname, uint16_t vid) { - int err; + char spa[MAXSPALEN]; dls_vlan_t *dvp; - dls_link_t *dlp; mod_hash_val_t val; + int err; /* - * Find the dls_vlan_t in the global hash table. + * Try to find this VLAN in i_dls_vlan_hash first. The spa + * is in the <macname/vid> form. */ + (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); + rw_enter(&i_dls_vlan_lock, RW_WRITER); - err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, - (mod_hash_val_t *)&dvp); - if (err != 0) { - err = ENOENT; - goto done; + if ((err = mod_hash_find(i_dls_vlan_hash, + (mod_hash_key_t)spa, (mod_hash_val_t)&dvp)) != 0) { + rw_exit(&i_dls_vlan_lock); + return (ENOENT); } /* * Check to see if it is referenced by any dls_impl_t. */ if (dvp->dv_ref != 0) { - err = EBUSY; - goto done; + rw_exit(&i_dls_vlan_lock); + return (EBUSY); } + ASSERT(dvp->dv_zone_ref == 0); + /* * Remove and destroy the hash table entry. */ - err = mod_hash_remove(i_dls_vlan_hash, (mod_hash_key_t)name, - (mod_hash_val_t *)&val); + err = mod_hash_remove(i_dls_vlan_hash, + (mod_hash_key_t)dvp->dv_spa, (mod_hash_val_t *)&val); ASSERT(err == 0); ASSERT(dvp == (dls_vlan_t *)val); + err = mod_hash_remove(i_dls_vlan_dev_hash, + (mod_hash_key_t)dvp->dv_dev, (mod_hash_val_t *)&val); + ASSERT(err == 0); + ASSERT(dvp == (dls_vlan_t *)val); + + if (vid != VLAN_ID_NONE && dvp->dv_ppa < MAC_MAX_MINOR) { + char node[MAXPATHLEN]; + char *driver; + + /* + * Remove the minor nodes for this link. + */ + driver = (char *)ddi_driver_name(dvp->dv_dip); + (void) snprintf(node, MAXPATHLEN, "%s%d", driver, + vid * 1000 + dvp->dv_ppa); + ddi_remove_minor_node(dvp->dv_dip, node); + } + + dls_mac_stat_destroy(dvp); + ASSERT(i_dls_vlan_count > 0); i_dls_vlan_count--; + rw_exit(&i_dls_vlan_lock); + + if (vid != VLAN_ID_NONE) { + if (!dvp->dv_force) { + (void) mac_margin_remove(dvp->dv_dlp->dl_mh, + VLAN_TAGSZ); + } + dls_mac_rele(dvp->dv_dlp); + } /* - * Save a reference to dv_dlp before freeing the dls_vlan_t back - * to the cache. + * Release minor to dls_minor_arenap for VLANs */ - dlp = dvp->dv_dlp; - kmem_cache_free(i_dls_vlan_cachep, dvp); + if (vid != VLAN_ID_NONE) + mac_minor_rele(getminor(dvp->dv_dev)); /* * Release the dls_link_t. This will destroy the dls_link_t and * release the MAC if there are no more dls_vlan_t. */ - dls_link_rele(dlp); -done: - rw_exit(&i_dls_vlan_lock); - return (err); + dls_link_rele(dvp->dv_dlp); + kmem_cache_free(i_dls_vlan_cachep, dvp); + return (0); } int -dls_vlan_hold(const char *name, dls_vlan_t **dvpp, boolean_t create_vlan) +dls_vlan_hold(const char *macname, uint16_t vid, dls_vlan_t **dvpp, + boolean_t force, boolean_t create_vlan) { - int err; + char spa[MAXSPALEN]; dls_vlan_t *dvp; - dls_link_t *dlp; - boolean_t vlan_created = B_FALSE; - uint16_t vid; - uint_t mac_ppa; + boolean_t vlan_created; + int err = 0; + + (void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid); again: rw_enter(&i_dls_vlan_lock, RW_WRITER); - - err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, - (mod_hash_val_t *)&dvp); - if (err != 0) { - char mac[MAXNAMELEN]; - uint_t index, len; + if ((err = mod_hash_find(i_dls_vlan_hash, + (mod_hash_key_t)spa, (mod_hash_val_t)&dvp)) != 0) { ASSERT(err == MH_ERR_NOTFOUND); vlan_created = B_FALSE; - if (!create_vlan) { - err = ENOENT; - goto done; + if (!create_vlan || vid == VLAN_ID_NONE) { + rw_exit(&i_dls_vlan_lock); + return (ENOENT); } - - /* - * Only create tagged vlans on demand. - * Note that if we get here, 'name' must be a sane - * value because it must have been derived from - * ddi_major_to_name(). - */ - if (ddi_parse(name, mac, &index) != DDI_SUCCESS || - (vid = DLS_PPA2VID(index)) == VLAN_ID_NONE || - vid > VLAN_ID_MAX) { - err = EINVAL; - goto done; - } - - mac_ppa = (uint_t)DLS_PPA2INST(index); - - len = strlen(mac); - ASSERT(len < MAXNAMELEN); - (void) snprintf(mac + len, MAXNAMELEN - len, "%d", mac_ppa); rw_exit(&i_dls_vlan_lock); - if ((err = dls_vlan_create(name, mac, vid)) != 0) { - rw_enter(&i_dls_vlan_lock, RW_WRITER); - goto done; - } + err = dls_vlan_create(macname, vid, force); + if ((err != 0) && (err != EEXIST)) + return (err); /* * At this point someone else could do a dls_vlan_hold and @@ -311,362 +398,164 @@ again: * destroyed. This will at worst cause us to spin a few * times. */ - vlan_created = B_TRUE; + vlan_created = (err != EEXIST); goto again; } - dlp = dvp->dv_dlp; - - if ((err = dls_mac_hold(dlp)) != 0) - goto done; - - /* Create a minor node for this VLAN */ - if (vid != 0 && vlan_created) { - /* A tagged VLAN */ - dvp->dv_minor = dls_minor_hold(B_TRUE); - dvp->dv_ppa = DLS_VIDINST2PPA(vid, mac_ppa); - - err = mod_hash_insert(i_dls_vlan_dev_hash, - (mod_hash_key_t)(uintptr_t)dvp->dv_minor, - (mod_hash_val_t)dvp); - ASSERT(err == 0); - - err = mac_vlan_create(dlp->dl_mh, name, dvp->dv_minor); - - if (err != 0) { - mod_hash_val_t val; - - err = mod_hash_remove(i_dls_vlan_dev_hash, - (mod_hash_key_t)(uintptr_t)dvp->dv_minor, - (mod_hash_val_t *)&val); - ASSERT(err == 0); - ASSERT(dvp == (dls_vlan_t *)val); - - dvp->dv_minor = 0; - dls_mac_rele(dlp); - goto done; - } - } - - /* - * Do not allow the creation of tagged VLAN interfaces on - * non-Ethernet links. Note that we cannot do this check in - * dls_vlan_create() nor in this function prior to the call to - * dls_mac_hold(). The reason is that before we do a - * dls_mac_hold(), we may not have opened the mac, and therefore do - * not know what kind of media the mac represents. In other words, - * dls_mac_hold() assigns the dl_mip of the dls_link_t we're - * interested in. - */ - if (dvp->dv_id != VLAN_ID_NONE && - (dlp->dl_mip->mi_media != DL_ETHER || - dlp->dl_mip->mi_nativemedia != DL_ETHER)) { - dls_mac_rele(dlp); - err = EINVAL; - goto done; - } - - if ((err = mac_start(dlp->dl_mh)) != 0) { - dls_mac_rele(dlp); - goto done; - } - - if (dvp->dv_ref++ == 0) - dls_mac_stat_create(dvp); - - *dvpp = dvp; -done: + dvp->dv_ref++; rw_exit(&i_dls_vlan_lock); - /* - * We could be destroying a vlan created by another thread. This - * is ok because this other thread will just loop back up and - * recreate the vlan. - */ - if (err != 0 && vlan_created) - (void) dls_vlan_destroy(name); - return (err); -} - -void -dls_vlan_rele(dls_vlan_t *dvp) -{ - dls_link_t *dlp; - char name[IFNAMSIZ]; - boolean_t destroy_vlan = B_FALSE; - - rw_enter(&i_dls_vlan_lock, RW_WRITER); - dlp = dvp->dv_dlp; - - /* a minor node has been created for this vlan */ - if (dvp->dv_ref == 1 && dvp->dv_minor > 0) { - int err; - mod_hash_val_t val; - - mac_vlan_remove(dlp->dl_mh, dvp->dv_name); - err = mod_hash_remove(i_dls_vlan_dev_hash, - (mod_hash_key_t)(uintptr_t)dvp->dv_minor, - (mod_hash_val_t *)&val); - ASSERT(err == 0); - ASSERT(dvp == (dls_vlan_t *)val); - dls_minor_rele(dvp->dv_minor); - dvp->dv_minor = 0; - } - - mac_stop(dlp->dl_mh); - dls_mac_rele(dlp); - if (--dvp->dv_ref == 0) { - dls_mac_stat_destroy(dvp); - /* - * Tagged vlans get destroyed when dv_ref drops - * to 0. We need to copy dv_name here because - * dvp could disappear after we drop i_dls_vlan_lock. - */ - if (dvp->dv_id != 0) { - (void) strlcpy(name, dvp->dv_name, IFNAMSIZ); - destroy_vlan = B_TRUE; - } + if ((err = dls_mac_hold(dvp->dv_dlp)) != 0) { + rw_enter(&i_dls_vlan_lock, RW_WRITER); + dvp->dv_ref--; + rw_exit(&i_dls_vlan_lock); + if (vlan_created) + (void) dls_vlan_destroy(macname, vid); + return (err); } - rw_exit(&i_dls_vlan_lock); - if (destroy_vlan) - (void) dls_vlan_destroy(name); -} - -typedef struct dls_vlan_walk_state { - int (*fn)(dls_vlan_t *, void *); - void *arg; - int rc; -} dls_vlan_walk_state_t; - -/*ARGSUSED*/ -static uint_t -dls_vlan_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) -{ - dls_vlan_walk_state_t *statep = arg; - dls_vlan_t *dvp; - dvp = (dls_vlan_t *)val; - statep->rc = statep->fn(dvp, statep->arg); - - return ((statep->rc == 0) ? MH_WALK_CONTINUE : MH_WALK_TERMINATE); -} - -int -dls_vlan_walk(int (*fn)(dls_vlan_t *, void *), void *arg) -{ - dls_vlan_walk_state_t state; - - rw_enter(&i_dls_vlan_lock, RW_READER); - - state.fn = fn; - state.arg = arg; - state.rc = 0; - mod_hash_walk(i_dls_vlan_hash, dls_vlan_walker, (void *)&state); - - rw_exit(&i_dls_vlan_lock); - return (state.rc); + *dvpp = dvp; + return (0); } int -dls_vlan_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) +dls_vlan_hold_by_dev(dev_t dev, dls_vlan_t **dvpp) { dls_vlan_t *dvp; - - if (minor <= DLD_MAX_MINOR) { - *ppa = (t_uscalar_t)minor - 1; - return (0); - } + int err; rw_enter(&i_dls_vlan_lock, RW_WRITER); - - if (mod_hash_find(i_dls_vlan_dev_hash, (mod_hash_key_t)(uintptr_t)minor, - (mod_hash_val_t *)&dvp) != 0) { + if ((err = mod_hash_find(i_dls_vlan_dev_hash, (mod_hash_key_t)dev, + (mod_hash_val_t *)&dvp)) != 0) { + ASSERT(err == MH_ERR_NOTFOUND); rw_exit(&i_dls_vlan_lock); return (ENOENT); } - *ppa = dvp->dv_ppa; + dvp->dv_ref++; rw_exit(&i_dls_vlan_lock); + + if ((err = dls_mac_hold(dvp->dv_dlp)) != 0) { + rw_enter(&i_dls_vlan_lock, RW_WRITER); + dvp->dv_ref--; + rw_exit(&i_dls_vlan_lock); + return (err); + } + + *dvpp = dvp; return (0); } -int -dls_vlan_rele_by_name(const char *name) +/* + * Free the dvp if this is a VLAN and this is the last reference. + */ +void +dls_vlan_rele(dls_vlan_t *dvp) { - dls_vlan_t *dvp; - dls_link_t *dlp; + char macname[MAXNAMELEN]; + uint16_t vid; boolean_t destroy_vlan = B_FALSE; - rw_enter(&i_dls_vlan_lock, RW_WRITER); + dls_mac_rele(dvp->dv_dlp); - if (mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, - (mod_hash_val_t *)&dvp) != 0) { + rw_enter(&i_dls_vlan_lock, RW_WRITER); + if (--dvp->dv_ref != 0) { rw_exit(&i_dls_vlan_lock); - return (ENOENT); + return; } - dlp = dvp->dv_dlp; - - /* a minor node has been created for this vlan */ - if (dvp->dv_ref == 1 && dvp->dv_minor > 0) { - int err; - mod_hash_val_t val; - - mac_vlan_remove(dlp->dl_mh, dvp->dv_name); - err = mod_hash_remove(i_dls_vlan_dev_hash, - (mod_hash_key_t)(uintptr_t)dvp->dv_minor, - (mod_hash_val_t *)&val); - ASSERT(err == 0); - ASSERT(dvp == (dls_vlan_t *)val); - dls_minor_rele(dvp->dv_minor); - dvp->dv_minor = 0; - } - - mac_stop(dlp->dl_mh); - dls_mac_rele(dlp); - if (--dvp->dv_ref == 0) { - dls_mac_stat_destroy(dvp); - /* Tagged vlans get destroyed when dv_ref drops to 0. */ - if (dvp->dv_id != 0) - destroy_vlan = B_TRUE; + if (dvp->dv_id != VLAN_ID_NONE) { + destroy_vlan = B_TRUE; + (void) strncpy(macname, dvp->dv_dlp->dl_name, MAXNAMELEN); + vid = dvp->dv_id; } rw_exit(&i_dls_vlan_lock); - if (destroy_vlan) - (void) dls_vlan_destroy(name); - return (0); + if (destroy_vlan) + (void) dls_vlan_destroy(macname, vid); } -typedef struct dls_vlan_dip_state { - minor_t minor; - dev_info_t *dip; -} dls_vlan_dip_k_state_t; - -static int -dls_vlan_devinfo(dls_vlan_t *dvp, void *arg) +int +dls_vlan_setzid(const char *mac, uint16_t vid, zoneid_t zid) { - dls_vlan_dip_k_state_t *statep = arg; - - if (dvp->dv_minor == statep->minor) { - dls_link_t *dlp = dvp->dv_dlp; + dls_vlan_t *dvp; + int err; + zoneid_t old_zid; - if (dls_mac_hold(dlp) != 0) - return (0); - statep->dip = mac_devinfo_get(dlp->dl_mh); - dls_mac_rele(dlp); + if ((err = dls_vlan_hold(mac, vid, &dvp, B_FALSE, B_TRUE)) != 0) + return (err); - return (1); + mutex_enter(&dvp->dv_lock); + if ((old_zid = dvp->dv_zid) == zid) { + mutex_exit(&dvp->dv_lock); + goto done; } - return (0); -} - -dev_info_t * -dls_vlan_finddevinfo(dev_t dev) -{ - dls_vlan_dip_k_state_t vlan_state; - - vlan_state.minor = getminor(dev); - vlan_state.dip = NULL; - - (void) dls_vlan_walk(dls_vlan_devinfo, &vlan_state); - return (vlan_state.dip); -} - -/* - * Allocate a new minor number. - */ -minor_t -dls_minor_hold(boolean_t sleep) -{ - /* - * Grab a value from the arena. - */ - return (PTR_TO_MINOR(vmem_alloc(minor_arenap, 1, - (sleep) ? VM_SLEEP : VM_NOSLEEP))); -} - -/* - * Release a previously allocated minor number. - */ -void -dls_minor_rele(minor_t minor) -{ /* - * Return the value to the arena. + * Check whether this dvp is used by its own zones, if yes, + * we cannot change its zoneid. */ - vmem_free(minor_arenap, MINOR_TO_PTR(minor), 1); -} - -int -dls_vlan_setzoneid(char *name, zoneid_t zid, boolean_t docheck) -{ - int err; - dls_vlan_t *dvp; - - if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) - return (err); + if (dvp->dv_zone_ref != 0) { + mutex_exit(&dvp->dv_lock); + err = EBUSY; + goto done; + } - rw_enter(&i_dls_vlan_lock, RW_WRITER); - if (!docheck) { + if (zid == GLOBAL_ZONEID) { + /* + * Move the link from the local zone to the global zone, + * and release the reference to this link. At the same time + * reset the link's active state so that an aggregation is + * allowed to be created over it. + */ dvp->dv_zid = zid; - } else { - dls_impl_t *dip; - - for (dip = dvp->dv_impl_list; dip != NULL; - dip = dip->di_next_impl) - if (dip->di_zid != zid) - break; - if (dip == NULL) - dvp->dv_zid = zid; - else + mutex_exit(&dvp->dv_lock); + dls_mac_active_clear(dvp->dv_dlp); + dls_vlan_rele(dvp); + goto done; + } else if (old_zid == GLOBAL_ZONEID) { + /* + * Move the link from the global zone to the local zone, + * and hold a reference to this link. Also, set the link + * to the "active" state so that the global zone is + * not able to create an aggregation over this link. + * TODO: revisit once we allow creating aggregations + * within a local zone. + */ + if (!dls_mac_active_set(dvp->dv_dlp)) { + mutex_exit(&dvp->dv_lock); err = EBUSY; + goto done; + } + dvp->dv_zid = zid; + mutex_exit(&dvp->dv_lock); + return (0); + } else { + /* + * Move the link from a local zone to another local zone. + */ + dvp->dv_zid = zid; + mutex_exit(&dvp->dv_lock); } - rw_exit(&i_dls_vlan_lock); +done: dls_vlan_rele(dvp); return (err); } -int -dls_vlan_getzoneid(char *name, zoneid_t *zidp) +/* + * Find dev_info_t based on the minor node of the link. + */ +dev_info_t * +dls_finddevinfo(dev_t dev) { - int err; dls_vlan_t *dvp; + dev_info_t *dip; - if ((err = dls_vlan_hold(name, &dvp, B_FALSE)) != 0) - return (err); - - *zidp = dvp->dv_zid; + if (dls_vlan_hold_by_dev(dev, &dvp) != 0) + return (NULL); + dip = dvp->dv_dip; dls_vlan_rele(dvp); - - return (0); -} - -void -dls_vlan_add_impl(dls_vlan_t *dvp, dls_impl_t *dip) -{ - rw_enter(&i_dls_vlan_lock, RW_WRITER); - dip->di_next_impl = dvp->dv_impl_list; - dvp->dv_impl_list = dip; - rw_exit(&i_dls_vlan_lock); -} - - -void -dls_vlan_remove_impl(dls_vlan_t *dvp, dls_impl_t *dip) -{ - dls_impl_t **pp; - dls_impl_t *p; - - rw_enter(&i_dls_vlan_lock, RW_WRITER); - for (pp = &dvp->dv_impl_list; (p = *pp) != NULL; - pp = &(p->di_next_impl)) - if (p == dip) - break; - ASSERT(p != NULL); - *pp = p->di_next_impl; - p->di_next_impl = NULL; - rw_exit(&i_dls_vlan_lock); + return (dip); } diff --git a/usr/src/uts/common/io/dmfe/dmfe_main.c b/usr/src/uts/common/io/dmfe/dmfe_main.c index 74ef877524..93653c95bb 100644 --- a/usr/src/uts/common/io/dmfe/dmfe_main.c +++ b/usr/src/uts/common/io/dmfe/dmfe_main.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. */ @@ -3097,6 +3097,7 @@ dmfe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) macp->m_callbacks = &dmfe_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; /* * Finally, we're ready to register ourselves with the MAC layer diff --git a/usr/src/uts/common/io/e1000g/e1000g_main.c b/usr/src/uts/common/io/e1000g/e1000g_main.c index e572e708f1..484eb0c2e8 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_main.c +++ b/usr/src/uts/common/io/e1000g/e1000g_main.c @@ -564,6 +564,7 @@ e1000g_register_mac(struct e1000g *Adapter) hw->mac.max_frame_size - 256 : (hw->mac.max_frame_size != ETHERMAX) ? hw->mac.max_frame_size - 24 : ETHERMTU; + mac->m_margin = VLAN_TAGSZ; err = mac_register(mac, &Adapter->mh); mac_free(mac); diff --git a/usr/src/uts/common/io/gld.c b/usr/src/uts/common/io/gld.c index 240d81c25e..d14b0eff00 100644 --- a/usr/src/uts/common/io/gld.c +++ b/usr/src/uts/common/io/gld.c @@ -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. */ @@ -212,8 +212,7 @@ extern void gld_sr_dump(gld_mac_info_t *); uint32_t gld_global_options = GLD_OPT_NO_ETHRXSNAP; /* - * VLANs are only supported on ethernet devices that manipulate VLAN headers - * themselves. + * The device is of DL_ETHER type and is able to support VLAN by itself. */ #define VLAN_CAPABLE(macinfo) \ ((macinfo)->gldm_type == DL_ETHER && \ @@ -655,6 +654,12 @@ gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo) } /* + * Correct margin size if it is not set. + */ + if (VLAN_CAPABLE(macinfo) && (macinfo->gldm_margin == 0)) + macinfo->gldm_margin = VTAG_SIZE; + + /* * For now, only Infiniband drivers can use MDT. Do not add * support for Ethernet, FDDI or TR. */ @@ -2214,7 +2219,6 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) } return (GLD_SUCCESS); - badarg: freemsg(mp); @@ -3396,6 +3400,23 @@ gld_ioctl(queue_t *q, mblk_t *mp) gld_fastpath(gld, q, mp); break; + case DLIOCMARGININFO: { /* margin size */ + int err; + + if ((macinfo = gld->gld_mac_info) == NULL) { + miocnak(q, mp, 0, EINVAL); + break; + } + + if ((err = miocpullup(mp, sizeof (uint32_t))) != 0) { + miocnak(q, mp, 0, err); + break; + } + + *((uint32_t *)mp->b_cont->b_rptr) = macinfo->gldm_margin; + miocack(q, mp, sizeof (uint32_t), 0); + break; + } default: macinfo = gld->gld_mac_info; if (macinfo == NULL || macinfo->gldm_ioctl == NULL) { diff --git a/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.c b/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.c index 6e6a937114..69feb36606 100644 --- a/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.c +++ b/usr/src/uts/common/io/ib/clients/rds/rds_ioctl.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. */ @@ -87,57 +87,6 @@ rds_do_ip_ioctl(int cmd, int len, caddr_t arg) return (err); } -static int -rds_dl_info(ldi_handle_t lh, dl_info_ack_t *info) -{ - dl_info_req_t *info_req; - union DL_primitives *dl_prim; - mblk_t *mp; - k_sigset_t smask; - int error; - - if ((mp = allocb(sizeof (dl_info_req_t), BPRI_MED)) == NULL) { - return (ENOMEM); - } - - mp->b_datap->db_type = M_PROTO; - - info_req = (dl_info_req_t *)(uintptr_t)mp->b_wptr; - mp->b_wptr += sizeof (dl_info_req_t); - info_req->dl_primitive = DL_INFO_REQ; - - sigintr(&smask, 0); - if ((error = ldi_putmsg(lh, mp)) != 0) { - sigunintr(&smask); - return (error); - } - if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { - sigunintr(&smask); - return (error); - } - sigunintr(&smask); - - dl_prim = (union DL_primitives *)(uintptr_t)mp->b_rptr; - switch (dl_prim->dl_primitive) { - case DL_INFO_ACK: - if (((uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr) < - sizeof (dl_info_ack_t)) { - error = -1; - } else { - *info = *(dl_info_ack_t *)(uintptr_t)mp->b_rptr; - error = 0; - } - break; - default: - error = -1; - break; - } - - freemsg(mp); - return (error); -} - - /* * Return 0 if the interface is IB. * Return error (>0) if any error is encountered during processing. @@ -153,6 +102,7 @@ rds_is_ib_interface(char *name) dl_info_ack_t info; int ret = 0; int i; + k_sigset_t smask; /* * ibd devices are only style 2 devices @@ -186,7 +136,9 @@ rds_is_ib_interface(char *name) return (ret); } - ret = rds_dl_info(lh, &info); + sigintr(&smask, 0); + ret = dl_info(lh, &info, NULL, NULL, NULL); + sigunintr(&smask); (void) ldi_close(lh, FREAD|FWRITE, kcred); if (ret != 0) { return (ret); diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c index 954c12d05a..3e19c58bef 100644 --- a/usr/src/uts/common/io/igb/igb_main.c +++ b/usr/src/uts/common/io/igb/igb_main.c @@ -633,6 +633,7 @@ igb_register_mac(igb_t *igb) mac->m_min_sdu = 0; mac->m_max_sdu = igb->max_frame_size - sizeof (struct ether_vlan_header) - ETHERFCSL; + mac->m_margin = VLAN_TAGSZ; status = mac_register(mac, &igb->mac_hdl); diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index d093353ba3..d12bfdf021 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.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. */ @@ -32,15 +32,18 @@ #include <sys/types.h> #include <sys/conf.h> +#include <sys/id_space.h> #include <sys/stat.h> +#include <sys/mkdev.h> #include <sys/stream.h> #include <sys/strsun.h> #include <sys/strsubr.h> #include <sys/dlpi.h> +#include <sys/dls.h> #include <sys/modhash.h> +#include <sys/vlan.h> #include <sys/mac.h> #include <sys/mac_impl.h> -#include <sys/dls.h> #include <sys/dld.h> #include <sys/modctl.h> #include <sys/fs/dv_node.h> @@ -58,6 +61,8 @@ static mod_hash_t *i_mac_impl_hash; krwlock_t i_mac_impl_lock; uint_t i_mac_impl_count; static kmem_cache_t *mac_vnic_tx_cache; +static id_space_t *minor_ids; +static uint32_t minor_count; #define MACTYPE_KMODDIR "mac" #define MACTYPE_HASHSZ 67 @@ -87,6 +92,7 @@ i_mac_constructor(void *buf, void *arg, int kmflag) mip->mi_linkstate = LINK_STATE_UNKNOWN; rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); + rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL); rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); @@ -107,11 +113,13 @@ i_mac_destructor(void *buf, void *arg) mac_impl_t *mip = buf; ASSERT(mip->mi_ref == 0); + ASSERT(!mip->mi_exclusive); ASSERT(mip->mi_active == 0); ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); ASSERT(mip->mi_devpromisc == 0); ASSERT(mip->mi_promisc == 0); ASSERT(mip->mi_mmap == NULL); + ASSERT(mip->mi_mmrp == NULL); ASSERT(mip->mi_mnfp == NULL); ASSERT(mip->mi_resource_add == NULL); ASSERT(mip->mi_ksp == NULL); @@ -119,6 +127,7 @@ i_mac_destructor(void *buf, void *arg) ASSERT(mip->mi_notify_bits == 0); ASSERT(mip->mi_notify_thread == NULL); + rw_destroy(&mip->mi_gen_lock); rw_destroy(&mip->mi_state_lock); rw_destroy(&mip->mi_data_lock); rw_destroy(&mip->mi_notify_lock); @@ -357,14 +366,26 @@ mac_init(void) MACTYPE_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + + /* + * Allocate an id space to manage minor numbers. The range of the + * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal + * minor number is MAXMIN, but id_t is type of integer and does not + * allow MAXMIN). + */ + minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32); + ASSERT(minor_ids != NULL); + minor_count = 0; } int mac_fini(void) { - if (i_mac_impl_count > 0) + if (i_mac_impl_count > 0 || minor_count > 0) return (EBUSY); + id_space_destroy(minor_ids); + mod_hash_destroy_hash(i_mac_impl_hash); rw_destroy(&i_mac_impl_lock); @@ -379,13 +400,9 @@ mac_fini(void) * Client functions. */ -int -mac_open(const char *macname, mac_handle_t *mhp) +static int +mac_hold(const char *macname, mac_impl_t **pmip) { - char driver[MAXNAMELEN]; - uint_t ddi_instance; - major_t major; - dev_info_t *dip; mac_impl_t *mip; int err; @@ -397,74 +414,170 @@ mac_open(const char *macname, mac_handle_t *mhp) return (EINVAL); /* - * Split the device name into driver and instance components. + * Look up its entry in the global hash table. */ - if (ddi_parse(macname, driver, &ddi_instance) != DDI_SUCCESS) - return (EINVAL); + rw_enter(&i_mac_impl_lock, RW_WRITER); + err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, + (mod_hash_val_t *)&mip); - if ((strcmp(driver, "aggr") == 0) || (strcmp(driver, "vnic") == 0)) - ddi_instance = 0; + if (err != 0) { + rw_exit(&i_mac_impl_lock); + return (ENOENT); + } - /* - * Get the major number of the driver. - */ - if ((major = ddi_name_to_major(driver)) == (major_t)-1) - return (EINVAL); + if (mip->mi_disabled) { + rw_exit(&i_mac_impl_lock); + return (ENOENT); + } - /* - * Hold the given instance to prevent it from being detached. - * This will also attach the instance if it is not currently attached. - * Currently we ensure that mac_register() (called by the driver's - * attach entry point) and all code paths under it cannot possibly - * call mac_open() because this would lead to a recursive attach - * panic. - */ - if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) - return (EINVAL); + if (mip->mi_exclusive) { + rw_exit(&i_mac_impl_lock); + return (EBUSY); + } + + mip->mi_ref++; + rw_exit(&i_mac_impl_lock); + + *pmip = mip; + return (0); +} + +static void +mac_rele(mac_impl_t *mip) +{ + rw_enter(&i_mac_impl_lock, RW_WRITER); + ASSERT(mip->mi_ref != 0); + if (--mip->mi_ref == 0) + ASSERT(!mip->mi_activelink); + rw_exit(&i_mac_impl_lock); +} + +int +mac_hold_exclusive(mac_handle_t mh) +{ + mac_impl_t *mip = (mac_impl_t *)mh; /* * Look up its entry in the global hash table. */ -again: rw_enter(&i_mac_impl_lock, RW_WRITER); - err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, - (mod_hash_val_t *)&mip); - if (err != 0) { - err = ENOENT; - goto failed; + if (mip->mi_disabled) { + rw_exit(&i_mac_impl_lock); + return (ENOENT); } - if (mip->mi_disabled) { + if (mip->mi_ref != 0) { rw_exit(&i_mac_impl_lock); - goto again; + return (EBUSY); } + ASSERT(!mip->mi_exclusive); + mip->mi_ref++; + mip->mi_exclusive = B_TRUE; + rw_exit(&i_mac_impl_lock); + return (0); +} + +void +mac_rele_exclusive(mac_handle_t mh) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + /* + * Look up its entry in the global hash table. + */ + rw_enter(&i_mac_impl_lock, RW_WRITER); + ASSERT(mip->mi_ref == 1 && mip->mi_exclusive); + mip->mi_ref--; + mip->mi_exclusive = B_FALSE; rw_exit(&i_mac_impl_lock); +} + +int +mac_open(const char *macname, mac_handle_t *mhp) +{ + mac_impl_t *mip; + int err; + + /* + * Look up its entry in the global hash table. + */ + if ((err = mac_hold(macname, &mip)) != 0) + return (err); + + rw_enter(&mip->mi_gen_lock, RW_WRITER); + + if ((mip->mi_oref != 0) || + !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { + goto done; + } + /* + * Note that we do not hold i_mac_impl_lock when calling the + * mc_open() callback function to avoid deadlock with the + * i_mac_notify() function. + */ + if ((err = mip->mi_open(mip->mi_driver)) != 0) { + rw_exit(&mip->mi_gen_lock); + mac_rele(mip); + return (err); + } + +done: + mip->mi_oref++; + rw_exit(&mip->mi_gen_lock); *mhp = (mac_handle_t)mip; return (0); +} -failed: - rw_exit(&i_mac_impl_lock); - ddi_release_devi(dip); +int +mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) +{ + dls_dl_handle_t dlh; + int err; + + if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) + return (err); + + if (dls_devnet_vid(dlh) != VLAN_ID_NONE) { + err = EINVAL; + goto done; + } + + err = mac_open(dls_devnet_mac(dlh), mhp); + +done: + dls_devnet_rele_tmp(dlh); return (err); } +int +mac_open_by_linkname(const char *link, mac_handle_t *mhp) +{ + datalink_id_t linkid; + int err; + + if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) + return (err); + return (mac_open_by_linkid(linkid, mhp)); +} + void mac_close(mac_handle_t mh) { mac_impl_t *mip = (mac_impl_t *)mh; - dev_info_t *dip = mip->mi_dip; - rw_enter(&i_mac_impl_lock, RW_WRITER); + rw_enter(&mip->mi_gen_lock, RW_WRITER); - ASSERT(mip->mi_ref != 0); - if (--mip->mi_ref == 0) { - ASSERT(!mip->mi_activelink); + ASSERT(mip->mi_oref != 0); + if (--mip->mi_oref == 0) { + if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) + mip->mi_close(mip->mi_driver); } - ddi_release_devi(dip); - rw_exit(&i_mac_impl_lock); + rw_exit(&mip->mi_gen_lock); + + mac_rele(mip); } const mac_info_t * @@ -479,6 +592,18 @@ mac_devinfo_get(mac_handle_t mh) return (((mac_impl_t *)mh)->mi_dip); } +const char * +mac_name(mac_handle_t mh) +{ + return (((mac_impl_t *)mh)->mi_name); +} + +minor_t +mac_minor(mac_handle_t mh) +{ + return (((mac_impl_t *)mh)->mi_minor); +} + uint64_t mac_stat_get(mac_handle_t mh, uint_t stat) { @@ -751,10 +876,8 @@ mac_unicst_set(mac_handle_t mh, const uint8_t *addr) * This check is necessary otherwise it may call into mac_unicst_set * recursively. */ - if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { - err = 0; + if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) goto done; - } if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) goto done; @@ -838,7 +961,6 @@ mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) err = EPROTO; goto done; } - /* * Disable promiscuous mode on the device if this is the last * enabling. @@ -1248,6 +1370,59 @@ mac_free(mac_register_t *mregp) } /* + * Allocate a minor number. + */ +minor_t +mac_minor_hold(boolean_t sleep) +{ + minor_t minor; + + /* + * Grab a value from the arena. + */ + atomic_add_32(&minor_count, 1); + + if (sleep) + minor = (uint_t)id_alloc(minor_ids); + else + minor = (uint_t)id_alloc_nosleep(minor_ids); + + if (minor == 0) { + atomic_add_32(&minor_count, -1); + return (0); + } + + return (minor); +} + +/* + * Release a previously allocated minor number. + */ +void +mac_minor_rele(minor_t minor) +{ + /* + * Return the value to the arena. + */ + id_free(minor_ids, minor); + atomic_add_32(&minor_count, -1); +} + +uint32_t +mac_no_notification(mac_handle_t mh) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + return (mip->mi_unsup_note); +} + +boolean_t +mac_is_legacy(mac_handle_t mh) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + return (mip->mi_legacy); +} + +/* * mac_register() is how drivers register new MACs with the GLDv3 * framework. The mregp argument is allocated by drivers using the * mac_alloc() function, and can be freed using mac_free() immediately upon @@ -1258,12 +1433,16 @@ mac_free(mac_register_t *mregp) int mac_register(mac_register_t *mregp, mac_handle_t *mhp) { - mac_impl_t *mip; - mactype_t *mtype; - int err = EINVAL; - struct devnames *dnp; - minor_t minor; - boolean_t style1_created = B_FALSE, style2_created = B_FALSE; + mac_impl_t *mip; + mactype_t *mtype; + int err = EINVAL; + struct devnames *dnp = NULL; + uint_t instance; + boolean_t style1_created = B_FALSE; + boolean_t style2_created = B_FALSE; + mac_capab_legacy_t legacy; + char *driver; + minor_t minor = 0; /* Find the required MAC-Type plugin. */ if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) @@ -1277,23 +1456,59 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) */ mip->mi_disabled = B_TRUE; - mip->mi_drvname = ddi_driver_name(mregp->m_dip); /* - * Some drivers such as aggr need to register multiple MACs. Such - * drivers must supply a non-zero "instance" argument so that each - * MAC can be assigned a unique MAC name and can have unique - * kstats. - */ - mip->mi_instance = ((mregp->m_instance == 0) ? - ddi_get_instance(mregp->m_dip) : mregp->m_instance); + * When a mac is registered, the m_instance field can be set to: + * + * 0: Get the mac's instance number from m_dip. + * This is usually used for physical device dips. + * + * [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number. + * For example, when an aggregation is created with the key option, + * "key" will be used as the instance number. + * + * -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1]. + * This is often used when a MAC of a virtual link is registered + * (e.g., aggregation when "key" is not specified, or vnic). + * + * Note that the instance number is used to derive the mi_minor field + * of mac_impl_t, which will then be used to derive the name of kstats + * and the devfs nodes. The first 2 cases are needed to preserve + * backward compatibility. + */ + switch (mregp->m_instance) { + case 0: + instance = ddi_get_instance(mregp->m_dip); + break; + case ((uint_t)-1): + minor = mac_minor_hold(B_TRUE); + if (minor == 0) { + err = ENOSPC; + goto fail; + } + instance = minor - 1; + break; + default: + instance = mregp->m_instance; + if (instance >= MAC_MAX_MINOR) { + err = EINVAL; + goto fail; + } + break; + } + + mip->mi_minor = (minor_t)(instance + 1); + mip->mi_dip = mregp->m_dip; + + driver = (char *)ddi_driver_name(mip->mi_dip); /* Construct the MAC name as <drvname><instance> */ (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", - mip->mi_drvname, mip->mi_instance); + driver, instance); mip->mi_driver = mregp->m_driver; mip->mi_type = mtype; + mip->mi_margin = mregp->m_margin; mip->mi_info.mi_media = mtype->mt_type; mip->mi_info.mi_nativemedia = mtype->mt_nativetype; mip->mi_info.mi_sdu_min = mregp->m_min_sdu; @@ -1374,20 +1589,39 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) } mip->mi_callbacks = mregp->m_callbacks; - mip->mi_dip = mregp->m_dip; - /* * Set up the possible transmit routines. */ mip->mi_txinfo.mt_fn = mip->mi_tx; mip->mi_txinfo.mt_arg = mip->mi_driver; + mip->mi_legacy = mac_capab_get((mac_handle_t)mip, + MAC_CAPAB_LEGACY, &legacy); + + if (mip->mi_legacy) { + /* + * Legacy device. Messages being sent will be looped back + * by the underlying driver. Therefore the txloop function + * pointer is the same as the tx function pointer. + */ + mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn; + mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg; + mip->mi_unsup_note = legacy.ml_unsup_note; + mip->mi_phy_dev = legacy.ml_dev; + } else { + /* + * Normal device. The framework needs to do the loopback. + */ + mip->mi_txloopinfo.mt_fn = mac_txloop; + mip->mi_txloopinfo.mt_arg = mip; + mip->mi_unsup_note = 0; + mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip), + ddi_get_instance(mip->mi_dip) + 1); + } + mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx; mip->mi_vnic_txinfo.mt_arg = mip; - mip->mi_txloopinfo.mt_fn = mac_txloop; - mip->mi_txloopinfo.mt_arg = mip; - mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop; mip->mi_vnic_txloopinfo.mt_arg = mip; @@ -1404,39 +1638,31 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) */ mac_stat_create(mip); - err = EEXIST; - /* Create a style-2 DLPI device */ - if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, - S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) - goto fail; - style2_created = B_TRUE; - - /* Create a style-1 DLPI device */ - minor = (minor_t)mip->mi_instance + 1; - if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, - DDI_NT_NET, 0) != DDI_SUCCESS) - goto fail; - style1_created = B_TRUE; - - /* - * Create a link for this MAC. The link name will be the same as - * the MAC name. - */ - err = dls_create(mip->mi_name, mip->mi_name); - if (err != 0) - goto fail; - /* set the gldv3 flag in dn_flags */ dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; LOCK_DEV_OPS(&dnp->dn_lock); - dnp->dn_flags |= DN_GLDV3_DRIVER; + dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER); UNLOCK_DEV_OPS(&dnp->dn_lock); + if (mip->mi_minor < MAC_MAX_MINOR + 1) { + /* Create a style-2 DLPI device */ + if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0, + DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) + goto fail; + style2_created = B_TRUE; + + /* Create a style-1 DLPI device */ + if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, + mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS) + goto fail; + style1_created = B_TRUE; + } + rw_enter(&i_mac_impl_lock, RW_WRITER); if (mod_hash_insert(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { + rw_exit(&i_mac_impl_lock); - VERIFY(dls_destroy(mip->mi_name) == 0); err = EEXIST; goto fail; } @@ -1446,15 +1672,21 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) */ mip->mi_disabled = B_FALSE; - cmn_err(CE_NOTE, "!%s registered", mip->mi_name); - rw_exit(&i_mac_impl_lock); atomic_inc_32(&i_mac_impl_count); + + cmn_err(CE_NOTE, "!%s registered", mip->mi_name); *mhp = (mac_handle_t)mip; return (0); fail: + if (style1_created) + ddi_remove_minor_node(mip->mi_dip, mip->mi_name); + + if (style2_created) + ddi_remove_minor_node(mip->mi_dip, driver); + /* clean up notification thread */ if (mip->mi_notify_thread != NULL) { mutex_enter(&mip->mi_notify_bits_lock); @@ -1470,10 +1702,6 @@ fail: mip->mi_type->mt_addr_length); mip->mi_info.mi_unicst_addr = NULL; } - if (style1_created) - ddi_remove_minor_node(mip->mi_dip, mip->mi_name); - if (style2_created) - ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); mac_stat_destroy(mip); @@ -1488,6 +1716,11 @@ fail: mip->mi_pdata_size = 0; } + if (minor != 0) { + ASSERT(minor > MAC_MAX_MINOR); + mac_minor_rele(minor); + } + kmem_cache_free(i_mac_impl_cachep, mip); return (err); } @@ -1495,7 +1728,6 @@ fail: int mac_disable(mac_handle_t mh) { - int err; mac_impl_t *mip = (mac_impl_t *)mh; /* @@ -1510,14 +1742,6 @@ mac_disable(mac_handle_t mh) } mip->mi_disabled = B_TRUE; rw_exit(&i_mac_impl_lock); - - if ((err = dls_destroy(mip->mi_name)) != 0) { - rw_enter(&i_mac_impl_lock, RW_WRITER); - mip->mi_disabled = B_FALSE; - rw_exit(&i_mac_impl_lock); - return (err); - } - return (0); } @@ -1528,6 +1752,7 @@ mac_unregister(mac_handle_t mh) mac_impl_t *mip = (mac_impl_t *)mh; mod_hash_val_t val; mac_multicst_addr_t *p, *nextp; + mac_margin_req_t *mmr, *nextmmr; /* * See if there are any other references to this mac_t (e.g., VLAN's). @@ -1551,22 +1776,24 @@ mac_unregister(mac_handle_t mh) cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); mutex_exit(&mip->mi_notify_bits_lock); - /* - * Remove both style 1 and style 2 minor nodes - */ - ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); - ddi_remove_minor_node(mip->mi_dip, mip->mi_name); + if (mip->mi_minor < MAC_MAX_MINOR + 1) { + ddi_remove_minor_node(mip->mi_dip, mip->mi_name); + ddi_remove_minor_node(mip->mi_dip, + (char *)ddi_driver_name(mip->mi_dip)); + } ASSERT(!mip->mi_activelink); mac_stat_destroy(mip); - (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, - &val); + rw_enter(&i_mac_impl_lock, RW_WRITER); + (void) mod_hash_remove(i_mac_impl_hash, + (mod_hash_key_t)mip->mi_name, &val); ASSERT(mip == (mac_impl_t *)val); ASSERT(i_mac_impl_count > 0); atomic_dec_32(&i_mac_impl_count); + rw_exit(&i_mac_impl_lock); if (mip->mi_pdata != NULL) kmem_free(mip->mi_pdata, mip->mi_pdata_size); @@ -1582,6 +1809,15 @@ mac_unregister(mac_handle_t mh) } mip->mi_mmap = NULL; + /* + * Free the list of margin request. + */ + for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) { + nextmmr = mmr->mmr_nextp; + kmem_free(mmr, sizeof (mac_margin_req_t)); + } + mip->mi_mmrp = NULL; + mip->mi_linkstate = LINK_STATE_UNKNOWN; kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); mip->mi_info.mi_unicst_addr = NULL; @@ -1589,6 +1825,9 @@ mac_unregister(mac_handle_t mh) atomic_dec_32(&mip->mi_type->mt_ref); mip->mi_type = NULL; + if (mip->mi_minor > MAC_MAX_MINOR) + mac_minor_rele(mip->mi_minor); + cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); kmem_cache_free(i_mac_impl_cachep, mip); @@ -1888,6 +2127,12 @@ mac_unicst_update(mac_handle_t mh, const uint8_t *addr) return; /* + * If the address has not changed, do nothing. + */ + if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) + return; + + /* * Save the address. */ bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); @@ -2035,6 +2280,150 @@ mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) refresh(arg, (mip->mi_devpromisc != 0)); } +/* + * The mac client requests that the mac not to change its margin size to + * be less than the specified value. If "current" is B_TRUE, then the client + * requests the mac not to change its margin size to be smaller than the + * current size. Further, return the current margin size value in this case. + * + * We keep every requested size in an ordered list from largest to smallest. + */ +int +mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + mac_margin_req_t **pp, *p; + int err = 0; + + rw_enter(&(mip->mi_data_lock), RW_WRITER); + if (current) + *marginp = mip->mi_margin; + + /* + * If the current margin value cannot satisfy the margin requested, + * return ENOTSUP directly. + */ + if (*marginp > mip->mi_margin) { + err = ENOTSUP; + goto done; + } + + /* + * Check whether the given margin is already in the list. If so, + * bump the reference count. + */ + for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { + if (p->mmr_margin == *marginp) { + /* + * The margin requested is already in the list, + * so just bump the reference count. + */ + p->mmr_ref++; + goto done; + } + if (p->mmr_margin < *marginp) + break; + } + + + if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) { + err = ENOMEM; + goto done; + } + + p->mmr_margin = *marginp; + p->mmr_ref++; + p->mmr_nextp = *pp; + *pp = p; + +done: + rw_exit(&(mip->mi_data_lock)); + return (err); +} + +/* + * The mac client requests to cancel its previous mac_margin_add() request. + * We remove the requested margin size from the list. + */ +int +mac_margin_remove(mac_handle_t mh, uint32_t margin) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + mac_margin_req_t **pp, *p; + int err = 0; + + rw_enter(&(mip->mi_data_lock), RW_WRITER); + /* + * Find the entry in the list for the given margin. + */ + for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { + if (p->mmr_margin == margin) { + if (--p->mmr_ref == 0) + break; + + /* + * There is still a reference to this address so + * there's nothing more to do. + */ + goto done; + } + } + + /* + * We did not find an entry for the given margin. + */ + if (p == NULL) { + err = ENOENT; + goto done; + } + + ASSERT(p->mmr_ref == 0); + + /* + * Remove it from the list. + */ + *pp = p->mmr_nextp; + kmem_free(p, sizeof (mac_margin_req_t)); +done: + rw_exit(&(mip->mi_data_lock)); + return (err); +} + +/* + * The mac client requests to get the mac's current margin value. + */ +void +mac_margin_get(mac_handle_t mh, uint32_t *marginp) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + rw_enter(&(mip->mi_data_lock), RW_READER); + *marginp = mip->mi_margin; + rw_exit(&(mip->mi_data_lock)); +} + +boolean_t +mac_margin_update(mac_handle_t mh, uint32_t margin) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + uint32_t margin_needed = 0; + + rw_enter(&(mip->mi_data_lock), RW_WRITER); + + if (mip->mi_mmrp != NULL) + margin_needed = mip->mi_mmrp->mmr_margin; + + if (margin_needed <= margin) + mip->mi_margin = margin; + + rw_exit(&(mip->mi_data_lock)); + + if (margin_needed <= margin) + i_mac_notify(mip, MAC_NOTE_MARGIN); + + return (margin_needed <= margin); +} + boolean_t mac_do_active_set(mac_handle_t mh, boolean_t shareable) { @@ -2428,27 +2817,3 @@ done: mutex_exit(&i_mactype_lock); return (err); } - -int -mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor) -{ - mac_impl_t *mip = (mac_impl_t *)mh; - - /* Create a style-1 DLPI device */ - if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor, - DDI_NT_NET, 0) != DDI_SUCCESS) { - return (-1); - } - return (0); -} - -void -mac_vlan_remove(mac_handle_t mh, const char *name) -{ - mac_impl_t *mip = (mac_impl_t *)mh; - dev_info_t *dipp; - - ddi_remove_minor_node(mip->mi_dip, (char *)name); - dipp = ddi_get_parent(mip->mi_dip); - (void) devfs_clean(dipp, NULL, 0); -} diff --git a/usr/src/uts/common/io/mac/mac_stat.c b/usr/src/uts/common/io/mac/mac_stat.c index f25afd3f1f..c7fdb0d8d5 100644 --- a/usr/src/uts/common/io/mac/mac_stat.c +++ b/usr/src/uts/common/io/mac/mac_stat.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. */ @@ -154,10 +154,19 @@ mac_stat_create(mac_impl_t *mip) kstat_t *ksp; kstat_named_t *knp; uint_t count; + major_t major = getmajor(mip->mi_phy_dev); count = MAC_MOD_NKSTAT + MAC_NKSTAT + mip->mi_type->mt_statcount; - ksp = kstat_create(mip->mi_drvname, mip->mi_instance, MAC_KSTAT_NAME, - MAC_KSTAT_CLASS, KSTAT_TYPE_NAMED, count, 0); + if (!GLDV3_DRV(major)) { + ksp = kstat_create((const char *)ddi_major_to_name(major), + getminor(mip->mi_phy_dev) - 1, MAC_KSTAT_NAME, + MAC_KSTAT_CLASS, KSTAT_TYPE_NAMED, count, 0); + } else { + major = ddi_driver_major(mip->mi_dip); + ksp = kstat_create((const char *)ddi_major_to_name(major), + mip->mi_minor - 1, MAC_KSTAT_NAME, + MAC_KSTAT_CLASS, KSTAT_TYPE_NAMED, count, 0); + } if (ksp == NULL) return; diff --git a/usr/src/uts/common/io/mac/plugins/mac_ib.c b/usr/src/uts/common/io/mac/plugins/mac_ib.c index 97fd438dbd..35503c6c7f 100644 --- a/usr/src/uts/common/io/mac/plugins/mac_ib.c +++ b/usr/src/uts/common/io/mac/plugins/mac_ib.c @@ -69,6 +69,7 @@ _init(void) mtrp->mtr_ident = MAC_PLUGIN_IDENT_IB; mtrp->mtr_ops = &mac_ib_type_ops; mtrp->mtr_mactype = DL_IB; + mtrp->mtr_nativetype = DL_IB; mtrp->mtr_addrlen = IPOIB_ADDRL; mtrp->mtr_brdcst_addr = ib_brdcst; diff --git a/usr/src/uts/common/io/mxfe/mxfe.c b/usr/src/uts/common/io/mxfe/mxfe.c index e8468e4a61..091b877159 100644 --- a/usr/src/uts/common/io/mxfe/mxfe.c +++ b/usr/src/uts/common/io/mxfe/mxfe.c @@ -52,6 +52,7 @@ #include <sys/mac_ether.h> #include <sys/ddi.h> #include <sys/sunddi.h> +#include <sys/vlan.h> #include "mxfe.h" #include "mxfeimpl.h" @@ -522,6 +523,7 @@ mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) macp->m_callbacks = &mxfe_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) { mac_free(macp); diff --git a/usr/src/uts/common/io/net_dacf.c b/usr/src/uts/common/io/net_dacf.c new file mode 100644 index 0000000000..b0f4907425 --- /dev/null +++ b/usr/src/uts/common/io/net_dacf.c @@ -0,0 +1,136 @@ +/* + * 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 module provides the dacf functions to be called after a device + * of "ddi_network" node type has attached and before it detaches. + * Specifically, net_postattach() will be called during the post-attach + * process of each "ddi_network" device, and net_predetach() will be + * called during the pre-detach process of each device. + */ +#include <sys/modctl.h> +#include <sys/sunddi.h> +#include <sys/ddi.h> +#include <sys/dacf.h> +#include <sys/softmac.h> + +/* + * DACF entry points + */ +static int net_postattach(dacf_infohdl_t, dacf_arghdl_t, int); +static int net_predetach(dacf_infohdl_t, dacf_arghdl_t, int); + +static dacf_op_t net_config_op[] = { + { DACF_OPID_POSTATTACH, net_postattach }, + { DACF_OPID_PREDETACH, net_predetach }, + { DACF_OPID_END, NULL }, +}; + +static dacf_opset_t opsets[] = { + { "net_config", net_config_op }, + { NULL, NULL } +}; + +static struct dacfsw dacfsw = { + DACF_MODREV_1, + opsets +}; + +static struct modldacf modldacf = { + &mod_dacfops, + "net DACF", + &dacfsw +}; + +struct modlinkage modlinkage = { + MODREV_1, &modldacf, NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * Post-attach routine invoked for DDI_NT_NET drivers by DACF framework + */ +/* ARGSUSED */ +static int +net_postattach(dacf_infohdl_t info_hdl, dacf_arghdl_t arg_hdl, int flags) +{ + dev_info_t *dip; + dev_t dev; + int err; + + dip = dacf_devinfo_node(info_hdl); + dev = dacf_get_dev(info_hdl); + + if ((err = softmac_create(dip, dev)) != 0) { + const char *drvname; + int ppa; + + drvname = ddi_driver_name(dip); + ppa = i_ddi_devi_get_ppa(dip); + cmn_err(CE_WARN, "net_postattach: cannot create softmac " + "for device %s%d (%d)", drvname, ppa, err); + return (DACF_FAILURE); + } + + return (DACF_SUCCESS); +} + +/* + * Pre-detach routine invoked for DDI_NT_NET drivers by DACF framework + */ +/* ARGSUSED */ +static int +net_predetach(dacf_infohdl_t info_hdl, dacf_arghdl_t arg_hdl, int flags) +{ + dev_info_t *dip; + dev_t dev; + + dip = dacf_devinfo_node(info_hdl); + dev = dacf_get_dev(info_hdl); + + if (softmac_destroy(dip, dev) != 0) + return (DACF_FAILURE); + + return (DACF_SUCCESS); +} diff --git a/usr/src/uts/common/io/nge/nge_main.c b/usr/src/uts/common/io/nge/nge_main.c index 11987c5742..c062ab4e87 100644 --- a/usr/src/uts/common/io/nge/nge_main.c +++ b/usr/src/uts/common/io/nge/nge_main.c @@ -1839,6 +1839,7 @@ nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) macp->m_callbacks = &nge_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ngep->default_mtu; + macp->m_margin = VTAG_SIZE; /* * Finally, we're ready to register ourselves with the mac * interface; if this succeeds, we're all ready to start() diff --git a/usr/src/uts/common/io/nxge/nxge_main.c b/usr/src/uts/common/io/nxge/nxge_main.c index 1debecb937..9f856e5d92 100644 --- a/usr/src/uts/common/io/nxge/nxge_main.c +++ b/usr/src/uts/common/io/nxge/nxge_main.c @@ -4655,6 +4655,7 @@ nxge_mac_register(p_nxge_t nxgep) macp->m_min_sdu = 0; macp->m_max_sdu = nxgep->mac.maxframesize - sizeof (struct ether_header) - ETHERFCSL - 4; + macp->m_margin = VLAN_TAGSZ; status = mac_register(macp, &nxgep->mach); mac_free(macp); diff --git a/usr/src/uts/common/io/rge/rge_main.c b/usr/src/uts/common/io/rge/rge_main.c index c9bdf4d6d0..107cb01eca 100755 --- a/usr/src/uts/common/io/rge/rge_main.c +++ b/usr/src/uts/common/io/rge/rge_main.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. */ @@ -1758,6 +1758,7 @@ rge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) macp->m_callbacks = &rge_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = rgep->default_mtu; + macp->m_margin = VLAN_TAGSZ; /* * Finally, we're ready to register ourselves with the MAC layer diff --git a/usr/src/uts/common/io/sfe/sfe_util.c b/usr/src/uts/common/io/sfe/sfe_util.c index 0225b26088..0d04a520b5 100644 --- a/usr/src/uts/common/io/sfe/sfe_util.c +++ b/usr/src/uts/common/io/sfe/sfe_util.c @@ -4533,6 +4533,7 @@ gem_gld3_init(struct gem_dev *dp, mac_register_t *macp) macp->m_callbacks = &gem_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = dp->mtu; + macp->m_margin = VTAG_SIZE; } /* ======================================================================== */ diff --git a/usr/src/cmd/dladm/aggregation.conf b/usr/src/uts/common/io/softmac/softmac.conf index 5cb5189578..72163c27e6 100644 --- a/usr/src/cmd/dladm/aggregation.conf +++ b/usr/src/uts/common/io/softmac/softmac.conf @@ -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,12 +19,9 @@ # 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. +#ident "%Z%%M% %I% %E% SMI" +name="softmac" parent="pseudo" instance=0; diff --git a/usr/src/uts/common/io/softmac/softmac_capab.c b/usr/src/uts/common/io/softmac/softmac_capab.c new file mode 100644 index 0000000000..d1178d19aa --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_capab.c @@ -0,0 +1,756 @@ +/* + * 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 <sys/types.h> +#include <sys/mac.h> +#include <sys/softmac_impl.h> + +typedef struct softmac_capab_ops { + int (*sc_hcksum_ack)(void *, t_uscalar_t); + int (*sc_zcopy_ack)(void *, t_uscalar_t); + int (*sc_mdt_ack)(void *, dl_capab_mdt_t *); +} softmac_capab_ops_t; + +static int dl_capab(ldi_handle_t, mblk_t **); +static int softmac_fill_hcksum_ack(void *, t_uscalar_t); +static int softmac_fill_zcopy_ack(void *, t_uscalar_t); +static int softmac_fill_mdt_ack(void *, dl_capab_mdt_t *); +static int softmac_adv_hcksum_ack(void *, t_uscalar_t); +static int softmac_adv_zcopy_ack(void *, t_uscalar_t); +static int softmac_adv_mdt_ack(void *, dl_capab_mdt_t *); +static int softmac_enable_hcksum_ack(void *, t_uscalar_t); +static int softmac_enable_mdt_ack(void *, dl_capab_mdt_t *); +static int softmac_capab_send(softmac_lower_t *, boolean_t); +static int i_capab_ack(mblk_t *, queue_t *, softmac_capab_ops_t *, void *); +static int i_capab_id_ack(mblk_t *, dl_capability_sub_t *, queue_t *, + softmac_capab_ops_t *, void *); +static int i_capab_sub_ack(mblk_t *, dl_capability_sub_t *, queue_t *, + softmac_capab_ops_t *, void *); +static int i_capab_hcksum_ack(dl_capab_hcksum_t *, queue_t *, + softmac_capab_ops_t *, void *); +static int i_capab_zcopy_ack(dl_capab_zerocopy_t *, queue_t *, + softmac_capab_ops_t *, void *); +static int i_capab_mdt_ack(dl_capab_mdt_t *, queue_t *, + softmac_capab_ops_t *, void *); +static int i_capab_hcksum_verify(dl_capab_hcksum_t *, queue_t *); +static int i_capab_zcopy_verify(dl_capab_zerocopy_t *, queue_t *); +static int i_capab_mdt_verify(dl_capab_mdt_t *, queue_t *); + +static softmac_capab_ops_t softmac_fill_capab_ops = +{ + softmac_fill_hcksum_ack, + softmac_fill_zcopy_ack, + softmac_fill_mdt_ack, +}; + +static softmac_capab_ops_t softmac_adv_capab_ops = +{ + softmac_adv_hcksum_ack, + softmac_adv_zcopy_ack, + softmac_adv_mdt_ack +}; + +static softmac_capab_ops_t softmac_enable_capab_ops = +{ + softmac_enable_hcksum_ack, + NULL, + softmac_enable_mdt_ack +}; + +int +softmac_fill_capab(ldi_handle_t lh, softmac_t *softmac) +{ + mblk_t *mp = NULL; + union DL_primitives *prim; + int err = 0; + + if ((err = dl_capab(lh, &mp)) != 0) + goto exit; + + prim = (union DL_primitives *)mp->b_rptr; + if (prim->dl_primitive == DL_ERROR_ACK) { + err = -1; + goto exit; + } + + err = i_capab_ack(mp, NULL, &softmac_fill_capab_ops, softmac); + +exit: + freemsg(mp); + return (err); +} + +static int +dl_capab(ldi_handle_t lh, mblk_t **mpp) +{ + dl_capability_req_t *capb; + union DL_primitives *dl_prim; + mblk_t *mp; + int err; + + if ((mp = allocb(sizeof (dl_capability_req_t), BPRI_MED)) == NULL) + return (ENOMEM); + mp->b_datap->db_type = M_PROTO; + + capb = (dl_capability_req_t *)mp->b_wptr; + mp->b_wptr += sizeof (dl_capability_req_t); + bzero(mp->b_rptr, sizeof (dl_capability_req_t)); + capb->dl_primitive = DL_CAPABILITY_REQ; + + (void) ldi_putmsg(lh, mp); + if ((err = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) + return (err); + + dl_prim = (union DL_primitives *)mp->b_rptr; + switch (dl_prim->dl_primitive) { + case DL_CAPABILITY_ACK: + if (MBLKL(mp) < DL_CAPABILITY_ACK_SIZE) { + printf("dl_capability: DL_CAPABILITY_ACK " + "protocol err\n"); + break; + } + *mpp = mp; + return (0); + + case DL_ERROR_ACK: + if (MBLKL(mp) < DL_ERROR_ACK_SIZE) { + printf("dl_capability: DL_ERROR_ACK protocol err\n"); + break; + } + if (((dl_error_ack_t *)dl_prim)->dl_error_primitive != + DL_CAPABILITY_REQ) { + printf("dl_capability: DL_ERROR_ACK rtnd prim %u\n", + ((dl_error_ack_t *)dl_prim)->dl_error_primitive); + break; + } + + *mpp = mp; + return (0); + + default: + printf("dl_capability: bad ACK header %u\n", + dl_prim->dl_primitive); + break; + } + + freemsg(mp); + return (-1); +} + +static int +softmac_fill_hcksum_ack(void *arg, t_uscalar_t flags) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * There are two types of acks we process here: + * 1. acks in reply to a (first form) generic capability req + * (no ENABLE flag set) + * 2. acks in reply to a ENABLE capability req. + * (ENABLE flag set) + * Only the first type should be expected here. + */ + + if (flags & HCKSUM_ENABLE) { + cmn_err(CE_WARN, "softmac_fill_hcksum_ack: unexpected " + "HCKSUM_ENABLE flag in hardware checksum capability"); + } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | + HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) { + softmac->smac_capab_flags |= MAC_CAPAB_HCKSUM; + softmac->smac_hcksum_txflags = flags; + } + return (0); +} + +static int +softmac_fill_zcopy_ack(void *arg, t_uscalar_t flags) +{ + softmac_t *softmac = (softmac_t *)arg; + + ASSERT(flags == DL_CAPAB_VMSAFE_MEM); + softmac->smac_capab_flags &= (~MAC_CAPAB_NO_ZCOPY); + return (0); +} + +static int +softmac_fill_mdt_ack(void *arg, dl_capab_mdt_t *mdt) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * There are two types of acks we process here: + * 1. acks in reply to a (first form) generic capability req + * (ENABLE flag might be set by some drivers) + * 2. acks in reply to a ENABLE capability req. + * (ENABLE flag set) + */ + + ASSERT(mdt->mdt_version == MDT_VERSION_2); + softmac->smac_mdt = B_TRUE; + softmac->smac_mdt_capab.mdt_hdr_head = mdt->mdt_hdr_head; + softmac->smac_mdt_capab.mdt_hdr_tail = mdt->mdt_hdr_tail; + softmac->smac_mdt_capab.mdt_max_pld = mdt->mdt_max_pld; + softmac->smac_mdt_capab.mdt_span_limit = mdt->mdt_span_limit; + return (0); +} + +int +softmac_capab_enable(softmac_lower_t *slp) +{ + softmac_t *softmac = slp->sl_softmac; + int err; + + if (softmac->smac_no_capability_req) + return (0); + + /* + * Send DL_CAPABILITY_REQ to get capability advertisement. + */ + if ((err = softmac_capab_send(slp, B_FALSE)) != 0) + return (err); + + /* + * Send DL_CAPABILITY_REQ to enable specific capabilities. + */ + if ((err = softmac_capab_send(slp, B_TRUE)) != 0) + return (err); + + return (0); +} + +static int +softmac_capab_send(softmac_lower_t *slp, boolean_t enable) +{ + softmac_t *softmac; + dl_capability_req_t *capb; + dl_capability_sub_t *subcapb; + mblk_t *reqmp, *ackmp; + int err; + size_t size = 0; + + softmac = slp->sl_softmac; + + if (enable) { + /* No need to enable DL_CAPAB_ZEROCOPY */ + if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) + size += sizeof (dl_capability_sub_t) + + sizeof (dl_capab_hcksum_t); + + if (softmac->smac_mdt) { + if (!(softmac->smac_mdt_capab.mdt_flags & + DL_CAPAB_MDT_ENABLE)) { + /* + * The MDT capability was not enabled for the + * first time, enable it now. + */ + size += sizeof (dl_capability_sub_t) + + sizeof (dl_capab_mdt_t); + } + } + + if (size == 0) + return (0); + } + + /* + * Create DL_CAPABILITY_REQ message and send it down + */ + reqmp = allocb(sizeof (dl_capability_req_t) + size, BPRI_MED); + if (reqmp == NULL) + return (ENOMEM); + + bzero(reqmp->b_rptr, sizeof (dl_capability_req_t) + size); + + DB_TYPE(reqmp) = M_PROTO; + reqmp->b_wptr = reqmp->b_rptr + sizeof (dl_capability_req_t) + size; + + capb = (dl_capability_req_t *)reqmp->b_rptr; + capb->dl_primitive = DL_CAPABILITY_REQ; + + if (!enable) + goto output; + + capb->dl_sub_offset = sizeof (dl_capability_req_t); + + if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) { + dl_capab_hcksum_t *hck_subcapp; + + size = sizeof (dl_capability_sub_t) + + sizeof (dl_capab_hcksum_t); + capb->dl_sub_length += size; + + subcapb = (dl_capability_sub_t *)(capb + 1); + subcapb->dl_cap = DL_CAPAB_HCKSUM; + subcapb->dl_length = sizeof (dl_capab_hcksum_t); + hck_subcapp = (dl_capab_hcksum_t *)(subcapb + 1); + hck_subcapp->hcksum_version = HCKSUM_VERSION_1; + hck_subcapp->hcksum_txflags = + softmac->smac_hcksum_txflags | HCKSUM_ENABLE; + } + + if (softmac->smac_mdt) { + if (!(softmac->smac_mdt_capab.mdt_flags & + DL_CAPAB_MDT_ENABLE)) { + dl_capab_mdt_t *mdt_subcapp; + + size = sizeof (dl_capability_sub_t) + + sizeof (dl_capab_mdt_t); + capb->dl_sub_length += size; + + subcapb = (dl_capability_sub_t *) + ((uint8_t *)(subcapb + 1) + subcapb->dl_length); + + subcapb->dl_cap = DL_CAPAB_MDT; + subcapb->dl_length = sizeof (dl_capab_mdt_t); + mdt_subcapp = (dl_capab_mdt_t *)(subcapb + 1); + mdt_subcapp->mdt_version = MDT_VERSION_2; + mdt_subcapp->mdt_flags = + (softmac->smac_mdt_capab.mdt_flags | + DL_CAPAB_MDT_ENABLE); + mdt_subcapp->mdt_hdr_head = + softmac->smac_mdt_capab.mdt_hdr_head; + mdt_subcapp->mdt_hdr_tail = + softmac->smac_mdt_capab.mdt_hdr_tail; + mdt_subcapp->mdt_max_pld = + softmac->smac_mdt_capab.mdt_max_pld; + mdt_subcapp->mdt_span_limit = + softmac->smac_mdt_capab.mdt_span_limit; + } + } + +output: + err = softmac_proto_tx(slp, reqmp, &ackmp); + if (err == 0) { + if (enable) { + err = i_capab_ack(ackmp, NULL, + &softmac_enable_capab_ops, softmac); + } else { + err = i_capab_ack(ackmp, NULL, + &softmac_adv_capab_ops, softmac); + } + } + freemsg(ackmp); + + return (err); +} + +static int +softmac_adv_hcksum_ack(void *arg, t_uscalar_t flags) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * There are two types of acks we process here: + * 1. acks in reply to a (first form) generic capability req + * (no ENABLE flag set) + * 2. acks in reply to a ENABLE capability req. + * (ENABLE flag set) + * Only the first type should be expected here. + */ + + if (flags & HCKSUM_ENABLE) { + cmn_err(CE_WARN, "softmac_adv_hcksum_ack: unexpected " + "HCKSUM_ENABLE flag in hardware checksum capability"); + return (-1); + } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | + HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) { + /* + * The acknowledgement should be the same as we got when + * the softmac is created. + */ + if (!(softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)) { + ASSERT(B_FALSE); + return (-1); + } + if (softmac->smac_hcksum_txflags != flags) { + ASSERT(B_FALSE); + return (-1); + } + } + + return (0); +} + +static int +softmac_adv_zcopy_ack(void *arg, t_uscalar_t flags) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * The acknowledgement should be the same as we got when + * the softmac is created. + */ + ASSERT(flags == DL_CAPAB_VMSAFE_MEM); + if (softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY) { + ASSERT(B_FALSE); + return (-1); + } + + return (0); +} + +static int +softmac_adv_mdt_ack(void *arg, dl_capab_mdt_t *mdt) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * The acknowledgement should be the same as we got when + * the softmac is created. + */ + if (!softmac->smac_mdt) { + ASSERT(B_FALSE); + return (-1); + } + + if ((softmac->smac_mdt_capab.mdt_hdr_head != mdt->mdt_hdr_head) || + (softmac->smac_mdt_capab.mdt_hdr_tail != mdt->mdt_hdr_tail) || + (softmac->smac_mdt_capab.mdt_max_pld != mdt->mdt_max_pld) || + (softmac->smac_mdt_capab.mdt_span_limit != mdt->mdt_span_limit)) { + ASSERT(B_FALSE); + return (-1); + } + /* + * We need the mdt_flags field to know whether an additional + * DL_CAPAB_MDT_ENABLE is necessary. + */ + softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags; + return (0); +} + +static int +softmac_enable_hcksum_ack(void *arg, t_uscalar_t flags) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * There are two types of acks we process here: + * 1. acks in reply to a (first form) generic capability req + * (no ENABLE flag set) + * 2. acks in reply to a ENABLE capability req. + * (ENABLE flag set) + * Only the second type should be expected here. + */ + + if (flags & HCKSUM_ENABLE) { + if ((flags & ~HCKSUM_ENABLE) != softmac->smac_hcksum_txflags) { + cmn_err(CE_WARN, "softmac_enable_hcksum_ack: unexpected" + " hardware capability flag value 0x%x", flags); + return (-1); + } + } else { + cmn_err(CE_WARN, "softmac_enable_hcksum_ack: " + "hardware checksum flag HCKSUM_ENABLE is not set"); + return (-1); + } + + return (0); +} + +static int +softmac_enable_mdt_ack(void *arg, dl_capab_mdt_t *mdt) +{ + softmac_t *softmac = (softmac_t *)arg; + + /* + * There are two types of acks we process here: + * 1. acks in reply to a (first form) generic capability req + * (no ENABLE flag set) + * 2. acks in reply to a ENABLE capability req. + * (ENABLE flag set) + * Only the second type should be expected here. + */ + + if (mdt->mdt_flags & DL_CAPAB_MDT_ENABLE) { + if ((softmac->smac_mdt_capab.mdt_hdr_head != + mdt->mdt_hdr_head) || + (softmac->smac_mdt_capab.mdt_hdr_tail != + mdt->mdt_hdr_tail) || + (softmac->smac_mdt_capab.mdt_max_pld != + mdt->mdt_max_pld) || + (softmac->smac_mdt_capab.mdt_span_limit != + mdt->mdt_span_limit)) { + cmn_err(CE_WARN, "softmac_enable_mdt_ack: " + "unexpected MDT capability value"); + return (-1); + } + softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags; + } else { + cmn_err(CE_WARN, "softmac_enable_mdt_ack: " + "MDT flag DL_CAPAB_MDT_ENABLE is not set"); + return (-1); + } + + return (0); +} + +static int +i_capab_ack(mblk_t *mp, queue_t *q, softmac_capab_ops_t *op, void *arg) +{ + union DL_primitives *prim; + dl_capability_ack_t *cap; + dl_capability_sub_t *sub, *end; + int err = 0; + + prim = (union DL_primitives *)mp->b_rptr; + ASSERT(prim->dl_primitive == DL_CAPABILITY_ACK); + + cap = (dl_capability_ack_t *)prim; + if (cap->dl_sub_length == 0) + goto exit; + + /* Is dl_sub_length correct? */ + if ((sizeof (*cap) + cap->dl_sub_length) > MBLKL(mp)) { + err = EINVAL; + goto exit; + } + + sub = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_offset); + end = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_length + - sizeof (*sub)); + for (; (sub <= end) && (err == 0); ) { + switch (sub->dl_cap) { + case DL_CAPAB_ID_WRAPPER: + err = i_capab_id_ack(mp, sub, q, op, arg); + break; + default: + err = i_capab_sub_ack(mp, sub, q, op, arg); + break; + } + sub = (dl_capability_sub_t *)((caddr_t)sub + sizeof (*sub) + + sub->dl_length); + } + +exit: + return (err); +} + +static int +i_capab_id_ack(mblk_t *mp, dl_capability_sub_t *outers, + queue_t *q, softmac_capab_ops_t *op, void *arg) +{ + dl_capab_id_t *capab_id; + dl_capability_sub_t *inners; + caddr_t capend; + int err = EINVAL; + + ASSERT(outers->dl_cap == DL_CAPAB_ID_WRAPPER); + + capend = (caddr_t)(outers + 1) + outers->dl_length; + if (capend > (caddr_t)mp->b_wptr) { + cmn_err(CE_WARN, "i_capab_id_ack: malformed " + "sub-capability too long"); + return (err); + } + + capab_id = (dl_capab_id_t *)(outers + 1); + + if (outers->dl_length < sizeof (*capab_id) || + (inners = &capab_id->id_subcap, + inners->dl_length > (outers->dl_length - sizeof (*inners)))) { + cmn_err(CE_WARN, "i_capab_id_ack: malformed " + "encapsulated capab type %d too long", + inners->dl_cap); + return (err); + } + + if ((q != NULL) && (!dlcapabcheckqid(&capab_id->id_mid, q))) { + cmn_err(CE_WARN, "i_capab_id_ack: pass-thru module(s) " + "detected, discarding capab type %d", inners->dl_cap); + return (err); + } + + /* Process the encapsulated sub-capability */ + return (i_capab_sub_ack(mp, inners, q, op, arg)); +} + +static int +i_capab_sub_ack(mblk_t *mp, dl_capability_sub_t *sub, queue_t *q, + softmac_capab_ops_t *op, void *arg) +{ + caddr_t capend; + dl_capab_hcksum_t *hcksum; + dl_capab_zerocopy_t *zcopy; + dl_capab_mdt_t *mdt; + int err = 0; + + capend = (caddr_t)(sub + 1) + sub->dl_length; + if (capend > (caddr_t)mp->b_wptr) { + cmn_err(CE_WARN, "i_capab_sub_ack: " + "malformed sub-capability too long"); + return (EINVAL); + } + + switch (sub->dl_cap) { + case DL_CAPAB_HCKSUM: + hcksum = (dl_capab_hcksum_t *)(sub + 1); + err = i_capab_hcksum_ack(hcksum, q, op, arg); + break; + + case DL_CAPAB_ZEROCOPY: + zcopy = (dl_capab_zerocopy_t *)(sub + 1); + err = i_capab_zcopy_ack(zcopy, q, op, arg); + break; + + case DL_CAPAB_MDT: + mdt = (dl_capab_mdt_t *)(sub + 1); + err = i_capab_mdt_ack(mdt, q, op, arg); + break; + + default: + cmn_err(CE_WARN, "i_capab_sub_ack: unknown capab type %d", + sub->dl_cap); + err = EINVAL; + } + + return (err); +} + +static int +i_capab_hcksum_ack(dl_capab_hcksum_t *hcksum, queue_t *q, + softmac_capab_ops_t *op, void *arg) +{ + t_uscalar_t flags; + int err = 0; + + if ((err = i_capab_hcksum_verify(hcksum, q)) != 0) + return (err); + + flags = hcksum->hcksum_txflags; + + if (!(flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | + HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM | HCKSUM_ENABLE))) { + cmn_err(CE_WARN, "i_capab_hcksum_ack: invalid " + "hardware checksum capability flags 0x%x", flags); + return (EINVAL); + } + + if (op->sc_hcksum_ack) + return (op->sc_hcksum_ack(arg, flags)); + else { + cmn_err(CE_WARN, "i_capab_hcksum_ack: unexpected hardware " + "checksum acknowledgement"); + return (EINVAL); + } +} + +static int +i_capab_zcopy_ack(dl_capab_zerocopy_t *zcopy, queue_t *q, + softmac_capab_ops_t *op, void *arg) +{ + t_uscalar_t flags; + int err = 0; + + if ((err = i_capab_zcopy_verify(zcopy, q)) != 0) + return (err); + + flags = zcopy->zerocopy_flags; + if (!(flags & DL_CAPAB_VMSAFE_MEM)) { + cmn_err(CE_WARN, "i_capab_zcopy_ack: invalid zcopy capability " + "flags 0x%x", flags); + return (EINVAL); + } + if (op->sc_zcopy_ack) + return (op->sc_zcopy_ack(arg, flags)); + else { + cmn_err(CE_WARN, "i_capab_zcopy_ack: unexpected zcopy " + "acknowledgement"); + return (EINVAL); + } +} + +static int +i_capab_mdt_ack(dl_capab_mdt_t *mdt, queue_t *q, + softmac_capab_ops_t *op, void *arg) +{ + int err; + + if ((err = i_capab_mdt_verify(mdt, q)) != 0) + return (err); + + if (op->sc_mdt_ack) + return (op->sc_mdt_ack(arg, mdt)); + else { + cmn_err(CE_WARN, "i_capab_mdt_ack: unexpected MDT " + "acknowledgement"); + return (EINVAL); + } +} + +static int +i_capab_hcksum_verify(dl_capab_hcksum_t *hcksum, queue_t *q) +{ + if (hcksum->hcksum_version != HCKSUM_VERSION_1) { + cmn_err(CE_WARN, "i_capab_hcksum_verify: " + "unsupported hardware checksum capability (version %d, " + "expected %d)", hcksum->hcksum_version, HCKSUM_VERSION_1); + return (-1); + } + + if ((q != NULL) && !dlcapabcheckqid(&hcksum->hcksum_mid, q)) { + cmn_err(CE_WARN, "i_capab_hcksum_verify: unexpected pass-thru " + "module detected; hardware checksum capability discarded"); + return (-1); + } + return (0); +} + +static int +i_capab_zcopy_verify(dl_capab_zerocopy_t *zcopy, queue_t *q) +{ + if (zcopy->zerocopy_version != ZEROCOPY_VERSION_1) { + cmn_err(CE_WARN, "i_capab_zcopy_verify: unsupported zcopy " + "capability (version %d, expected %d)", + zcopy->zerocopy_version, ZEROCOPY_VERSION_1); + return (-1); + } + + if ((q != NULL) && !dlcapabcheckqid(&zcopy->zerocopy_mid, q)) { + cmn_err(CE_WARN, "i_capab_zcopy_verify: unexpected pass-thru " + "module detected; zcopy checksum capability discarded"); + return (-1); + } + return (0); +} + +static int +i_capab_mdt_verify(dl_capab_mdt_t *mdt, queue_t *q) +{ + if (mdt->mdt_version != MDT_VERSION_2) { + cmn_err(CE_WARN, "i_capab_mdt_verify: unsupported MDT " + "capability (version %d, expected %d)", + mdt->mdt_version, MDT_VERSION_2); + return (-1); + } + + if ((q != NULL) && !dlcapabcheckqid(&mdt->mdt_mid, q)) { + cmn_err(CE_WARN, "i_capab_mdt_verify: unexpected pass-thru " + "module detected; MDT capability discarded"); + return (-1); + } + return (0); +} diff --git a/usr/src/uts/common/io/softmac/softmac_ctl.c b/usr/src/uts/common/io/softmac/softmac_ctl.c new file mode 100644 index 0000000000..33472bd303 --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_ctl.c @@ -0,0 +1,389 @@ +/* + * 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 <sys/stropts.h> +#include <sys/softmac_impl.h> + +int +softmac_send_notify_req(softmac_lower_t *slp, uint32_t notifications) +{ + mblk_t *reqmp; + + /* + * create notify req message and send it down + */ + reqmp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, + DL_NOTIFY_REQ); + if (reqmp == NULL) + return (ENOMEM); + + ((dl_notify_req_t *)reqmp->b_rptr)->dl_notifications = notifications; + + return (softmac_proto_tx(slp, reqmp, NULL)); +} + +int +softmac_send_bind_req(softmac_lower_t *slp, uint_t sap) +{ + dl_bind_req_t *bind; + mblk_t *reqmp; + + /* + * create bind req message and send it down + */ + reqmp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ); + if (reqmp == NULL) + return (ENOMEM); + + bind = (dl_bind_req_t *)reqmp->b_rptr; + bind->dl_sap = sap; + bind->dl_conn_mgmt = 0; + bind->dl_max_conind = 0; + bind->dl_xidtest_flg = 0; + bind->dl_service_mode = DL_CLDLS; + + return (softmac_proto_tx(slp, reqmp, NULL)); +} + +int +softmac_send_promisc_req(softmac_lower_t *slp, t_uscalar_t level, boolean_t on) +{ + mblk_t *reqmp; + size_t size; + t_uscalar_t dl_prim; + + /* + * create promisc message and send it down + */ + if (on) { + dl_prim = DL_PROMISCON_REQ; + size = DL_PROMISCON_REQ_SIZE; + } else { + dl_prim = DL_PROMISCOFF_REQ; + size = DL_PROMISCOFF_REQ_SIZE; + } + + reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); + if (reqmp == NULL) + return (ENOMEM); + + if (on) + ((dl_promiscon_req_t *)reqmp->b_rptr)->dl_level = level; + else + ((dl_promiscoff_req_t *)reqmp->b_rptr)->dl_level = level; + + return (softmac_proto_tx(slp, reqmp, NULL)); +} + +int +softmac_m_promisc(void *arg, boolean_t on) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp = softmac->smac_lower; + + ASSERT(slp != NULL); + return (softmac_send_promisc_req(slp, DL_PROMISC_PHYS, on)); +} + +int +softmac_m_multicst(void *arg, boolean_t add, const uint8_t *mca) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp; + dl_enabmulti_req_t *enabmulti; + dl_disabmulti_req_t *disabmulti; + mblk_t *reqmp; + t_uscalar_t dl_prim; + uint32_t size, addr_length; + + /* + * create multicst message and send it down + */ + addr_length = softmac->smac_addrlen; + if (add) { + size = sizeof (dl_enabmulti_req_t) + addr_length; + dl_prim = DL_ENABMULTI_REQ; + } else { + size = sizeof (dl_disabmulti_req_t) + addr_length; + dl_prim = DL_DISABMULTI_REQ; + } + + reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); + if (reqmp == NULL) + return (ENOMEM); + + if (add) { + enabmulti = (dl_enabmulti_req_t *)reqmp->b_rptr; + enabmulti->dl_addr_offset = sizeof (dl_enabmulti_req_t); + enabmulti->dl_addr_length = addr_length; + (void) memcpy(&enabmulti[1], mca, addr_length); + } else { + disabmulti = (dl_disabmulti_req_t *)reqmp->b_rptr; + disabmulti->dl_addr_offset = sizeof (dl_disabmulti_req_t); + disabmulti->dl_addr_length = addr_length; + (void) memcpy(&disabmulti[1], mca, addr_length); + } + + slp = softmac->smac_lower; + ASSERT(slp != NULL); + return (softmac_proto_tx(slp, reqmp, NULL)); +} + +int +softmac_m_unicst(void *arg, const uint8_t *macaddr) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp; + dl_set_phys_addr_req_t *phyaddr; + mblk_t *reqmp; + size_t size; + + /* + * create set_phys_addr message and send it down + */ + size = DL_SET_PHYS_ADDR_REQ_SIZE + softmac->smac_addrlen; + reqmp = mexchange(NULL, NULL, size, M_PROTO, DL_SET_PHYS_ADDR_REQ); + if (reqmp == NULL) + return (ENOMEM); + + phyaddr = (dl_set_phys_addr_req_t *)reqmp->b_rptr; + phyaddr->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); + phyaddr->dl_addr_length = softmac->smac_addrlen; + (void) memcpy(&phyaddr[1], macaddr, softmac->smac_addrlen); + + slp = softmac->smac_lower; + ASSERT(slp != NULL); + return (softmac_proto_tx(slp, reqmp, NULL)); +} + +void +softmac_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) +{ + softmac_lower_t *slp = ((softmac_t *)arg)->smac_lower; + mblk_t *ackmp; + + ASSERT(slp != NULL); + softmac_ioctl_tx(slp, mp, &ackmp); + qreply(wq, ackmp); +} + +static void +softmac_process_notify_ind(queue_t *rq, mblk_t *mp) +{ + softmac_lower_t *slp = rq->q_ptr; + dl_notify_ind_t *dlnip = (dl_notify_ind_t *)mp->b_rptr; + softmac_t *softmac = slp->sl_softmac; + uint_t addroff, addrlen; + + ASSERT(dlnip->dl_primitive == DL_NOTIFY_IND); + + switch (dlnip->dl_notification) { + case DL_NOTE_PHYS_ADDR: + if (dlnip->dl_data != DL_CURR_PHYS_ADDR) + break; + + addroff = dlnip->dl_addr_offset; + addrlen = dlnip->dl_addr_length - softmac->smac_saplen; + if (addroff == 0 || addrlen != softmac->smac_addrlen || + !MBLKIN(mp, addroff, addrlen)) { + cmn_err(CE_NOTE, "softmac: got malformed " + "DL_NOTIFY_IND; length/offset %d/%d", + addrlen, addroff); + break; + } + + mac_unicst_update(softmac->smac_mh, mp->b_rptr + addroff); + break; + + case DL_NOTE_LINK_UP: + mac_link_update(softmac->smac_mh, LINK_STATE_UP); + break; + + case DL_NOTE_LINK_DOWN: + mac_link_update(softmac->smac_mh, LINK_STATE_DOWN); + break; + } + + freemsg(mp); +} + +static void +softmac_process_dlpi(softmac_lower_t *slp, mblk_t *mp, uint_t minlen, + t_uscalar_t reqprim) +{ + const char *ackname; + + ackname = dl_primstr(((union DL_primitives *)mp->b_rptr)->dl_primitive); + + if (MBLKL(mp) < minlen) { + cmn_err(CE_WARN, "softmac: got short %s", ackname); + freemsg(mp); + return; + } + + mutex_enter(&slp->sl_mutex); + if (slp->sl_pending_prim != reqprim) { + cmn_err(CE_NOTE, "softmac: got unexpected %s", ackname); + mutex_exit(&slp->sl_mutex); + freemsg(mp); + return; + } + + slp->sl_pending_prim = DL_PRIM_INVAL; + slp->sl_ack_mp = mp; + cv_signal(&slp->sl_cv); + mutex_exit(&slp->sl_mutex); +} + +void +softmac_rput_process_proto(queue_t *rq, mblk_t *mp) +{ + softmac_lower_t *slp = rq->q_ptr; + union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; + ssize_t len = MBLKL(mp); + const char *primstr; + + if (len < sizeof (t_uscalar_t)) { + cmn_err(CE_WARN, "softmac: got runt DLPI message"); + goto exit; + } + + primstr = dl_primstr(dlp->dl_primitive); + + switch (dlp->dl_primitive) { + case DL_OK_ACK: + if (len < DL_OK_ACK_SIZE) + goto runt; + + softmac_process_dlpi(slp, mp, DL_OK_ACK_SIZE, + dlp->ok_ack.dl_correct_primitive); + return; + + case DL_ERROR_ACK: + if (len < DL_ERROR_ACK_SIZE) + goto runt; + + cmn_err(CE_NOTE, "softmac: received DL_ERROR_ACK for " + "%s errno/unix_errno 0x%x/%d", + dl_primstr(dlp->error_ack.dl_error_primitive), + dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno); + + softmac_process_dlpi(slp, mp, DL_ERROR_ACK_SIZE, + dlp->error_ack.dl_error_primitive); + return; + + case DL_NOTIFY_IND: + if (len < DL_NOTIFY_IND_SIZE) + goto runt; + + softmac_process_notify_ind(rq, mp); + return; + + case DL_NOTIFY_ACK: + softmac_process_dlpi(slp, mp, DL_NOTIFY_ACK_SIZE, + DL_NOTIFY_REQ); + return; + + case DL_CAPABILITY_ACK: + softmac_process_dlpi(slp, mp, DL_CAPABILITY_ACK_SIZE, + DL_CAPABILITY_REQ); + return; + + case DL_BIND_ACK: + softmac_process_dlpi(slp, mp, DL_BIND_ACK_SIZE, DL_BIND_REQ); + return; + + case DL_CONTROL_ACK: + softmac_process_dlpi(slp, mp, DL_CONTROL_ACK_SIZE, + DL_CONTROL_REQ); + return; + + case DL_UNITDATA_IND: + case DL_PHYS_ADDR_ACK: + /* + * a. Because the stream is in DLIOCRAW mode, + * DL_UNITDATA_IND messages are not expected. + * b. The lower stream should not receive DL_PHYS_ADDR_REQ, + * so DL_PHYS_ADDR_ACK messages are also unexpected. + */ + default: + cmn_err(CE_WARN, "softmac: got unexpected %s", primstr); + break; + } +exit: + freemsg(mp); + return; +runt: + cmn_err(CE_WARN, "softmac: got runt %s", primstr); + freemsg(mp); +} + +void +softmac_rput_process_notdata(queue_t *rq, mblk_t *mp) +{ + softmac_lower_t *slp = rq->q_ptr; + + switch (DB_TYPE(mp)) { + case M_PROTO: + case M_PCPROTO: + softmac_rput_process_proto(rq, mp); + break; + + case M_FLUSH: + if (*mp->b_rptr & FLUSHR) + flushq(rq, FLUSHDATA); + if (*mp->b_rptr & FLUSHW) + flushq(OTHERQ(rq), FLUSHDATA); + putnext(rq, mp); + break; + + case M_IOCACK: + case M_IOCNAK: + case M_COPYIN: + case M_COPYOUT: + mutex_enter(&slp->sl_mutex); + if (!slp->sl_pending_ioctl) { + mutex_exit(&slp->sl_mutex); + cmn_err(CE_NOTE, "softmac: got unexpected mblk " + "type 0x%x", DB_TYPE(mp)); + freemsg(mp); + break; + } + + slp->sl_pending_ioctl = B_FALSE; + slp->sl_ack_mp = mp; + cv_broadcast(&slp->sl_cv); + mutex_exit(&slp->sl_mutex); + return; + + default: + cmn_err(CE_NOTE, "softmac: got unsupported mblk type 0x%x", + DB_TYPE(mp)); + freemsg(mp); + break; + } +} diff --git a/usr/src/uts/common/io/softmac/softmac_dev.c b/usr/src/uts/common/io/softmac/softmac_dev.c new file mode 100644 index 0000000000..501cec84da --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_dev.c @@ -0,0 +1,417 @@ +/* + * 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 <sys/types.h> +#include <sys/dld.h> +#include <inet/common.h> +#include <sys/stropts.h> +#include <sys/modctl.h> +#include <sys/avl.h> +#include <sys/softmac_impl.h> +#include <sys/softmac.h> + +dev_info_t *softmac_dip = NULL; + +static int softmac_open(queue_t *, dev_t *, int, int, cred_t *); +static int softmac_close(queue_t *); +static void softmac_rput(queue_t *, mblk_t *); +static void softmac_rsrv(queue_t *); +static void softmac_wput(queue_t *, mblk_t *); +static void softmac_wsrv(queue_t *); +static int softmac_attach(dev_info_t *, ddi_attach_cmd_t); +static int softmac_detach(dev_info_t *, ddi_detach_cmd_t); +static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **); + +static struct module_info softmac_modinfo = { + 0, + SOFTMAC_DEV_NAME, + 0, + INFPSZ, + 65536, + 1024 +}; + +/* + * hi-water mark is 1 because of the flow control mechanism implemented in + * dld. Refer to the comments in dld_str.c for details. + */ +static struct module_info softmac_dld_modinfo = { + 0, + SOFTMAC_DEV_NAME, + 0, + INFPSZ, + 1, + 0 +}; + +static struct qinit softmac_urinit = { + (pfi_t)softmac_rput, /* qi_putp */ + (pfi_t)softmac_rsrv, /* qi_srvp */ + softmac_open, /* qi_qopen */ + softmac_close, /* qi_qclose */ + NULL, /* qi_qadmin */ + &softmac_modinfo /* qi_minfo */ +}; + +static struct qinit softmac_uwinit = { + (pfi_t)softmac_wput, /* qi_putp */ + (pfi_t)softmac_wsrv, /* qi_srvp */ + NULL, /* qi_qopen */ + NULL, /* qi_qclose */ + NULL, /* qi_qadmin */ + &softmac_modinfo /* qi_minfo */ +}; + +static struct streamtab softmac_tab = { + &softmac_urinit, /* st_rdinit */ + &softmac_uwinit /* st_wrinit */ +}; + +DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach, + softmac_detach, nodev, softmac_info, D_MP, &softmac_tab); + +static struct qinit softmac_dld_r_qinit = { + NULL, NULL, dld_open, dld_close, NULL, &softmac_dld_modinfo +}; + +static struct qinit softmac_dld_w_qinit = { + (pfi_t)dld_wput, (pfi_t)dld_wsrv, NULL, NULL, NULL, + &softmac_dld_modinfo +}; + +static struct fmodsw softmac_fmodsw = { + SOFTMAC_DEV_NAME, + &softmac_tab, + D_MP +}; + +static struct modldrv softmac_modldrv = { + &mod_driverops, + "softmac driver", + &softmac_ops +}; + +static struct modlstrmod softmac_modlstrmod = { + &mod_strmodops, + "softmac module", + &softmac_fmodsw +}; + +static struct modlinkage softmac_modlinkage = { + MODREV_1, + &softmac_modlstrmod, + &softmac_modldrv, + NULL +}; + +int +_init(void) +{ + int err; + + softmac_init(); + + if ((err = mod_install(&softmac_modlinkage)) != 0) { + softmac_fini(); + return (err); + } + + return (0); +} + +int +_fini(void) +{ + int err; + + if (softmac_busy()) + return (EBUSY); + + if ((err = mod_remove(&softmac_modlinkage)) != 0) + return (err); + + softmac_fini(); + + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&softmac_modlinkage, modinfop)); +} + +static int +softmac_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) +{ + softmac_lower_t *slp; + /* + * This is a self-cloning driver so that each queue should only + * get opened once. + */ + if (rq->q_ptr != NULL) + return (EBUSY); + + if (sflag == MODOPEN) { + /* + * This is the softmac module pushed over an underlying + * legacy device. Initialize the lower structure. + */ + if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL) + return (ENOMEM); + + slp->sl_wq = WR(rq); + cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL); + mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL); + cv_init(&slp->sl_ctl_cv, NULL, CV_DRIVER, NULL); + mutex_init(&slp->sl_ctl_mutex, NULL, MUTEX_DRIVER, NULL); + slp->sl_pending_prim = DL_PRIM_INVAL; + rq->q_ptr = WR(rq)->q_ptr = slp; + qprocson(rq); + return (0); + } + + /* + * Regular device open of a softmac DLPI node. We modify + * the queues' q_qinfo pointer such that all future STREAMS + * operations will go through dld's entry points (including + * dld_close()). + */ + rq->q_qinfo = &softmac_dld_r_qinit; + WR(rq)->q_qinfo = &softmac_dld_w_qinit; + return (dld_open(rq, devp, flag, sflag, credp)); +} + +static int +softmac_close(queue_t *rq) +{ + softmac_lower_t *slp = rq->q_ptr; + + /* + * Call the appropriate delete routine depending on whether this is + * a module or device. + */ + ASSERT(WR(rq)->q_next != NULL); + + qprocsoff(rq); + + slp->sl_softmac = NULL; + slp->sl_lh = NULL; + + /* + * slp->sl_handle could be non-NULL if it is in the aggregation. + */ + slp->sl_handle = (mac_resource_handle_t)NULL; + + ASSERT(slp->sl_ack_mp == NULL); + ASSERT(slp->sl_ctl_inprogress == B_FALSE); + ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); + ASSERT(slp->sl_pending_ioctl == B_FALSE); + + cv_destroy(&slp->sl_cv); + mutex_destroy(&slp->sl_mutex); + cv_destroy(&slp->sl_ctl_cv); + mutex_destroy(&slp->sl_ctl_mutex); + + kmem_free(slp, sizeof (*slp)); + return (0); +} + +static void +softmac_rput(queue_t *rq, mblk_t *mp) +{ + softmac_lower_t *slp = rq->q_ptr; + union DL_primitives *dlp; + + /* + * This is the softmac module. + */ + ASSERT(WR(rq)->q_next != NULL); + ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); + + switch (DB_TYPE(mp)) { + case M_DATA: + /* + * Some drivers start to send up packets even if not in the + * DL_IDLE state, where sl_softmac is not set yet. Drop the + * packet in this case. + */ + if (slp->sl_softmac == NULL) { + freemsg(mp); + return; + } + + /* + * This is the most common case. + */ + if (DB_REF(mp) == 1) { + ASSERT(slp->sl_softmac != NULL); + /* + * We don't need any locks to protect sl_handle + * because ip_input() can tolerate if sl_handle + * is reset to NULL when DL_CAPAB_POLL is + * disabled. + */ + mac_rx(slp->sl_softmac->smac_mh, slp->sl_handle, mp); + return; + } else { + softmac_rput_process_data(slp, mp); + } + break; + case M_PROTO: + case M_PCPROTO: + if (MBLKL(mp) < sizeof (dlp->dl_primitive)) { + freemsg(mp); + break; + } + dlp = (union DL_primitives *)mp->b_rptr; + if (dlp->dl_primitive == DL_UNITDATA_IND) { + cmn_err(CE_WARN, "got unexpected %s message", + dl_primstr(DL_UNITDATA_IND)); + freemsg(mp); + break; + } + /*FALLTHROUGH*/ + default: + softmac_rput_process_notdata(rq, mp); + break; + } +} + +/* ARGSUSED */ +static void +softmac_rsrv(queue_t *rq) +{ +} + +static void +softmac_wput(queue_t *wq, mblk_t *mp) +{ + /* + * This is the softmac module + */ + ASSERT(wq->q_next != NULL); + + switch (DB_TYPE(mp)) { + case M_IOCTL: { + struct iocblk *ioc = (struct iocblk *)mp->b_rptr; + + switch (ioc->ioc_cmd) { + case SMAC_IOC_START: { + softmac_lower_t *slp = wq->q_ptr; + smac_ioc_start_t *arg; + + if (ioc->ioc_count != sizeof (*arg)) { + miocnak(wq, mp, 0, EINVAL); + break; + } + + /* + * Assign the devname and perstream handle of the + * specific lower stream and return it as a part + * of the ioctl. + */ + arg = (smac_ioc_start_t *)mp->b_cont->b_rptr; + arg->si_slp = slp; + + miocack(wq, mp, sizeof (*arg), 0); + break; + } + default: + miocnak(wq, mp, 0, EINVAL); + break; + } + break; + } + default: + freemsg(mp); + break; + } +} + +static void +softmac_wsrv(queue_t *wq) +{ + softmac_lower_t *slp = wq->q_ptr; + + /* + * This is the softmac module + */ + ASSERT(wq->q_next != NULL); + + /* + * Inform that the tx resource is available; mac_tx_update() will + * inform all the upper streams sharing this lower stream. + */ + if (slp->sl_softmac != NULL) + mac_tx_update(slp->sl_softmac->smac_mh); +} + +static int +softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + ASSERT(ddi_get_instance(dip) == 0); + + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + softmac_dip = dip; + + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +static int +softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + if (cmd != DDI_DETACH) + return (DDI_FAILURE); + + softmac_dip = NULL; + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +static int +softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + if (softmac_dip != NULL) { + *result = softmac_dip; + return (DDI_SUCCESS); + } + break; + + case DDI_INFO_DEVT2INSTANCE: + *result = NULL; + return (DDI_SUCCESS); + + } + + return (DDI_FAILURE); +} diff --git a/usr/src/uts/common/io/softmac/softmac_main.c b/usr/src/uts/common/io/softmac/softmac_main.c new file mode 100644 index 0000000000..8a218c53fb --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_main.c @@ -0,0 +1,1192 @@ +/* + * 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 softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3 + * framework. It also creates the kernel datalink structure for each + * physical network device. + * + * Specifically, a softmac will be created for each physical network device + * (dip) during the device's post-attach process. When this softmac is + * created, the following will also be done: + * - create the device's <link name, linkid> mapping; + * - register the mac if this is a non-GLDv3 device and the media type is + * supported by the GLDv3 framework; + * - create the kernel data-link structure for this physical device; + * + * This softmac will be destroyed during the device's pre-detach process, + * and all the above will be undone. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/cred.h> +#include <sys/dlpi.h> +#include <sys/sunndi.h> +#include <sys/modhash.h> +#include <sys/stropts.h> +#include <sys/sysmacros.h> +#include <sys/vlan.h> +#include <sys/softmac_impl.h> +#include <sys/softmac.h> +#include <sys/dls.h> + +/* + * Softmac hash table including softmacs for both style-2 and style-1 devices. + */ +static krwlock_t softmac_hash_lock; +static mod_hash_t *softmac_hash; + +#define SOFTMAC_HASHSZ 64 + +static void softmac_mac_register(void *); +static int softmac_create_datalink(softmac_t *); +static int softmac_m_start(void *); +static void softmac_m_stop(void *); +static int softmac_m_open(void *); +static void softmac_m_close(void *); +static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); + +#define SOFTMAC_M_CALLBACK_FLAGS \ + (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE) + +static mac_callbacks_t softmac_m_callbacks = { + SOFTMAC_M_CALLBACK_FLAGS, + softmac_m_stat, + softmac_m_start, + softmac_m_stop, + softmac_m_promisc, + softmac_m_multicst, + softmac_m_unicst, + softmac_m_tx, + softmac_m_resources, + softmac_m_ioctl, + softmac_m_getcapab, + softmac_m_open, + softmac_m_close +}; + +void +softmac_init() +{ + softmac_hash = mod_hash_create_extended("softmac_hash", + SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, + mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + + rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); +} + +void +softmac_fini() +{ + rw_destroy(&softmac_hash_lock); + mod_hash_destroy_hash(softmac_hash); +} + +/* ARGSUSED */ +static uint_t +softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + boolean_t *pexist = arg; + + *pexist = B_TRUE; + return (MH_WALK_TERMINATE); +} + +boolean_t +softmac_busy() +{ + boolean_t exist = B_FALSE; + + rw_enter(&softmac_hash_lock, RW_READER); + mod_hash_walk(softmac_hash, softmac_exist, &exist); + rw_exit(&softmac_hash_lock); + return (exist); +} + +/* + * This function is called for each minor node during the post-attach of + * each DDI_NT_NET device instance. Note that it is possible that a device + * instance has two minor nodes (DLPI style-1 and style-2), so that for that + * specific device, softmac_create() could be called twice. + * + * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t + * is created to track each minor node. + * + * For each minor node of a legacy device, a taskq is started to finish + * softmac_mac_register(), which will finish the rest of work (see comments + * above softmac_mac_register()). + */ +int +softmac_create(dev_info_t *dip, dev_t dev) +{ + char devname[MAXNAMELEN]; + softmac_t *softmac; + softmac_dev_t *softmac_dev = NULL; + datalink_id_t linkid; + int index; + int ppa, err = 0; + mac_handle_t mh; + + /* + * Force the softmac driver to be attached. + */ + if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { + cmn_err(CE_WARN, "softmac_create:softmac attach fails"); + return (ENXIO); + } + + ppa = ddi_get_instance(dip); + (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); + + /* + * We expect legacy devices have at most two minor nodes - one style-1 + * and one style-2. + */ + if (!GLDV3_DRV(ddi_driver_major(dip)) && + i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { + cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported", + devname); + return (ENOTSUP); + } + + /* + * Check whether the softmac for the specified device already exists + */ + rw_enter(&softmac_hash_lock, RW_WRITER); + if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, + (mod_hash_val_t *)&softmac)) != 0) { + + softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP); + mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL); + cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL); + rw_init(&softmac->smac_lock, NULL, RW_DRIVER, NULL); + (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); + + /* + * Insert the softmac into the hash table. + */ + err = mod_hash_insert(softmac_hash, + (mod_hash_key_t)softmac->smac_devname, + (mod_hash_val_t)softmac); + ASSERT(err == 0); + } + + mutex_enter(&softmac->smac_mutex); + if (softmac->smac_attachok_cnt == 0) { + /* + * Initialize the softmac if this is the post-attach of the + * first minor node. + */ + softmac->smac_flags = 0; + softmac->smac_umajor = ddi_driver_major(dip); + softmac->smac_uppa = ppa; + + /* + * Note that for GLDv3 devices, we create devfs minor nodes + * for VLANs as well. Assume a GLDv3 driver on which only + * a VLAN is created. During the detachment of this device + * instance, the following would happen: + * a. the pre-detach callback softmac_destroy() succeeds. + * Because the physical link itself is not in use, + * softmac_destroy() succeeds and destroys softmac_t; + * b. the device detach fails in mac_unregister() because + * this MAC is still used by a VLAN. + * c. the post-attach callback is then called which leads + * us here. Note that ddi_minor_node_count() returns 3 + * (including the minior node of the VLAN). In that case, + * we must correct the minor node count to 2 as that is + * the count of minor nodes that go through post-attach. + */ + if (GLDV3_DRV(ddi_driver_major(dip))) { + softmac->smac_flags |= SOFTMAC_GLDV3; + softmac->smac_cnt = 2; + } else { + softmac->smac_cnt = + i_ddi_minor_node_count(dip, DDI_NT_NET); + } + } + + index = (getmajor(dev) == ddi_name_to_major("clone")); + if (softmac->smac_softmac[index] != NULL) { + /* + * This is possible if the post_attach() is called: + * + * a. after pre_detach() fails. + * + * b. for a new round of reattachment. Note that DACF will not + * call pre_detach() for successfully post_attached minor + * nodes even when the post-attach failed after all. + * + * Both seem to be defects in the DACF framework. To work + * around it and only clear the SOFTMAC_ATTACH_DONE flag for + * the b case, a smac_attached_left field is used to tell + * the two cases apart. + */ + ASSERT(softmac->smac_attachok_cnt != 0); + + if (softmac->smac_attached_left != 0) + /* case a */ + softmac->smac_attached_left--; + else if (softmac->smac_attachok_cnt != softmac->smac_cnt) { + /* case b */ + softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE; + } + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + return (0); + } + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + + /* + * Inform dlmgmtd of this link so that softmac_hold_device() is able + * to know the existence of this link. This could fail if dlmgmtd + * is not yet started. + */ + (void) dls_mgmt_create(devname, makedevice(ddi_driver_major(dip), + ppa + 1), DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); + + /* + * No lock is needed for access this softmac pointer, as pre-detach and + * post-attach won't happen at the same time. + */ + mutex_enter(&softmac->smac_mutex); + + softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); + softmac_dev->sd_dev = dev; + softmac->smac_softmac[index] = softmac_dev; + + /* + * Continue to register the mac and create the datalink only when all + * the minor nodes are attached. + */ + if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { + mutex_exit(&softmac->smac_mutex); + return (0); + } + + if (!GLDV3_DRV(ddi_driver_major(dip))) { + + /* + * Note that this function could be called as a result of + * a open() system call, and spec_open() already locked the + * snode (SLOCKED is set). Therefore, we must start a + * taskq to finish the rest of work to sidestep the risk + * that our ldi_open_by_dev() call would again try to hold + * the same lock. + * + * If all the minor nodes have been attached, start the taskq + * to finish the rest of the work. + */ + ASSERT(softmac->smac_taskq == NULL); + softmac->smac_taskq = taskq_dispatch(system_taskq, + softmac_mac_register, softmac, TQ_SLEEP); + mutex_exit(&softmac->smac_mutex); + return (0); + } + + if ((err = mac_open(softmac->smac_devname, &mh)) != 0) + goto done; + + softmac->smac_media = (mac_info(mh))->mi_nativemedia; + softmac->smac_mh = mh; + + /* + * We can safely release the reference on the mac because + * this mac will only be unregistered and destroyed when + * the device detaches, and the softmac will be destroyed + * before then (in the pre-detach routine of the device). + */ + mac_close(mh); + + /* + * Create the GLDv3 datalink for this mac. + */ + err = softmac_create_datalink(softmac); + +done: + if (err != 0) { + softmac->smac_mh = NULL; + kmem_free(softmac_dev, sizeof (softmac_dev_t)); + softmac->smac_softmac[index] = NULL; + --softmac->smac_attachok_cnt; + } + ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); + softmac->smac_flags |= SOFTMAC_ATTACH_DONE; + softmac->smac_attacherr = err; + cv_broadcast(&softmac->smac_cv); + mutex_exit(&softmac->smac_mutex); + return (err); +} + +static boolean_t +softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) +{ + softmac_t *softmac = arg; + + if (!(softmac->smac_capab_flags & cap)) + return (B_FALSE); + + switch (cap) { + case MAC_CAPAB_HCKSUM: { + uint32_t *txflags = cap_data; + + *txflags = softmac->smac_hcksum_txflags; + break; + } + case MAC_CAPAB_LEGACY: { + mac_capab_legacy_t *legacy = cap_data; + + legacy->ml_unsup_note = ~softmac->smac_notifications & + (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); + legacy->ml_dev = makedevice(softmac->smac_umajor, + softmac->smac_uppa + 1); + break; + } + + /* + * For the capabilities below, there's nothing for us to fill in; + * simply return B_TRUE if we support it. + */ + case MAC_CAPAB_NO_ZCOPY: + case MAC_CAPAB_POLL: + case MAC_CAPAB_NO_NATIVEVLAN: + default: + break; + } + return (B_TRUE); +} + +static int +softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) +{ + datalink_id_t linkid = DATALINK_INVALID_LINKID; + uint32_t media; + int err; + + if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, + softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { + *linkidp = linkid; + } + + if (err == EEXIST) { + /* + * There is a link name conflict. Either: + * + * - An existing link with the same device name with a + * different media type from of the given type. + * Mark this link back to persistent only; or + * + * - We cannot assign the "suggested" name because + * GLDv3 and therefore vanity naming is not supported + * for this link type. Delete this link's <link name, + * linkid> mapping. + */ + if (media != softmac->smac_media) { + cmn_err(CE_WARN, "%s device %s conflicts with " + "existing %s device %s.", + dl_mactypestr(softmac->smac_media), + softmac->smac_devname, dl_mactypestr(media), + softmac->smac_devname); + (void) dls_mgmt_destroy(linkid, B_FALSE); + } else { + cmn_err(CE_WARN, "link name %s is already in-use.", + softmac->smac_devname); + (void) dls_mgmt_destroy(linkid, B_TRUE); + } + + cmn_err(CE_WARN, "%s device might not be available " + "for use.", softmac->smac_devname); + cmn_err(CE_WARN, "See dladm(1M) for more information."); + } + + return (err); +} + +/* + * This function: + * 1. provides the link's media type to dlmgmtd. + * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. + */ +static int +softmac_create_datalink(softmac_t *softmac) +{ + datalink_id_t linkid = DATALINK_INVALID_LINKID; + int err; + + ASSERT(MUTEX_HELD(&softmac->smac_mutex)); + + /* + * First provide the media type of the physical link to dlmgmtd. + * + * If the new <linkname, linkid> mapping operation failed with EBADF + * or ENOENT, it might because the dlmgmtd was not started in time + * (e.g., diskless boot); ignore the failure and continue. The + * mapping will be recreated once the daemon has started. + */ + if (((err = softmac_update_info(softmac, &linkid)) != 0) && + (err != EBADF) && (err != ENOENT)) { + return (err); + } + + /* + * Create the GLDv3 datalink. + */ + if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && + ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { + cmn_err(CE_WARN, "dls_devnet_create failed for %s", + softmac->smac_devname); + return (err); + } + + if (linkid == DATALINK_INVALID_LINKID) + softmac->smac_flags |= SOFTMAC_NEED_RECREATE; + + return (0); +} + +/* + * This function is only called for legacy devices. It: + * 1. registers the MAC for the legacy devices whose media type is supported + * by the GLDv3 framework. + * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. + */ +static void +softmac_mac_register(void *arg) +{ + softmac_t *softmac = arg; + softmac_dev_t *softmac_dev; + dev_t dev; + ldi_handle_t lh = NULL; + ldi_ident_t li = NULL; + int index; + boolean_t native_vlan = B_FALSE; + int err; + + /* + * Note that we do not need any locks to access this softmac pointer, + * as softmac_destroy() will wait until this function is called. + */ + ASSERT(softmac != NULL); + + if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { + mutex_enter(&softmac->smac_mutex); + goto done; + } + + /* + * Determine whether this legacy device support VLANs by opening + * the style-2 device node (if it exists) and attaching to a VLAN + * PPA (1000 + ppa). + */ + dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); + err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); + if (err == 0) { + if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) + native_vlan = B_TRUE; + (void) ldi_close(lh, FREAD|FWRITE, kcred); + } + + err = EINVAL; + for (index = 0; index < 2; index++) { + dl_info_ack_t dlia; + dl_error_ack_t dlea; + uint32_t notes; + struct strioctl iocb; + uint32_t margin; + int rval; + + if ((softmac_dev = softmac->smac_softmac[index]) == NULL) + continue; + + softmac->smac_dev = dev = softmac_dev->sd_dev; + if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, + li) != 0) { + continue; + } + + /* + * Pop all the intermediate modules in order to negotiate + * capabilities correctly. + */ + while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) + ; + + /* DLPI style-1 or DLPI style-2? */ + if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { + if (rval == ENOTSUP) { + cmn_err(CE_NOTE, "softmac: received " + "DL_ERROR_ACK to DL_INFO_ACK; " + "DLPI errno 0x%x, UNIX errno %d", + dlea.dl_errno, dlea.dl_unix_errno); + } + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + /* + * Currently only DL_ETHER has GLDv3 mac plugin support. + * For media types that GLDv3 does not support, create a + * link id for it. + */ + if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { + (void) ldi_close(lh, FREAD|FWRITE, kcred); + err = 0; + break; + } + + if ((dlia.dl_provider_style == DL_STYLE2) && + (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + if ((rval = dl_bind(lh, 0, NULL)) != 0) { + if (rval == ENOTSUP) { + cmn_err(CE_NOTE, "softmac: received " + "DL_ERROR_ACK to DL_BIND_ACK; " + "DLPI errno 0x%x, UNIX errno %d", + dlea.dl_errno, dlea.dl_unix_errno); + } + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + /* + * Call dl_info() after dl_bind() because some drivers only + * provide correct information (e.g. MAC address) once bound. + */ + softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); + if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, + &softmac->smac_addrlen, &dlea)) != 0) { + if (rval == ENOTSUP) { + cmn_err(CE_NOTE, "softmac: received " + "DL_ERROR_ACK to DL_INFO_ACK; " + "DLPI errno 0x%x, UNIX errno %d", + dlea.dl_errno, dlea.dl_unix_errno); + } + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + softmac->smac_style = dlia.dl_provider_style; + softmac->smac_saplen = ABS(dlia.dl_sap_length); + softmac->smac_min_sdu = dlia.dl_min_sdu; + softmac->smac_max_sdu = dlia.dl_max_sdu; + + if ((softmac->smac_saplen != sizeof (uint16_t)) || + (softmac->smac_addrlen != ETHERADDRL) || + (dlia.dl_brdcst_addr_length != ETHERADDRL) || + (dlia.dl_brdcst_addr_offset == 0)) { + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + /* + * Check other DLPI capabilities. Note that this must be after + * dl_bind() because some drivers return DL_ERROR_ACK if the + * stream is not bound. It is also before mac_register(), so + * we don't need any lock protection here. + * + * Softmac always supports POLL. + */ + softmac->smac_capab_flags = + (MAC_CAPAB_POLL | MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); + + softmac->smac_no_capability_req = B_FALSE; + if (softmac_fill_capab(lh, softmac) != 0) + softmac->smac_no_capability_req = B_TRUE; + + /* + * Check the margin of the underlying driver. + */ + margin = 0; + iocb.ic_cmd = DLIOCMARGININFO; + iocb.ic_timout = INFTIM; + iocb.ic_len = sizeof (margin); + iocb.ic_dp = (char *)&margin; + softmac->smac_margin = 0; + + if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, + &rval) == 0) { + softmac->smac_margin = margin; + } + + /* + * If the legacy driver doesn't support DLIOCMARGININFO, but + * it can support native VLAN, correct its margin value to 4. + */ + if (native_vlan) { + if (softmac->smac_margin == 0) + softmac->smac_margin = VLAN_TAGSZ; + } else { + softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; + } + + /* + * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. + */ + softmac->smac_notifications = 0; + notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; + switch (dl_notify(lh, ¬es, NULL)) { + case 0: + softmac->smac_notifications = notes; + break; + case ENOTSUP: + break; + default: + (void) ldi_close(lh, FREAD|FWRITE, kcred); + continue; + } + + (void) ldi_close(lh, FREAD|FWRITE, kcred); + err = 0; + break; + } + ldi_ident_release(li); + + mutex_enter(&softmac->smac_mutex); + + if (err != 0) + goto done; + + if (softmac->smac_media != DL_ETHER) + softmac->smac_flags |= SOFTMAC_NOSUPP; + + /* + * Finally, we're ready to register ourselves with the MAC layer + * interface; if this succeeds, we're all ready to start() + */ + if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { + mac_register_t *macp; + + if ((macp = mac_alloc(MAC_VERSION)) == NULL) { + err = ENOMEM; + goto done; + } + + macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; + macp->m_driver = softmac; + macp->m_dip = softmac_dip; + + macp->m_margin = softmac->smac_margin; + macp->m_src_addr = softmac->smac_unicst_addr; + macp->m_min_sdu = softmac->smac_min_sdu; + macp->m_max_sdu = softmac->smac_max_sdu; + macp->m_callbacks = &softmac_m_callbacks; + macp->m_instance = (uint_t)-1; + + err = mac_register(macp, &softmac->smac_mh); + mac_free(macp); + if (err != 0) { + cmn_err(CE_WARN, "mac_register failed for %s", + softmac->smac_devname); + goto done; + } + } + + /* + * Try to create the datalink for this softmac. + */ + if ((err = softmac_create_datalink(softmac)) != 0) { + if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { + (void) mac_unregister(softmac->smac_mh); + softmac->smac_mh = NULL; + } + } + +done: + ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); + softmac->smac_flags |= SOFTMAC_ATTACH_DONE; + softmac->smac_attacherr = err; + softmac->smac_taskq = NULL; + cv_broadcast(&softmac->smac_cv); + mutex_exit(&softmac->smac_mutex); +} + +int +softmac_destroy(dev_info_t *dip, dev_t dev) +{ + char devname[MAXNAMELEN]; + softmac_t *softmac; + softmac_dev_t *softmac_dev; + int index; + int ppa, err; + datalink_id_t linkid; + + ppa = ddi_get_instance(dip); + (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); + + rw_enter(&softmac_hash_lock, RW_WRITER); + err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, + (mod_hash_val_t *)&softmac); + ASSERT(err == 0); + + mutex_enter(&softmac->smac_mutex); + + /* + * Fail the predetach routine if this softmac is in-use. + */ + if (softmac->smac_hold_cnt != 0) { + softmac->smac_attached_left = softmac->smac_attachok_cnt; + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + return (EBUSY); + } + + /* + * Even if the predetach of one minor node has already failed + * (smac_attached_left is not 0), the DACF framework will continue + * to call the predetach routines of the other minor nodes, + * so we fail these calls here. + */ + if (softmac->smac_attached_left != 0) { + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + return (EBUSY); + } + + if (softmac->smac_attachok_cnt != softmac->smac_cnt) + goto done; + + /* + * This is the detach for the first minor node. Wait until all the + * minor nodes are attached. + */ + while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) + cv_wait(&softmac->smac_cv, &softmac->smac_mutex); + + if (softmac->smac_mh != NULL) { + if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { + if ((err = dls_devnet_destroy(softmac->smac_mh, + &linkid)) != 0) { + goto done; + } + } + /* + * If softmac_mac_register() succeeds in registering the mac + * of the legacy device, unregister it. + */ + if (!(softmac->smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { + if ((err = mac_unregister(softmac->smac_mh)) != 0) { + (void) dls_devnet_create(softmac->smac_mh, + linkid); + goto done; + } + } + softmac->smac_mh = NULL; + } + softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE; + +done: + if (err == 0) { + /* + * Free softmac_dev + */ + index = (getmajor(dev) == ddi_name_to_major("clone")); + softmac_dev = softmac->smac_softmac[index]; + ASSERT(softmac_dev != NULL); + softmac->smac_softmac[index] = NULL; + kmem_free(softmac_dev, sizeof (softmac_dev_t)); + + if (--softmac->smac_attachok_cnt == 0) { + mod_hash_val_t hashval; + + err = mod_hash_remove(softmac_hash, + (mod_hash_key_t)devname, + (mod_hash_val_t *)&hashval); + ASSERT(err == 0); + + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + + ASSERT(softmac->smac_taskq == NULL); + ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); + mutex_destroy(&softmac->smac_mutex); + cv_destroy(&softmac->smac_cv); + rw_destroy(&softmac->smac_lock); + kmem_free(softmac, sizeof (softmac_t)); + return (0); + } + } else { + softmac->smac_attached_left = softmac->smac_attachok_cnt; + } + + mutex_exit(&softmac->smac_mutex); + rw_exit(&softmac_hash_lock); + return (err); +} + +/* + * This function is called as the result of a newly started dlmgmtd daemon. + * + * We walk through every softmac that was created but failed to notify + * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs + * when softmacs are created before dlmgmtd is ready. For example, during + * diskless boot, a network device is used (and therefore attached) before + * the datalink-management service starts dlmgmtd. + */ +/* ARGSUSED */ +static uint_t +softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) +{ + softmac_t *softmac = (softmac_t *)val; + datalink_id_t linkid; + int err; + + ASSERT(RW_READ_HELD(&softmac_hash_lock)); + + /* + * Wait for softmac_create() and softmac_mac_register() to exit. + */ + mutex_enter(&softmac->smac_mutex); + while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) + cv_wait(&softmac->smac_cv, &softmac->smac_mutex); + + if ((softmac->smac_attacherr != 0) || + !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { + mutex_exit(&softmac->smac_mutex); + return (MH_WALK_CONTINUE); + } + + if (dls_mgmt_create(softmac->smac_devname, + makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), + DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { + mutex_exit(&softmac->smac_mutex); + return (MH_WALK_CONTINUE); + } + + if ((err = softmac_update_info(softmac, &linkid)) != 0) { + cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " + "failed (%d)", softmac->smac_devname, err); + mutex_exit(&softmac->smac_mutex); + return (MH_WALK_CONTINUE); + } + + /* + * Create a link for this MAC. The link name will be the same + * as the MAC name. + */ + if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { + err = dls_devnet_recreate(softmac->smac_mh, linkid); + if (err != 0) { + cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " + "%s (linkid %d) failed (%d)", + softmac->smac_devname, linkid, err); + } + } + + softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; + mutex_exit(&softmac->smac_mutex); + + return (MH_WALK_CONTINUE); +} + +/* + * See comments above softmac_mac_recreate(). + */ +void +softmac_recreate() +{ + /* + * Walk through the softmac_hash table. Request to create the + * [link name, linkid] mapping if we failed to do so. + */ + rw_enter(&softmac_hash_lock, RW_READER); + mod_hash_walk(softmac_hash, softmac_mac_recreate, NULL); + rw_exit(&softmac_hash_lock); +} + +/* ARGSUSED */ +static int +softmac_m_start(void *arg) +{ + return (0); +} + +/* ARGSUSED */ +static void +softmac_m_stop(void *arg) +{ +} + +/* + * Set up the lower stream above the legacy device which is shared by + * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send + * and receive the raw data. Further, put the lower stream into + * DL_PROMISC_SAP mode to receive all packets of interest. + */ +static int +softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp) +{ + ldi_ident_t li; + dev_t dev; + ldi_handle_t lh = NULL; + softmac_lower_t *slp = NULL; + smac_ioc_start_t start_arg; + struct strioctl strioc; + uint32_t notifications; + int err, rval; + + if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) + return (err); + + dev = softmac->smac_dev; + err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); + ldi_ident_release(li); + if (err != 0) + goto done; + + /* + * Pop all the intermediate modules. The autopushed modules will + * be pushed when the softmac node is opened. + */ + while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) + ; + + if ((softmac->smac_style == DL_STYLE2) && + ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { + goto done; + } + + /* + * Put the lower stream into DLIOCRAW mode to send/receive raw data. + */ + if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0) + goto done; + + /* + * Then push the softmac shim layer atop the lower stream. + */ + if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, + kcred, &rval)) != 0) { + goto done; + } + + /* + * Send the ioctl to get the slp pointer. + */ + strioc.ic_cmd = SMAC_IOC_START; + strioc.ic_timout = INFTIM; + strioc.ic_len = sizeof (start_arg); + strioc.ic_dp = (char *)&start_arg; + + if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, + kcred, &rval)) != 0) { + goto done; + } + slp = start_arg.si_slp; + slp->sl_lh = lh; + slp->sl_softmac = softmac; + *slpp = slp; + + /* + * Bind to SAP 2 on token ring, 0 on other interface types. + * (SAP 0 has special significance on token ring). + * Note that the receive-side packets could come anytime after bind. + */ + if (softmac->smac_media == DL_TPR) + err = softmac_send_bind_req(slp, 2); + else + err = softmac_send_bind_req(slp, 0); + if (err != 0) + goto done; + + /* + * Put the lower stream into DL_PROMISC_SAP mode to receive all + * packets of interest. + * + * Some drivers (e.g. the old legacy eri driver) incorrectly pass up + * packets to DL_PROMISC_SAP stream when the lower stream is not bound, + * so we send DL_PROMISON_REQ after DL_BIND_REQ. + */ + if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0) + goto done; + + /* + * Enable the capabilities the underlying driver claims to support. + * Some drivers require this to be called after the stream is bound. + */ + if ((err = softmac_capab_enable(slp)) != 0) + goto done; + + /* + * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. + * We don't have to wait for the ack. + */ + notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | + DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | + DL_NOTE_PROMISC_OFF_PHYS; + + (void) softmac_send_notify_req(slp, + (notifications & softmac->smac_notifications)); + +done: + if (err != 0) + (void) ldi_close(lh, FREAD|FWRITE, kcred); + return (err); +} + +static int +softmac_m_open(void *arg) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp; + int err; + + rw_enter(&softmac->smac_lock, RW_READER); + if (softmac->smac_state == SOFTMAC_READY) + goto done; + rw_exit(&softmac->smac_lock); + + if ((err = softmac_lower_setup(softmac, &slp)) != 0) + return (err); + + rw_enter(&softmac->smac_lock, RW_WRITER); + ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED); + softmac->smac_lower = slp; + softmac->smac_state = SOFTMAC_READY; +done: + rw_exit(&softmac->smac_lock); + return (0); +} + +static void +softmac_m_close(void *arg) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp; + + rw_enter(&softmac->smac_lock, RW_WRITER); + slp = softmac->smac_lower; + ASSERT(slp != NULL); + + /* + * Note that slp is destroyed when lh is closed. + */ + (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); + softmac->smac_state = SOFTMAC_INITIALIZED; + softmac->smac_lower = NULL; + rw_exit(&softmac->smac_lock); +} + +int +softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) +{ + dev_info_t *dip; + char devname[MAXNAMELEN]; + softmac_t *softmac; + int ppa, err; + + if ((ppa = getminor(dev) - 1) > 1000) + return (ENOENT); + + /* + * First try to hold this device instance to force the MAC + * to be registered. + */ + if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) + return (ENOENT); + + if ((ddi_driver_major(dip) != getmajor(dev)) || + !NETWORK_DRV(getmajor(dev))) { + ddi_release_devi(dip); + return (ENOENT); + } + + /* + * This is a network device; wait for its softmac to be registered. + */ + (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); +again: + rw_enter(&softmac_hash_lock, RW_READER); + + if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, + (mod_hash_val_t *)&softmac) != 0) { + /* + * This is rare but possible. It could happen when pre-detach + * routine of the device succeeds. But the softmac will then + * be recreated when device fails to detach (as this device + * is held). + */ + rw_exit(&softmac_hash_lock); + goto again; + } + + /* + * Bump smac_hold_cnt to prevent device detach. + */ + mutex_enter(&softmac->smac_mutex); + softmac->smac_hold_cnt++; + mutex_exit(&softmac->smac_mutex); + + rw_exit(&softmac_hash_lock); + + /* + * Wait till the device is fully attached. + */ + mutex_enter(&softmac->smac_mutex); + while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) + cv_wait(&softmac->smac_cv, &softmac->smac_mutex); + + if ((err = softmac->smac_attacherr) == 0) { + /* + * If softmac is successfully attached, set smac_udip + * which is used in softmac_rele_device(). + */ + ASSERT(softmac->smac_udip == NULL || + softmac->smac_udip == dip); + softmac->smac_udip = dip; + *ddhp = (dls_dev_handle_t)softmac; + } + mutex_exit(&softmac->smac_mutex); + + if (err != 0) + softmac_rele_device((dls_dev_handle_t)softmac); + + return (err); +} + +void +softmac_rele_device(dls_dev_handle_t ddh) +{ + softmac_t *softmac; + dev_info_t *dip; + + if (ddh == NULL) + return; + + softmac = (softmac_t *)ddh; + mutex_enter(&softmac->smac_mutex); + dip = softmac->smac_udip; + if (--softmac->smac_hold_cnt == 0) + softmac->smac_udip = NULL; + mutex_exit(&softmac->smac_mutex); + + ddi_release_devi(dip); +} diff --git a/usr/src/uts/common/io/softmac/softmac_pkt.c b/usr/src/uts/common/io/softmac/softmac_pkt.c new file mode 100644 index 0000000000..8848dc755a --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_pkt.c @@ -0,0 +1,320 @@ +/* + * 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 <sys/strsubr.h> +#include <inet/led.h> +#include <sys/softmac_impl.h> + +/* + * Macro to check whether the write-queue of the lower stream is full. + * + * Because softmac is pushed right above the underlying device and + * _I_INSERT/_I_REMOVE is not processed in the lower stream, it is + * safe to directly access the q_next pointer. + */ +#define CANPUTNEXT(q) \ + (!((q)->q_next->q_nfsrv->q_flag & QFULL) || canput((q)->q_next)) + +mblk_t * +softmac_m_tx(void *arg, mblk_t *mp) +{ + queue_t *wq = ((softmac_t *)arg)->smac_lower->sl_wq; + + /* + * Optimize for the most common case. + */ + if (mp->b_cont == NULL) { + if (!CANPUTNEXT(wq)) + return (mp); + + mp->b_flag |= MSGNOLOOP; + putnext(wq, mp); + return (NULL); + } + + while (mp != NULL) { + mblk_t *next = mp->b_next; + + if (!CANPUTNEXT(wq)) + break; + mp->b_next = NULL; + mp->b_flag |= MSGNOLOOP; + putnext(wq, mp); + mp = next; + } + return (mp); +} + +/*ARGSUSED*/ +static void +softmac_blank(void *arg, time_t ticks, uint_t count) +{ +} + +void +softmac_m_resources(void *arg) +{ + softmac_t *softmac = arg; + softmac_lower_t *slp = softmac->smac_lower; + mac_rx_fifo_t mrf; + + ASSERT((softmac->smac_state == SOFTMAC_READY) && (slp != NULL)); + + /* + * Register rx resources and save resource handle for future reference. + * Note that the mac_resources() function must be called when the lower + * stream is plumbed. + */ + + mutex_enter(&slp->sl_mutex); + + mrf.mrf_type = MAC_RX_FIFO; + mrf.mrf_blank = softmac_blank; + mrf.mrf_arg = slp; + mrf.mrf_normal_blank_time = SOFTMAC_BLANK_TICKS; + mrf.mrf_normal_pkt_count = SOFTMAC_BLANK_PKT_COUNT; + + slp->sl_handle = + mac_resource_add(softmac->smac_mh, (mac_resource_t *)&mrf); + + mutex_exit(&slp->sl_mutex); +} + +void +softmac_rput_process_data(softmac_lower_t *slp, mblk_t *mp) +{ + /* + * When packets arrive, the softmac might not be fully started. + */ + ASSERT((slp->sl_softmac != NULL)); + ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); + + if (DB_REF(mp) > 1) { + mblk_t *tmp; + + if ((tmp = copymsg(mp)) == NULL) { + cmn_err(CE_WARN, "softmac_rput_process_data: " + "copymsg failed"); + goto failed; + } + freemsg(mp); + mp = tmp; + } + + mac_rx(slp->sl_softmac->smac_mh, slp->sl_handle, mp); + return; + +failed: + freemsg(mp); +} + +#define ACKTIMEOUT (10 * hz) + +/* + * Serialize control message processing. + */ +static void +softmac_serialize_enter(softmac_lower_t *slp) +{ + mutex_enter(&slp->sl_ctl_mutex); + while (slp->sl_ctl_inprogress) + cv_wait(&slp->sl_ctl_cv, &slp->sl_ctl_mutex); + + ASSERT(!slp->sl_ctl_inprogress); + ASSERT(!slp->sl_pending_ioctl); + ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); + + slp->sl_ctl_inprogress = B_TRUE; + mutex_exit(&slp->sl_ctl_mutex); +} + +static void +softmac_serialize_exit(softmac_lower_t *slp) +{ + mutex_enter(&slp->sl_ctl_mutex); + + ASSERT(slp->sl_ctl_inprogress); + ASSERT(!slp->sl_pending_ioctl); + ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); + + slp->sl_ctl_inprogress = B_FALSE; + cv_broadcast(&slp->sl_ctl_cv); + mutex_exit(&slp->sl_ctl_mutex); +} + +static int +dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno) +{ + return (error == DL_SYSERR ? unix_errno : EINVAL); +} + +static int +softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim, + t_uscalar_t ack, mblk_t **mpp) +{ + union DL_primitives *dlp; + int err = 0; + + softmac_serialize_enter(slp); + + /* + * Record the pending DLPI primitive. + */ + mutex_enter(&slp->sl_mutex); + slp->sl_pending_prim = dl_prim; + mutex_exit(&slp->sl_mutex); + + putnext(slp->sl_wq, mp); + + mutex_enter(&slp->sl_mutex); + while (slp->sl_pending_prim != DL_PRIM_INVAL) { + if (cv_timedwait(&slp->sl_cv, &slp->sl_mutex, + lbolt + ACKTIMEOUT) == -1) + break; + } + + mp = slp->sl_ack_mp; + slp->sl_ack_mp = NULL; + + /* + * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim + * won't be set to DL_PRIM_INVAL. + */ + ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL); + + slp->sl_pending_prim = DL_PRIM_INVAL; + mutex_exit(&slp->sl_mutex); + + if (mp != NULL) { + dlp = (union DL_primitives *)mp->b_rptr; + + if (dlp->dl_primitive == DL_ERROR_ACK) { + err = dlpi_get_errno(dlp->error_ack.dl_errno, + dlp->error_ack.dl_unix_errno); + } else { + ASSERT(dlp->dl_primitive == ack); + } + } else { + err = ENOMSG; + } + + if (mpp != NULL) + *mpp = mp; + else + freemsg(mp); + + softmac_serialize_exit(slp); + return (err); +} + +void +softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) +{ + softmac_serialize_enter(slp); + + /* + * Record that ioctl processing is currently in progress. + */ + mutex_enter(&slp->sl_mutex); + slp->sl_pending_ioctl = B_TRUE; + mutex_exit(&slp->sl_mutex); + + putnext(slp->sl_wq, mp); + + mutex_enter(&slp->sl_mutex); + while (slp->sl_pending_ioctl) + cv_wait(&slp->sl_cv, &slp->sl_mutex); + mp = slp->sl_ack_mp; + slp->sl_ack_mp = NULL; + mutex_exit(&slp->sl_mutex); + + ASSERT(mpp != NULL && mp != NULL); + *mpp = mp; + + softmac_serialize_exit(slp); +} + +static int +softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive, + t_uscalar_t error, t_uscalar_t unix_errno) +{ + union DL_primitives *dlp; + + if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO, + DL_ERROR_ACK)) == NULL) + return (ENOMEM); + + dlp = (union DL_primitives *)(*mpp)->b_rptr; + dlp->error_ack.dl_error_primitive = error_primitive; + dlp->error_ack.dl_errno = error; + dlp->error_ack.dl_unix_errno = unix_errno; + + return (0); +} + +int +softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) +{ + int err = 0; + t_uscalar_t dl_prim; + + dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; + + ASSERT(slp->sl_softmac != NULL); + + switch (dl_prim) { + case DL_ENABMULTI_REQ: + case DL_DISABMULTI_REQ: + case DL_SET_PHYS_ADDR_REQ: + case DL_UNBIND_REQ: + case DL_UDQOS_REQ: + case DL_PROMISCON_REQ: + case DL_PROMISCOFF_REQ: + err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp); + break; + case DL_BIND_REQ: + err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp); + break; + case DL_NOTIFY_REQ: + err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp); + break; + case DL_CONTROL_REQ: + err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp); + break; + case DL_CAPABILITY_REQ: + err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp); + break; + default: + if (mpp != NULL) { + *mpp = mp; + err = softmac_mexchange_error_ack(mpp, dl_prim, + DL_UNSUPPORTED, 0); + } + break; + } + return (err); +} diff --git a/usr/src/uts/common/io/softmac/softmac_stat.c b/usr/src/uts/common/io/softmac/softmac_stat.c new file mode 100644 index 0000000000..78b5306c86 --- /dev/null +++ b/usr/src/uts/common/io/softmac/softmac_stat.c @@ -0,0 +1,270 @@ +/* + * 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 <sys/types.h> +#include <sys/kstat.h> +#include <sys/mac.h> +#include <sys/dls.h> +#include <sys/softmac_impl.h> + +typedef struct i_softmac_stat_info_s { + uint_t ssi_stat; + char *ssi_name; + char *ssi_alias; +} i_softmac_stat_info_t; + +/* + * Must be the same order as mac_driver_stat. + */ +static i_softmac_stat_info_t i_softmac_driver_si[] = { + { MAC_STAT_IFSPEED, "ifspeed", "link_speed" }, + { MAC_STAT_MULTIRCV, "multircv", NULL }, + { MAC_STAT_BRDCSTRCV, "brdcstrcv", NULL }, + { MAC_STAT_MULTIXMT, "multixmt", NULL }, + { MAC_STAT_BRDCSTXMT, "brdcstxmt", NULL }, + { MAC_STAT_NORCVBUF, "norcvbuf", "rx_no_buf" }, + { MAC_STAT_IERRORS, "ierrors", NULL }, + { MAC_STAT_UNKNOWNS, "unknowns", NULL }, + { MAC_STAT_NOXMTBUF, "noxmtbuf", "No Txpkt " }, + { MAC_STAT_OERRORS, "oerrors", NULL }, + { MAC_STAT_COLLISIONS, "collisions", NULL }, + { MAC_STAT_RBYTES, "rbytes64", "rbytes" }, + { MAC_STAT_IPACKETS, "ipackets64", "ipackets" }, + { MAC_STAT_OBYTES, "obytes64", "obytes" }, + { MAC_STAT_OPACKETS, "opackets64", "opackets" }, + { MAC_STAT_UNDERFLOWS, "uflo", NULL }, + { MAC_STAT_OVERFLOWS, "oflo", NULL } +}; + +/* + * Must be the same order as ether_stat. + */ +static i_softmac_stat_info_t i_softmac_ether_si[] = { + { ETHER_STAT_ALIGN_ERRORS, "align_errors", + "alignment_err" }, + { ETHER_STAT_FCS_ERRORS, "fcs_errors", "crc_err" }, + { ETHER_STAT_FIRST_COLLISIONS, "first_collisions", NULL }, + { ETHER_STAT_MULTI_COLLISIONS, "multi_collisions", NULL }, + { ETHER_STAT_SQE_ERRORS, "sqe_errors", NULL }, + { ETHER_STAT_DEFER_XMTS, "defer_xmts", NULL }, + { ETHER_STAT_TX_LATE_COLLISIONS, "tx_late_collisions", + "late_collisions" }, + { ETHER_STAT_EX_COLLISIONS, "ex_collisions", + "excessive_collisions" }, + { ETHER_STAT_MACXMT_ERRORS, "macxmt_errors", NULL }, + { ETHER_STAT_CARRIER_ERRORS, "carrier_errors", NULL }, + { ETHER_STAT_TOOLONG_ERRORS, "toolong_errors", "length_err" }, + { ETHER_STAT_MACRCV_ERRORS, "macrcv_errors", + "Rx Error Count" }, + + { ETHER_STAT_XCVR_ADDR, "xcvr_addr", NULL }, + { ETHER_STAT_XCVR_ID, "xcvr_id", NULL }, + { ETHER_STAT_XCVR_INUSE, "xcvr_inuse", NULL }, + + { ETHER_STAT_CAP_1000FDX, "cap_1000fdx", NULL }, + { ETHER_STAT_CAP_1000HDX, "cap_1000hdx", NULL }, + { ETHER_STAT_CAP_100FDX, "cap_100fdx", NULL }, + { ETHER_STAT_CAP_100HDX, "cap_100hdx", NULL }, + { ETHER_STAT_CAP_10FDX, "cap_10fdx", NULL }, + { ETHER_STAT_CAP_10HDX, "cap_10hdx", NULL }, + { ETHER_STAT_CAP_ASMPAUSE, "cap_asmpause", NULL }, + { ETHER_STAT_CAP_PAUSE, "cap_pause", NULL }, + { ETHER_STAT_CAP_AUTONEG, "cap_autoneg", NULL }, + + { ETHER_STAT_ADV_CAP_1000FDX, "adv_cap_1000fdx", NULL }, + { ETHER_STAT_ADV_CAP_1000HDX, "adv_cap_1000hdx", NULL }, + { ETHER_STAT_ADV_CAP_100FDX, "adv_cap_100fdx", NULL }, + { ETHER_STAT_ADV_CAP_100HDX, "adv_cap_100hdx", NULL }, + { ETHER_STAT_ADV_CAP_10FDX, "adv_cap_10fdx", NULL }, + { ETHER_STAT_ADV_CAP_10HDX, "adv_cap_10hdx", NULL }, + { ETHER_STAT_ADV_CAP_ASMPAUSE, "adv_cap_asmpause", NULL }, + { ETHER_STAT_ADV_CAP_PAUSE, "adv_cap_pause", NULL }, + { ETHER_STAT_ADV_CAP_AUTONEG, "adv_cap_autoneg", NULL }, + + { ETHER_STAT_LP_CAP_1000FDX, "lp_cap_1000fdx", NULL }, + { ETHER_STAT_LP_CAP_1000HDX, "lp_cap_1000hdx", NULL }, + { ETHER_STAT_LP_CAP_100FDX, "lp_cap_100fdx", NULL }, + { ETHER_STAT_LP_CAP_100HDX, "lp_cap_100hdx", NULL }, + { ETHER_STAT_LP_CAP_10FDX, "lp_cap_10fdx", NULL }, + { ETHER_STAT_LP_CAP_10HDX, "lp_cap_10hdx", NULL }, + { ETHER_STAT_LP_CAP_ASMPAUSE, "lp_cap_asmpause", NULL }, + { ETHER_STAT_LP_CAP_PAUSE, "lp_cap_pause", NULL }, + { ETHER_STAT_LP_CAP_AUTONEG, "lp_cap_autoneg", NULL }, + + { ETHER_STAT_LINK_ASMPAUSE, "link_asmpause", NULL }, + { ETHER_STAT_LINK_PAUSE, "link_pause", NULL }, + { ETHER_STAT_LINK_AUTONEG, "link_autoneg", NULL }, + { ETHER_STAT_LINK_DUPLEX, "link_duplex", "duplex" }, + + { ETHER_STAT_TOOSHORT_ERRORS, "runt_errors", NULL }, + { ETHER_STAT_CAP_REMFAULT, "cap_rem_fault", NULL }, + { ETHER_STAT_ADV_REMFAULT, "adv_rem_fault", NULL }, + { ETHER_STAT_LP_REMFAULT, "lp_rem_fault", NULL }, + + { ETHER_STAT_JABBER_ERRORS, "jabber_errors", NULL }, + { ETHER_STAT_CAP_100T4, "cap_100T4", NULL }, + { ETHER_STAT_ADV_CAP_100T4, "adv_cap_100T4", NULL }, + { ETHER_STAT_LP_CAP_100T4, "lp_cap_100T4", NULL } +}; + +static kstat_t *softmac_hold_dev_kstat(softmac_t *); +static void softmac_rele_dev_kstat(kstat_t *); +static int softmac_get_kstat(kstat_t *, char *, uint64_t *); + +static kstat_t * +softmac_hold_dev_kstat(softmac_t *softmac) +{ + char drv[MAXLINKNAMELEN]; + uint_t ppa; + kstat_t *ksp; + + if (ddi_parse(softmac->smac_devname, drv, &ppa) != DDI_SUCCESS) + return (NULL); + + /* + * Find the kstat by the module name and the instance number. + */ + ksp = kstat_hold_byname(drv, ppa, softmac->smac_devname, ALL_ZONES); + if (ksp != NULL) { + KSTAT_ENTER(ksp); + + if ((ksp->ks_data != NULL) && + (ksp->ks_type == KSTAT_TYPE_NAMED)) { + /* + * Update the kstat to get the latest statistics. + */ + if (KSTAT_UPDATE(ksp, KSTAT_READ) == 0) + return (ksp); + } + + KSTAT_EXIT(ksp); + kstat_rele(ksp); + } + return (NULL); +} + +static void +softmac_rele_dev_kstat(kstat_t *ksp) +{ + KSTAT_EXIT(ksp); + kstat_rele(ksp); +} + +/* + * The kstat needs to be held when calling this function. + */ +static int +softmac_get_kstat(kstat_t *ksp, char *name, uint64_t *valp) +{ + kstat_named_t *knp; + int i; + int ret = ENOTSUP; + + if (name == NULL) + return (ret); + + /* + * Search the kstat with the given name. + */ + for (i = 0, knp = KSTAT_NAMED_PTR(ksp); i < ksp->ks_ndata; i++, knp++) { + if (strcmp(knp->name, name) == 0) { + switch (knp->data_type) { + case KSTAT_DATA_INT32: + case KSTAT_DATA_UINT32: + *valp = (uint64_t)(knp->value.ui32); + ret = 0; + break; + case KSTAT_DATA_INT64: + case KSTAT_DATA_UINT64: + *valp = knp->value.ui64; + ret = 0; + break; +#ifdef _LP64 + case KSTAT_DATA_LONG: + case KSTAT_DATA_ULONG: + *valp = (uint64_t)knp->value.ul; + ret = 0; + break; +#endif + case KSTAT_DATA_CHAR: + if (strcmp(name, "duplex") != 0) + break; + if (strncmp(knp->value.c, "full", 4) == 0) + *valp = LINK_DUPLEX_FULL; + else if (strncmp(knp->value.c, "half", 4) == 0) + *valp = LINK_DUPLEX_HALF; + else + *valp = LINK_DUPLEX_UNKNOWN; + ret = 0; + break; + } + break; + } + } + + return (ret); +} + +int +softmac_m_stat(void *arg, uint_t stat, uint64_t *val) +{ + softmac_t *softmac = arg; + kstat_t *ksp; + uint_t index; + int ret; + + if ((ksp = softmac_hold_dev_kstat(softmac)) == NULL) + return (ENOTSUP); + + if (IS_MAC_STAT(stat)) { + index = stat - MAC_STAT_MIN; + if ((ret = softmac_get_kstat(ksp, + i_softmac_driver_si[index].ssi_name, val)) != 0) { + ret = softmac_get_kstat(ksp, + i_softmac_driver_si[index].ssi_alias, val); + } + } else { + ASSERT(IS_MACTYPE_STAT(stat)); + index = stat - MACTYPE_STAT_MIN; + + switch (softmac->smac_media) { + case DL_ETHER: + if ((ret = softmac_get_kstat(ksp, + i_softmac_ether_si[index].ssi_name, val)) != 0) { + ret = softmac_get_kstat(ksp, + i_softmac_ether_si[index].ssi_alias, val); + } + break; + default: + ret = ENOTSUP; + break; + } + } + + softmac_rele_dev_kstat(ksp); + return (ret); +} diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index 644d83c352..6f20d98a5a 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.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. */ @@ -626,12 +626,8 @@ done: static uchar_t boot_macaddr[16]; static int boot_maclen; -static uchar_t *getmacaddr(dev_info_t *dip, int *maclen); +static uchar_t *getmacaddr(dev_info_t *dip, size_t *maclenp); static int matchmac(dev_info_t *dip, void *arg); -int dl_attach(ldi_handle_t lh, int unit); -int dl_bind(ldi_handle_t lh, uint_t sap, uint_t max_conn, - uint_t service, uint_t conn_mgmt); -int dl_phys_addr(ldi_handle_t lh, struct ether_addr *eaddr); #endif /* !_OBP */ @@ -705,7 +701,7 @@ matchmac(dev_info_t *dip, void *arg) char **devpathp = (char **)arg; char *model_str; uchar_t *macaddr; - int maclen; + size_t maclen; /* XXX Should use "device-type" per IEEE 1275 */ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, @@ -750,40 +746,15 @@ matchmac(dev_info_t *dip, void *arg) } static uchar_t * -getmacaddr_gldv3(char *drv, int inst, int *maclenp) -{ - char ifname[16]; - mac_handle_t mh; - uchar_t *macaddr; - - (void) snprintf(ifname, sizeof (ifname), "%s%d", drv, inst); - if (mac_open(ifname, &mh) < 0) { - return (NULL); - } - *maclenp = sizeof (struct ether_addr); - macaddr = kmem_alloc(*maclenp, KM_SLEEP); - mac_unicst_get(mh, macaddr); - mac_close(mh); - - return (macaddr); -} - -static uchar_t * -getmacaddr(dev_info_t *dip, int *maclenp) +getmacaddr(dev_info_t *dip, size_t *maclenp) { int rc, ppa; ldi_ident_t li; ldi_handle_t lh; - char *drv_name = (char *)ddi_driver_name(dip); + const char *drv_name = ddi_driver_name(dip); char *clonepath; uchar_t *macaddr = NULL; - /* a simpler way to get mac address for GLDv3 drivers */ - if (GLDV3_DRV(ddi_name_to_major(drv_name))) { - return (getmacaddr_gldv3(drv_name, ddi_get_instance(dip), - maclenp)); - } - if (rc = ldi_ident_from_mod(&modlinkage, &li)) { cmn_err(CE_WARN, "getmacaddr: ldi_ident_from_mod failed: %d\n", rc); @@ -806,245 +777,27 @@ getmacaddr(dev_info_t *dip, int *maclenp) kmem_free(clonepath, MAXPATHLEN); ppa = i_ddi_devi_get_ppa(dip); - if ((dl_attach(lh, ppa) != 0) || - (dl_bind(lh, ETHERTYPE_IP, 0, DL_CLDLS, 0) != 0)) { + if ((dl_attach(lh, ppa, NULL) != 0) || + (dl_bind(lh, ETHERTYPE_IP, NULL) != 0)) { (void) ldi_close(lh, FREAD|FWRITE, CRED()); cmn_err(CE_WARN, "getmacaddr: dl_attach/bind(%s%d) failed: %d\n", drv_name, ppa, rc); return (NULL); } - *maclenp = sizeof (struct ether_addr); - macaddr = kmem_alloc(*maclenp, KM_SLEEP); - if (dl_phys_addr(lh, (struct ether_addr *)macaddr) != 0) { - kmem_free(macaddr, *maclenp); + + *maclenp = ETHERADDRL; + macaddr = kmem_alloc(ETHERADDRL, KM_SLEEP); + if (dl_phys_addr(lh, macaddr, maclenp, NULL) != 0 || + *maclenp != ETHERADDRL) { + kmem_free(macaddr, ETHERADDRL); macaddr = NULL; *maclenp = 0; cmn_err(CE_WARN, - "getmacaddr: dl_macaddr(%s%d) failed: %d\n", + "getmacaddr: dl_phys_addr(%s%d) failed: %d\n", drv_name, ppa, rc); } (void) ldi_close(lh, FREAD|FWRITE, CRED()); return (macaddr); } - #endif /* !_OBP */ - -int -dl_attach(ldi_handle_t lh, int unit) -{ - dl_attach_req_t *attach_req; - union DL_primitives *dl_prim; - mblk_t *mp; - int error; - - if ((mp = allocb(sizeof (dl_attach_req_t), BPRI_MED)) == NULL) { - cmn_err(CE_WARN, "dl_attach: allocb failed"); - return (ENOSR); - } - mp->b_datap->db_type = M_PROTO; - mp->b_wptr += sizeof (dl_attach_req_t); - - attach_req = (dl_attach_req_t *)mp->b_rptr; - attach_req->dl_primitive = DL_ATTACH_REQ; - attach_req->dl_ppa = unit; - - (void) ldi_putmsg(lh, mp); - if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { - cmn_err(CE_NOTE, "!dl_attach: ldi_getmsg failed: %d", error); - return (error); - } - - dl_prim = (union DL_primitives *)mp->b_rptr; - switch (dl_prim->dl_primitive) { - case DL_OK_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_ok_ack_t)) { - cmn_err(CE_NOTE, - "!dl_attach: DL_OK_ACK protocol error"); - break; - } - if (((dl_ok_ack_t *)dl_prim)->dl_correct_primitive != - DL_ATTACH_REQ) { - cmn_err(CE_NOTE, "!dl_attach: DL_OK_ACK rtnd prim %u", - ((dl_ok_ack_t *)dl_prim)->dl_correct_primitive); - break; - } - freemsg(mp); - return (0); - - case DL_ERROR_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { - cmn_err(CE_NOTE, - "!dl_attach: DL_ERROR_ACK protocol error"); - break; - } - break; - - default: - cmn_err(CE_NOTE, "!dl_attach: bad ACK header %u", - dl_prim->dl_primitive); - break; - } - - /* - * Error return only. - */ - freemsg(mp); - return (-1); -} - -int -dl_bind(ldi_handle_t lh, uint_t sap, uint_t max_conn, uint_t service, - uint_t conn_mgmt) -{ - dl_bind_req_t *bind_req; - union DL_primitives *dl_prim; - mblk_t *mp; - int error; - - if ((mp = allocb(sizeof (dl_bind_req_t), BPRI_MED)) == NULL) { - cmn_err(CE_WARN, "dl_bind: allocb failed"); - return (ENOSR); - } - mp->b_datap->db_type = M_PROTO; - - bind_req = (dl_bind_req_t *)mp->b_wptr; - mp->b_wptr += sizeof (dl_bind_req_t); - bind_req->dl_primitive = DL_BIND_REQ; - bind_req->dl_sap = sap; - bind_req->dl_max_conind = max_conn; - bind_req->dl_service_mode = service; - bind_req->dl_conn_mgmt = conn_mgmt; - bind_req->dl_xidtest_flg = 0; - - (void) ldi_putmsg(lh, mp); - if ((error = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) { - cmn_err(CE_NOTE, "!dl_bind: ldi_getmsg failed: %d", error); - return (error); - } - - dl_prim = (union DL_primitives *)mp->b_rptr; - switch (dl_prim->dl_primitive) { - case DL_BIND_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_bind_ack_t)) { - cmn_err(CE_NOTE, - "!dl_bind: DL_BIND_ACK protocol error"); - break; - } - if (((dl_bind_ack_t *)dl_prim)->dl_sap != sap) { - cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK bad sap %u", - ((dl_bind_ack_t *)dl_prim)->dl_sap); - break; - } - freemsg(mp); - return (0); - - case DL_ERROR_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { - cmn_err(CE_NOTE, - "!dl_bind: DL_ERROR_ACK protocol error"); - break; - } - break; - - default: - cmn_err(CE_NOTE, "!dl_bind: bad ACK header %u", - dl_prim->dl_primitive); - break; - } - - /* - * Error return only. - */ - freemsg(mp); - return (-1); -} - -int -dl_phys_addr(ldi_handle_t lh, struct ether_addr *eaddr) -{ - dl_phys_addr_req_t *phys_addr_req; - dl_phys_addr_ack_t *phys_addr_ack; - union DL_primitives *dl_prim; - mblk_t *mp; - int error; - uchar_t *addrp; - timestruc_t tv; - - if ((mp = allocb(sizeof (dl_phys_addr_req_t), BPRI_MED)) == - (mblk_t *)NULL) { - cmn_err(CE_WARN, "dl_phys_addr: allocb failed"); - return (ENOSR); - } - mp->b_datap->db_type = M_PROTO; - mp->b_wptr += sizeof (dl_phys_addr_req_t); - - phys_addr_req = (dl_phys_addr_req_t *)mp->b_rptr; - phys_addr_req->dl_primitive = DL_PHYS_ADDR_REQ; - phys_addr_req->dl_addr_type = DL_CURR_PHYS_ADDR; - - /* - * In case some provider doesn't implement or nack the - * request just wait for 15 seconds. - */ - tv.tv_sec = 15; - tv.tv_nsec = 0; - - (void) ldi_putmsg(lh, mp); - error = ldi_getmsg(lh, &mp, &tv); - if (error == ETIME) { - cmn_err(CE_NOTE, "!dl_phys_addr: timed out"); - return (-1); - } else if (error != 0) { - cmn_err(CE_NOTE, "!dl_phys_addr: ldi_getmsg failed: %d", error); - return (error); - } - - dl_prim = (union DL_primitives *)mp->b_rptr; - switch (dl_prim->dl_primitive) { - case DL_PHYS_ADDR_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_phys_addr_ack_t)) { - cmn_err(CE_NOTE, "!dl_phys_addr: " - "DL_PHYS_ADDR_ACK protocol error"); - break; - } - phys_addr_ack = &dl_prim->physaddr_ack; - if (phys_addr_ack->dl_addr_length != sizeof (*eaddr)) { - cmn_err(CE_NOTE, - "!dl_phys_addr: DL_PHYS_ADDR_ACK bad len %u", - phys_addr_ack->dl_addr_length); - break; - } - if (phys_addr_ack->dl_addr_length + - phys_addr_ack->dl_addr_offset > (mp->b_wptr-mp->b_rptr)) { - cmn_err(CE_NOTE, - "!dl_phys_addr: DL_PHYS_ADDR_ACK bad len %u", - phys_addr_ack->dl_addr_length); - break; - } - addrp = mp->b_rptr + phys_addr_ack->dl_addr_offset; - bcopy(addrp, eaddr, sizeof (*eaddr)); - freemsg(mp); - return (0); - - case DL_ERROR_ACK: - if ((mp->b_wptr-mp->b_rptr) < sizeof (dl_error_ack_t)) { - cmn_err(CE_NOTE, - "!dl_phys_addr: DL_ERROR_ACK protocol error"); - break; - } - - break; - - default: - cmn_err(CE_NOTE, "!dl_phys_addr: bad ACK header %u", - dl_prim->dl_primitive); - break; - } - - /* - * Error return only. - */ - freemsg(mp); - return (-1); -} diff --git a/usr/src/uts/common/io/sundlpi.c b/usr/src/uts/common/io/sundlpi.c index 80c3a6d722..43d5db0e5e 100644 --- a/usr/src/uts/common/io/sundlpi.c +++ b/usr/src/uts/common/io/sundlpi.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. */ @@ -36,6 +36,10 @@ #include <sys/stream.h> #include <sys/strsun.h> #include <sys/dlpi.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/cmn_err.h> #define DLADDRL (80) @@ -195,3 +199,390 @@ dlnotifyack( dlp->notify_ack.dl_notifications = notifications; qreply(wq, mp); } + +static int +dl_op(ldi_handle_t lh, mblk_t **mpp, t_uscalar_t expprim, size_t minlen, + dl_error_ack_t *dleap, timestruc_t *tvp) +{ + int err; + size_t len; + mblk_t *mp = *mpp; + t_uscalar_t reqprim, ackprim, ackreqprim; + union DL_primitives *dlp; + + reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; + + (void) ldi_putmsg(lh, mp); + + switch (err = ldi_getmsg(lh, &mp, tvp)) { + case 0: + break; + case ETIME: + cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s", + dl_primstr(reqprim), dl_primstr(expprim)); + return (ETIME); + default: + cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d", + dl_primstr(expprim), err); + return (err); + } + + len = MBLKL(mp); + if (len < sizeof (t_uscalar_t)) { + cmn_err(CE_NOTE, "!dl_op: received runt DLPI message"); + freemsg(mp); + return (EBADMSG); + } + + dlp = (union DL_primitives *)mp->b_rptr; + ackprim = dlp->dl_primitive; + + if (ackprim == expprim) { + if (len < minlen) + goto runt; + + if (ackprim == DL_OK_ACK) { + if (dlp->ok_ack.dl_correct_primitive != reqprim) { + ackreqprim = dlp->ok_ack.dl_correct_primitive; + goto mixup; + } + } + *mpp = mp; + return (0); + } + + if (ackprim == DL_ERROR_ACK) { + if (len < DL_ERROR_ACK_SIZE) + goto runt; + + if (dlp->error_ack.dl_error_primitive != reqprim) { + ackreqprim = dlp->error_ack.dl_error_primitive; + goto mixup; + } + + /* + * Return a special error code (ENOTSUP) indicating that the + * caller has returned DL_ERROR_ACK. Callers that want more + * details an pass a non-NULL dleap. + */ + if (dleap != NULL) + *dleap = dlp->error_ack; + + freemsg(mp); + return (ENOTSUP); + } + + cmn_err(CE_NOTE, "!dl_op: expected %s but received %s", + dl_primstr(expprim), dl_primstr(ackprim)); + freemsg(mp); + return (EBADMSG); +runt: + cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim)); + freemsg(mp); + return (EBADMSG); +mixup: + cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s", + dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim)); + freemsg(mp); + return (EBADMSG); +} + +/* + * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response. + * + * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the + * caller can get the contents by passing a non-NULL `dleap'). + */ +int +dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap) +{ + mblk_t *mp; + int err; + + mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ); + if (mp == NULL) + return (ENOMEM); + + ((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa; + + err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL); + if (err == 0) + freemsg(mp); + return (err); +} + +/* + * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response. + * + * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the + * caller can get the contents by passing a non-NULL `dleap'). + */ +int +dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap) +{ + dl_bind_req_t *dlbrp; + dl_bind_ack_t *dlbap; + mblk_t *mp; + int err; + + mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ); + if (mp == NULL) + return (ENOMEM); + + dlbrp = (dl_bind_req_t *)mp->b_rptr; + dlbrp->dl_sap = sap; + dlbrp->dl_conn_mgmt = 0; + dlbrp->dl_max_conind = 0; + dlbrp->dl_xidtest_flg = 0; + dlbrp->dl_service_mode = DL_CLDLS; + + err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL); + if (err == 0) { + dlbap = (dl_bind_ack_t *)mp->b_rptr; + if (dlbap->dl_sap != sap) { + cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK: bad sap %u", + dlbap->dl_sap); + err = EPROTO; + } + freemsg(mp); + } + return (err); +} + +/* + * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response. The caller + * must set `*physlenp' to the size of `physaddr' (both of which must be + * non-NULL); upon success they will be updated to contain the actual physical + * address and length. + * + * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the + * caller can get the contents by passing a non-NULL `dleap'). + */ +int +dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp, + dl_error_ack_t *dleap) +{ + dl_phys_addr_ack_t *dlpap; + mblk_t *mp; + int err; + t_uscalar_t paddrlen, paddroff; + timestruc_t tv; + + mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO, + DL_PHYS_ADDR_REQ); + if (mp == NULL) + return (ENOMEM); + + ((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR; + + /* + * In case some provider doesn't implement or NAK the + * request, just wait for 15 seconds. + */ + tv.tv_sec = 15; + tv.tv_nsec = 0; + + err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap, + &tv); + if (err == 0) { + dlpap = (dl_phys_addr_ack_t *)mp->b_rptr; + paddrlen = dlpap->dl_addr_length; + paddroff = dlpap->dl_addr_offset; + if (paddroff == 0 || paddrlen == 0 || paddrlen > *physlenp || + !MBLKIN(mp, paddroff, paddrlen)) { + cmn_err(CE_NOTE, "!dl_phys_addr: DL_PHYS_ADDR_ACK: " + "bad length/offset %d/%d", paddrlen, paddroff); + err = EBADMSG; + } else { + bcopy(mp->b_rptr + paddroff, physaddr, paddrlen); + *physlenp = paddrlen; + } + freemsg(mp); + } + return (err); +} + +/* + * Send a DL_INFO_REQ over `lh' and wait for the response. The caller must + * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t + * from the provider. The caller may optionally get the provider's physical + * address by passing a non-NULL `physaddr' and setting `*physlenp' to its + * size; upon success they will be updated to contain the actual physical + * address and its length. + * + * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the + * caller can get the contents by passing a non-NULL `dleap'). + */ +int +dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr, + size_t *physlenp, dl_error_ack_t *dleap) +{ + mblk_t *mp; + int err; + int addrlen, addroff; + + mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ); + if (mp == NULL) + return (ENOMEM); + + err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL); + if (err != 0) + return (err); + + *dliap = *(dl_info_ack_t *)mp->b_rptr; + if (physaddr != NULL) { + addrlen = dliap->dl_addr_length - ABS(dliap->dl_sap_length); + addroff = dliap->dl_addr_offset; + if (addroff == 0 || addrlen <= 0 || addrlen > *physlenp || + !MBLKIN(mp, addroff, dliap->dl_addr_length)) { + cmn_err(CE_NOTE, "!dl_info: DL_INFO_ACK: " + "bad length/offset %d/%d", addrlen, addroff); + freemsg(mp); + return (EBADMSG); + } + + if (dliap->dl_sap_length > 0) + addroff += dliap->dl_sap_length; + bcopy(mp->b_rptr + addroff, physaddr, addrlen); + *physlenp = addrlen; + } + freemsg(mp); + return (err); +} + +/* + * Send a DL_NOTIFY_REQ over `lh' and wait for the response. The caller + * should set `notesp' to the set of notifications they wish to enable; + * upon success it will contain the notifications enabled by the provider. + * + * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the + * caller can get the contents by passing a non-NULL `dleap'). + */ +int +dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap) +{ + mblk_t *mp; + int err; + + mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ); + if (mp == NULL) + return (ENOMEM); + + ((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp; + + err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL); + if (err == 0) { + *notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications; + freemsg(mp); + } + return (err); +} + +const char * +dl_primstr(t_uscalar_t prim) +{ + switch (prim) { + case DL_INFO_REQ: return ("DL_INFO_REQ"); + case DL_INFO_ACK: return ("DL_INFO_ACK"); + case DL_ATTACH_REQ: return ("DL_ATTACH_REQ"); + case DL_DETACH_REQ: return ("DL_DETACH_REQ"); + case DL_BIND_REQ: return ("DL_BIND_REQ"); + case DL_BIND_ACK: return ("DL_BIND_ACK"); + case DL_UNBIND_REQ: return ("DL_UNBIND_REQ"); + case DL_OK_ACK: return ("DL_OK_ACK"); + case DL_ERROR_ACK: return ("DL_ERROR_ACK"); + case DL_ENABMULTI_REQ: return ("DL_ENABMULTI_REQ"); + case DL_DISABMULTI_REQ: return ("DL_DISABMULTI_REQ"); + case DL_PROMISCON_REQ: return ("DL_PROMISCON_REQ"); + case DL_PROMISCOFF_REQ: return ("DL_PROMISCOFF_REQ"); + case DL_UNITDATA_REQ: return ("DL_UNITDATA_REQ"); + case DL_UNITDATA_IND: return ("DL_UNITDATA_IND"); + case DL_UDERROR_IND: return ("DL_UDERROR_IND"); + case DL_PHYS_ADDR_REQ: return ("DL_PHYS_ADDR_REQ"); + case DL_PHYS_ADDR_ACK: return ("DL_PHYS_ADDR_ACK"); + case DL_SET_PHYS_ADDR_REQ: return ("DL_SET_PHYS_ADDR_REQ"); + case DL_NOTIFY_REQ: return ("DL_NOTIFY_REQ"); + case DL_NOTIFY_ACK: return ("DL_NOTIFY_ACK"); + case DL_NOTIFY_IND: return ("DL_NOTIFY_IND"); + case DL_CAPABILITY_REQ: return ("DL_CAPABILITY_REQ"); + case DL_CAPABILITY_ACK: return ("DL_CAPABILITY_ACK"); + case DL_CONTROL_REQ: return ("DL_CONTROL_REQ"); + case DL_CONTROL_ACK: return ("DL_CONTROL_ACK"); + case DL_PASSIVE_REQ: return ("DL_PASSIVE_REQ"); + case DL_INTR_MODE_REQ: return ("DL_INTR_MODE_REQ"); + case DL_UDQOS_REQ: return ("DL_UDQOS_REQ"); + default: return ("<unknown primitive>"); + } +} + +const char * +dl_errstr(t_uscalar_t err) +{ + switch (err) { + case DL_ACCESS: return ("DL_ACCESS"); + case DL_BADADDR: return ("DL_BADADDR"); + case DL_BADCORR: return ("DL_BADCORR"); + case DL_BADDATA: return ("DL_BADDATA"); + case DL_BADPPA: return ("DL_BADPPA"); + case DL_BADPRIM: return ("DL_BADPRIM"); + case DL_BADQOSPARAM: return ("DL_BADQOSPARAM"); + case DL_BADQOSTYPE: return ("DL_BADQOSTYPE"); + case DL_BADSAP: return ("DL_BADSAP"); + case DL_BADTOKEN: return ("DL_BADTOKEN"); + case DL_BOUND: return ("DL_BOUND"); + case DL_INITFAILED: return ("DL_INITFAILED"); + case DL_NOADDR: return ("DL_NOADDR"); + case DL_NOTINIT: return ("DL_NOTINIT"); + case DL_OUTSTATE: return ("DL_OUTSTATE"); + case DL_SYSERR: return ("DL_SYSERR"); + case DL_UNSUPPORTED: return ("DL_UNSUPPORTED"); + case DL_UNDELIVERABLE: return ("DL_UNDELIVERABLE"); + case DL_NOTSUPPORTED: return ("DL_NOTSUPPORTED "); + case DL_TOOMANY: return ("DL_TOOMANY"); + case DL_NOTENAB: return ("DL_NOTENAB"); + case DL_BUSY: return ("DL_BUSY"); + case DL_NOAUTO: return ("DL_NOAUTO"); + case DL_NOXIDAUTO: return ("DL_NOXIDAUTO"); + case DL_NOTESTAUTO: return ("DL_NOTESTAUTO"); + case DL_XIDAUTO: return ("DL_XIDAUTO"); + case DL_TESTAUTO: return ("DL_TESTAUTO"); + case DL_PENDING: return ("DL_PENDING"); + default: return ("<unknown error>"); + } +} + +const char * +dl_mactypestr(t_uscalar_t mactype) +{ + switch (mactype) { + case DL_CSMACD: return ("CSMA/CD"); + case DL_TPB: return ("Token Bus"); + case DL_TPR: return ("Token Ring"); + case DL_METRO: return ("Metro Net"); + case DL_ETHER: return ("Ethernet"); + case DL_HDLC: return ("HDLC"); + case DL_CHAR: return ("Sync Character"); + case DL_CTCA: return ("CTCA"); + case DL_FDDI: return ("FDDI"); + case DL_FRAME: return ("Frame Relay (LAPF)"); + case DL_MPFRAME: return ("MP Frame Relay"); + case DL_ASYNC: return ("Async Character"); + case DL_IPX25: return ("X.25 (Classic IP)"); + case DL_LOOP: return ("Software Loopback"); + case DL_FC: return ("Fiber Channel"); + case DL_ATM: return ("ATM"); + case DL_IPATM: return ("ATM (Classic IP)"); + case DL_X25: return ("X.25 (LAPB)"); + case DL_ISDN: return ("ISDN"); + case DL_HIPPI: return ("HIPPI"); + case DL_100VG: return ("100BaseVG Ethernet"); + case DL_100VGTPR: return ("100BaseVG Token Ring"); + case DL_ETH_CSMA: return ("Ethernet/IEEE 802.3"); + case DL_100BT: return ("100BaseT"); + case DL_IB: return ("Infiniband"); + case DL_IPV4: return ("IPv4 Tunnel"); + case DL_IPV6: return ("IPv6 Tunnel"); + case DL_WIFI: return ("IEEE 802.11"); + default: return ("<unknown mactype>"); + } +} diff --git a/usr/src/uts/common/io/vnic/vnic_ctl.c b/usr/src/uts/common/io/vnic/vnic_ctl.c index 863a519088..77aab2f7f1 100644 --- a/usr/src/uts/common/io/vnic/vnic_ctl.c +++ b/usr/src/uts/common/io/vnic/vnic_ctl.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,21 +54,16 @@ static int vnic_detach(dev_info_t *, ddi_detach_cmd_t); static int vnic_open(queue_t *, dev_t *, int, int, cred_t *); static int vnic_close(queue_t *); static void vnic_wput(queue_t *, mblk_t *); +static void vnic_ioctl(queue_t *, mblk_t *); -typedef struct vnic_taskq_args_s { - queue_t *tq_vnic_q; - mblk_t *tq_vnic_mp; - int tq_vnic_flag; -} vnic_taskq_args_t; - -static void vnic_ioc_create(vnic_taskq_args_t *); -static void vnic_ioc_modify(vnic_taskq_args_t *); -static void vnic_ioc_delete(vnic_taskq_args_t *); -static void vnic_ioc_info(vnic_taskq_args_t *); +static int vnic_ioc_create(mblk_t *, int); +static int vnic_ioc_modify(mblk_t *, int); +static int vnic_ioc_delete(mblk_t *, int); +static int vnic_ioc_info(mblk_t *, int); typedef struct ioc_cmd_s { int ic_cmd; - void (*ic_func)(vnic_taskq_args_t *); + int (*ic_func)(mblk_t *, int); } ioc_cmd_t; static ioc_cmd_t ioc_cmd[] = { @@ -176,6 +171,12 @@ vnic_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) return (ENOSR); /* + * The ioctl handling callback to process control ioctl + * messages; see comments above dld_ioctl() for details. + */ + dsp->ds_ioctl = vnic_ioctl; + + /* * The VNIC control node uses its own set of entry points. */ WR(q)->q_qinfo = &vnic_w_ctl_qinit; @@ -193,21 +194,21 @@ vnic_close(queue_t *q) if (dsp->ds_type == DLD_CONTROL) { qprocsoff(q); + dld_finish_pending_task(dsp); + dsp->ds_ioctl = NULL; dld_str_destroy(dsp); return (0); } return (dld_close(q)); } -void +static void vnic_ioctl(queue_t *wq, mblk_t *mp) { /* LINTED alignment */ struct iocblk *iocp = (struct iocblk *)mp->b_rptr; - int i, err = 0; + int i, err = EINVAL; mblk_t *nmp; - void (*func)(); - vnic_taskq_args_t *taskq_args; if (mp->b_cont == NULL) { err = EINVAL; @@ -228,45 +229,29 @@ vnic_ioctl(queue_t *wq, mblk_t *mp) for (i = 0; i < IOC_CMD_SZ; i++) { if (iocp->ioc_cmd == ioc_cmd[i].ic_cmd) { - func = ioc_cmd[i].ic_func; + err = ioc_cmd[i].ic_func(mp, (int)iocp->ioc_flag); break; } } - if (i == IOC_CMD_SZ) { - freemsg(mp->b_cont); - err = EINVAL; - goto done; - } + if (err == 0) { + int len = 0; - taskq_args = kmem_zalloc(sizeof (vnic_taskq_args_t), KM_NOSLEEP); - if (taskq_args == NULL) { - freemsg(mp->b_cont); - err = ENOMEM; - goto done; - } - - taskq_args->tq_vnic_q = wq; - taskq_args->tq_vnic_mp = mp; - taskq_args->tq_vnic_flag = (int)iocp->ioc_flag; - if (taskq_dispatch(system_taskq, - func, taskq_args, TQ_NOSLEEP) == NULL) { - kmem_free(taskq_args, sizeof (vnic_taskq_args_t)); - freemsg(mp->b_cont); - err = ENOMEM; - goto done; + if (mp->b_cont != NULL) + len = MBLKL(mp->b_cont); + miocack(wq, mp, len, 0); + return; } done: - if (err != 0) - miocnak(wq, mp, 0, err); + miocnak(wq, mp, 0, err); } static void vnic_wput(queue_t *q, mblk_t *mp) { if (DB_TYPE(mp) == M_IOCTL) - vnic_ioctl(q, mp); + dld_ioctl(q, mp); else freemsg(mp); } @@ -368,39 +353,29 @@ vnic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) /* * Process a VNICIOC_CREATE request. */ -static void -vnic_ioc_create(vnic_taskq_args_t *taskq_args) +static int +vnic_ioc_create(mblk_t *mp, int mode) { STRUCT_HANDLE(vnic_ioc_create, create_arg); - queue_t *wq = taskq_args->tq_vnic_q; - mblk_t *mp = taskq_args->tq_vnic_mp; - int mode = taskq_args->tq_vnic_flag; int rc = 0; int mac_len; uchar_t mac_addr[MAXMACADDRLEN]; - uint_t vnic_id; - char dev_name[MAXNAMELEN + 1]; + datalink_id_t vnic_id, linkid; vnic_mac_addr_type_t mac_addr_type; - kmem_free(taskq_args, sizeof (vnic_taskq_args_t)); STRUCT_SET_HANDLE(create_arg, mode, (void *)mp->b_cont->b_rptr); - if (MBLKL(mp->b_cont) < STRUCT_SIZE(create_arg)) { - rc = EINVAL; - goto bail; - } + if (MBLKL(mp->b_cont) < STRUCT_SIZE(create_arg)) + return (EINVAL); /* - * VNIC id. For now it is specified by the user. Once we have - * vanity naming, we can pick a value for the user, and let - * the user assign a generic name to the VNIC (XXXND) + * VNIC link id */ vnic_id = STRUCT_FGET(create_arg, vc_vnic_id); /* - * Device name and number of the MAC port the VNIC is defined - * on top of. + * Linkid of the link the VNIC is defined on top of. */ - bcopy(STRUCT_FGET(create_arg, vc_dev_name), dev_name, MAXNAMELEN); + linkid = STRUCT_FGET(create_arg, vc_link_id); /* MAC address */ mac_addr_type = STRUCT_FGET(create_arg, vc_mac_addr_type); @@ -412,41 +387,27 @@ vnic_ioc_create(vnic_taskq_args_t *taskq_args) MAXMACADDRLEN); break; default: - rc = ENOTSUP; - goto bail; + return (ENOTSUP); } - rc = vnic_dev_create(vnic_id, dev_name, mac_len, mac_addr); - -bail: - freemsg(mp->b_cont); - mp->b_cont = NULL; - if (rc != 0) - miocnak(wq, mp, 0, rc); - else - miocack(wq, mp, 0, 0); + rc = vnic_dev_create(vnic_id, linkid, mac_len, mac_addr); + return (rc); } -static void -vnic_ioc_modify(vnic_taskq_args_t *taskq_args) +static int +vnic_ioc_modify(mblk_t *mp, int mode) { STRUCT_HANDLE(vnic_ioc_modify, modify_arg); - queue_t *wq = taskq_args->tq_vnic_q; - mblk_t *mp = taskq_args->tq_vnic_mp; - int mode = taskq_args->tq_vnic_flag; int err = 0; - uint_t vnic_id; + datalink_id_t vnic_id; uint_t modify_mask; vnic_mac_addr_type_t mac_addr_type; uint_t mac_len; uchar_t mac_addr[MAXMACADDRLEN]; - kmem_free(taskq_args, sizeof (vnic_taskq_args_t)); STRUCT_SET_HANDLE(modify_arg, mode, (void *)mp->b_cont->b_rptr); - if (MBLKL(mp->b_cont) < STRUCT_SIZE(modify_arg)) { - err = EINVAL; - goto done; - } + if (MBLKL(mp->b_cont) < STRUCT_SIZE(modify_arg)) + return (EINVAL); vnic_id = STRUCT_FGET(modify_arg, vm_vnic_id); modify_mask = STRUCT_FGET(modify_arg, vm_modify_mask); @@ -460,42 +421,23 @@ vnic_ioc_modify(vnic_taskq_args_t *taskq_args) err = vnic_dev_modify(vnic_id, modify_mask, mac_addr_type, mac_len, mac_addr); -done: - freemsg(mp->b_cont); - mp->b_cont = NULL; - if (err != 0) - miocnak(wq, mp, 0, err); - else - miocack(wq, mp, 0, 0); + return (err); } -static void -vnic_ioc_delete(vnic_taskq_args_t *taskq_args) +static int +vnic_ioc_delete(mblk_t *mp, int mode) { STRUCT_HANDLE(vnic_ioc_delete, delete_arg); - queue_t *wq = taskq_args->tq_vnic_q; - mblk_t *mp = taskq_args->tq_vnic_mp; - int mode = taskq_args->tq_vnic_flag; - uint_t vnic_id; + datalink_id_t vnic_id; int err = 0; - kmem_free(taskq_args, sizeof (vnic_taskq_args_t)); STRUCT_SET_HANDLE(delete_arg, mode, (void *)mp->b_cont->b_rptr); - if (STRUCT_SIZE(delete_arg) > MBLKL(mp)) { - err = EINVAL; - goto fail; - } + if (STRUCT_SIZE(delete_arg) > MBLKL(mp)) + return (EINVAL); vnic_id = STRUCT_FGET(delete_arg, vd_vnic_id); err = vnic_dev_delete(vnic_id); - -fail: - freemsg(mp->b_cont); - mp->b_cont = NULL; - if (err != 0) - miocnak(wq, mp, 0, err); - else - miocack(wq, mp, 0, err); + return (err); } typedef struct vnic_ioc_info_state { @@ -504,8 +446,9 @@ typedef struct vnic_ioc_info_state { } vnic_ioc_info_state_t; static int -vnic_ioc_info_new_vnic(void *arg, uint32_t id, vnic_mac_addr_type_t addr_type, - uint_t mac_len, uint8_t *mac_addr, char *dev_name) +vnic_ioc_info_new_vnic(void *arg, datalink_id_t id, + vnic_mac_addr_type_t addr_type, uint_t mac_len, uint8_t *mac_addr, + datalink_id_t linkid) { vnic_ioc_info_state_t *state = arg; /*LINTED*/ @@ -515,10 +458,10 @@ vnic_ioc_info_new_vnic(void *arg, uint32_t id, vnic_mac_addr_type_t addr_type, return (ENOSPC); vn->vn_vnic_id = id; + vn->vn_link_id = linkid; vn->vn_mac_addr_type = addr_type; vn->vn_mac_len = mac_len; bcopy(mac_addr, &(vn->vn_mac_addr), mac_len); - bcopy(dev_name, &(vn->vn_dev_name), MAXNAMELEN); state->where += sizeof (*vn); state->bytes_left -= sizeof (*vn); @@ -526,22 +469,18 @@ vnic_ioc_info_new_vnic(void *arg, uint32_t id, vnic_mac_addr_type_t addr_type, return (0); } -static void -vnic_ioc_info(vnic_taskq_args_t *taskq_args) +/* ARGSUSED */ +static int +vnic_ioc_info(mblk_t *mp, int mode) { - queue_t *wq = taskq_args->tq_vnic_q; - mblk_t *mp = taskq_args->tq_vnic_mp; vnic_ioc_info_t *info_argp; int rc, len; - uint32_t nvnics, vnic_id; - char dev_name[MAXNAMELEN]; + uint32_t nvnics; + datalink_id_t vnic_id, linkid; vnic_ioc_info_state_t state; - kmem_free(taskq_args, sizeof (vnic_taskq_args_t)); - if ((len = MBLKL(mp->b_cont)) < sizeof (*info_argp)) { - rc = EINVAL; - goto bail; - } + if ((len = MBLKL(mp->b_cont)) < sizeof (*info_argp)) + return (EINVAL); /* LINTED alignment */ info_argp = (vnic_ioc_info_t *)mp->b_cont->b_rptr; @@ -552,22 +491,12 @@ vnic_ioc_info(vnic_taskq_args_t *taskq_args) * regarding all vnics currently defined. */ vnic_id = info_argp->vi_vnic_id; - if (info_argp->vi_dev_name) - bcopy(info_argp->vi_dev_name, dev_name, MAXNAMELEN); + linkid = info_argp->vi_linkid; state.bytes_left = len - sizeof (vnic_ioc_info_t); state.where = (uchar_t *)(info_argp +1); - rc = vnic_info(&nvnics, vnic_id, dev_name, &state, + rc = vnic_info(&nvnics, vnic_id, linkid, &state, vnic_ioc_info_new_vnic); - -bail: - if (rc == 0) { - info_argp->vi_nvnics = nvnics; - miocack(wq, mp, len, 0); - } else { - freemsg(mp->b_cont); - mp->b_cont = NULL; - miocnak(wq, mp, 0, rc); - } + return (rc); } diff --git a/usr/src/uts/common/io/vnic/vnic_dev.c b/usr/src/uts/common/io/vnic/vnic_dev.c index 2433e499b0..676bcc1e6f 100644 --- a/usr/src/uts/common/io/vnic/vnic_dev.c +++ b/usr/src/uts/common/io/vnic/vnic_dev.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. */ @@ -44,10 +44,8 @@ #include <sys/dlpi.h> #include <sys/mac.h> #include <sys/mac_ether.h> +#include <sys/dls.h> #include <sys/pattr.h> -#if 0 -#include <sys/vlan.h> -#endif #include <sys/vnic.h> #include <sys/vnic_impl.h> #include <sys/gld.h> @@ -105,8 +103,8 @@ static uchar_t vnic_brdcst_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* used by vnic_walker */ typedef struct vnic_info_state { - uint32_t vs_vnic_id; - char vs_dev_name[MAXNAMELEN]; + datalink_id_t vs_vnic_id; + datalink_id_t vs_linkid; boolean_t vs_vnic_found; vnic_info_new_vnic_fn_t vs_new_vnic_fn; void *vs_fn_arg; @@ -165,7 +163,7 @@ vnic_dev_init(void) vnic_hash = mod_hash_create_idhash("vnic_hash", VNIC_HASHSZ, mod_hash_null_valdtor); - vnic_mac_hash = mod_hash_create_strhash("vnic_mac_hash", + vnic_mac_hash = mod_hash_create_idhash("vnic_mac_hash", VNIC_MAC_HASHSZ, mod_hash_null_valdtor); rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL); @@ -182,7 +180,7 @@ vnic_dev_fini(void) mutex_destroy(&vnic_mac_lock); rw_destroy(&vnic_lock); - mod_hash_destroy_strhash(vnic_mac_hash); + mod_hash_destroy_idhash(vnic_mac_hash); mod_hash_destroy_idhash(vnic_hash); kmem_cache_destroy(vnic_mac_cache); kmem_cache_destroy(vnic_cache); @@ -195,9 +193,8 @@ vnic_dev_count(void) } static int -vnic_mac_open(const char *dev_name, vnic_mac_t **vmp) +vnic_mac_open(datalink_id_t linkid, vnic_mac_t **vmp) { - char *str_key; int err; vnic_mac_t *vnic_mac = NULL; const mac_info_t *mip; @@ -206,7 +203,7 @@ vnic_mac_open(const char *dev_name, vnic_mac_t **vmp) mutex_enter(&vnic_mac_lock); - err = mod_hash_find(vnic_mac_hash, (mod_hash_key_t)dev_name, + err = mod_hash_find(vnic_mac_hash, (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&vnic_mac); if (err == 0) { /* this MAC is already opened, increment reference count */ @@ -217,12 +214,20 @@ vnic_mac_open(const char *dev_name, vnic_mac_t **vmp) } vnic_mac = kmem_cache_alloc(vnic_mac_cache, KM_SLEEP); - - if ((err = mac_open(dev_name, &vnic_mac->va_mh)) != 0) { + if ((err = mac_open_by_linkid(linkid, &vnic_mac->va_mh)) != 0) { vnic_mac->va_mh = NULL; goto bail; } + /* + * For now, we do not support VNICs over legacy drivers. This will + * soon be changed. + */ + if (mac_is_legacy(vnic_mac->va_mh)) { + err = ENOTSUP; + goto bail; + } + /* only ethernet support, for now */ mip = mac_info(vnic_mac->va_mh); if (mip->mi_media != DL_ETHER) { @@ -234,12 +239,10 @@ vnic_mac_open(const char *dev_name, vnic_mac_t **vmp) goto bail; } - (void) strcpy(vnic_mac->va_dev_name, dev_name); + vnic_mac->va_linkid = linkid; /* add entry to hash table */ - str_key = kmem_alloc(strlen(dev_name) + 1, KM_SLEEP); - (void) strcpy(str_key, dev_name); - err = mod_hash_insert(vnic_mac_hash, (mod_hash_key_t)str_key, + err = mod_hash_insert(vnic_mac_hash, (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t)vnic_mac); ASSERT(err == 0); @@ -585,7 +588,7 @@ vnic_mac_free(vnic_mac_t *vnic_mac) mac_close(vnic_mac->va_mh); (void) mod_hash_remove(vnic_mac_hash, - (mod_hash_key_t)vnic_mac->va_dev_name, &val); + (mod_hash_key_t)(uintptr_t)vnic_mac->va_linkid, &val); ASSERT(vnic_mac == (vnic_mac_t *)val); kmem_cache_free(vnic_mac_cache, vnic_mac); @@ -678,8 +681,8 @@ vnic_add_unicstaddr(vnic_t *vnic, mac_multi_addr_t *maddr) * been used up. */ set_promisc: - err = mac_promisc_set(vnic_mac->va_mh, B_TRUE, MAC_DEVPROMISC); - if (err != 0) { + if ((err = mac_promisc_set(vnic_mac->va_mh, B_TRUE, + MAC_DEVPROMISC)) != 0) { return (err); } @@ -719,7 +722,8 @@ vnic_remove_unicstaddr(vnic_t *vnic) * Returns 0 on success, an errno on failure. */ int -vnic_dev_create(uint_t vnic_id, char *dev_name, int mac_len, uchar_t *mac_addr) +vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, int mac_len, + uchar_t *mac_addr) { vnic_t *vnic = NULL; mac_register_t *mac; @@ -751,7 +755,7 @@ vnic_dev_create(uint_t vnic_id, char *dev_name, int mac_len, uchar_t *mac_addr) } /* open underlying MAC */ - err = vnic_mac_open(dev_name, &vnic_mac); + err = vnic_mac_open(linkid, &vnic_mac); if (err != 0) { kmem_cache_free(vnic_cache, vnic); rw_exit(&vnic_lock); @@ -788,7 +792,7 @@ vnic_dev_create(uint_t vnic_id, char *dev_name, int mac_len, uchar_t *mac_addr) mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; mac->m_driver = vnic; mac->m_dip = vnic_get_dip(); - mac->m_instance = vnic_id; + mac->m_instance = (uint_t)-1; mac->m_src_addr = vnic->vn_addr; mac->m_callbacks = &vnic_m_callbacks; @@ -796,10 +800,29 @@ vnic_dev_create(uint_t vnic_id, char *dev_name, int mac_len, uchar_t *mac_addr) mac->m_min_sdu = lower_mac_info->mi_sdu_min; mac->m_max_sdu = lower_mac_info->mi_sdu_max; + /* + * As the current margin size of the underlying mac is used to + * determine the margin size of the VNIC itself, request the + * underlying mac not to change to a smaller margin size. + */ + err = mac_margin_add(vnic_mac->va_mh, &(vnic->vn_margin), B_TRUE); + if (err != 0) + goto bail; + mac->m_margin = vnic->vn_margin; err = mac_register(mac, &vnic->vn_mh); mac_free(mac); - if (err != 0) + if (err != 0) { + VERIFY(mac_margin_remove(vnic_mac->va_mh, + vnic->vn_margin) == 0); goto bail; + } + + if ((err = dls_devnet_create(vnic->vn_mh, vnic->vn_id)) != 0) { + VERIFY(mac_margin_remove(vnic_mac->va_mh, + vnic->vn_margin) == 0); + (void) mac_unregister(vnic->vn_mh); + goto bail; + } /* add new VNIC to hash table */ err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id), @@ -880,7 +903,7 @@ bail_unlocked: */ /* ARGSUSED */ int -vnic_dev_modify(uint_t vnic_id, uint_t modify_mask, +vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask, vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr) { vnic_t *vnic = NULL; @@ -910,11 +933,12 @@ vnic_dev_modify(uint_t vnic_id, uint_t modify_mask, } int -vnic_dev_delete(uint_t vnic_id) +vnic_dev_delete(datalink_id_t vnic_id) { vnic_t *vnic = NULL; mod_hash_val_t val; vnic_flow_t *flent; + datalink_id_t tmpid; int rc; vnic_mac_t *vnic_mac; @@ -926,6 +950,13 @@ vnic_dev_delete(uint_t vnic_id) return (ENOENT); } + if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid)) != 0) { + rw_exit(&vnic_lock); + return (rc); + } + + ASSERT(vnic_id == tmpid); + /* * We cannot unregister the MAC yet. Unregistering would * free up mac_impl_t which should not happen at this time. @@ -935,6 +966,7 @@ vnic_dev_delete(uint_t vnic_id) * new claims on mac_impl_t. */ if (mac_disable(vnic->vn_mh) != 0) { + (void) dls_devnet_create(vnic->vn_mh, vnic_id); rw_exit(&vnic_lock); return (EBUSY); } @@ -955,6 +987,8 @@ vnic_dev_delete(uint_t vnic_id) vnic_classifier_flow_destroy(flent); } + rc = mac_margin_remove(vnic->vn_vnic_mac->va_mh, vnic->vn_margin); + ASSERT(rc == 0); rc = mac_unregister(vnic->vn_mh); ASSERT(rc == 0); (void) vnic_remove_unicstaddr(vnic); @@ -1329,8 +1363,8 @@ vnic_m_unicst(void *arg, const uint8_t *mac_addr) } int -vnic_info(uint_t *nvnics, uint32_t vnic_id, char *dev_name, void *fn_arg, - vnic_info_new_vnic_fn_t new_vnic_fn) +vnic_info(uint_t *nvnics, datalink_id_t vnic_id, datalink_id_t linkid, + void *fn_arg, vnic_info_new_vnic_fn_t new_vnic_fn) { vnic_info_state_t state; int rc = 0; @@ -1341,13 +1375,13 @@ vnic_info(uint_t *nvnics, uint32_t vnic_id, char *dev_name, void *fn_arg, bzero(&state, sizeof (state)); state.vs_vnic_id = vnic_id; - bcopy(state.vs_dev_name, dev_name, MAXNAMELEN); + state.vs_linkid = linkid; state.vs_new_vnic_fn = new_vnic_fn; state.vs_fn_arg = fn_arg; mod_hash_walk(vnic_hash, vnic_info_walker, &state); - if ((rc = state.vs_rc) == 0 && vnic_id != 0 && + if ((rc = state.vs_rc) == 0 && vnic_id != DATALINK_ALL_LINKID && !state.vs_vnic_found) rc = ENOENT; @@ -1371,14 +1405,16 @@ vnic_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) vnic = (vnic_t *)val; - if (state->vs_vnic_id != 0 && vnic->vn_id != state->vs_vnic_id) + if (state->vs_vnic_id != DATALINK_ALL_LINKID && + vnic->vn_id != state->vs_vnic_id) { goto bail; + } state->vs_vnic_found = B_TRUE; state->vs_rc = state->vs_new_vnic_fn(state->vs_fn_arg, vnic->vn_id, vnic->vn_addr_type, vnic->vn_vnic_mac->va_addr_len, - vnic->vn_addr, vnic->vn_vnic_mac->va_dev_name); + vnic->vn_addr, vnic->vn_vnic_mac->va_linkid); bail: return ((state->vs_rc == 0) ? MH_WALK_CONTINUE : MH_WALK_TERMINATE); } @@ -1473,9 +1509,10 @@ vnic_promisc_set(vnic_t *vnic, boolean_t on) return (0); if (on) { - r = mac_promisc_set(vnic_mac->va_mh, B_TRUE, MAC_DEVPROMISC); - if (r != 0) + if ((r = mac_promisc_set(vnic_mac->va_mh, B_TRUE, + MAC_DEVPROMISC)) != 0) { return (r); + } rw_enter(&vnic_mac->va_promisc_lock, RW_WRITER); vnic->vn_promisc_next = vnic_mac->va_promisc; diff --git a/usr/src/uts/common/io/xge/drv/xgell.c b/usr/src/uts/common/io/xge/drv/xgell.c index b236c7eefc..f3b1ef1295 100644 --- a/usr/src/uts/common/io/xge/drv/xgell.c +++ b/usr/src/uts/common/io/xge/drv/xgell.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. */ @@ -2236,6 +2236,7 @@ xgell_device_register(xgelldev_t *lldev, xgell_config_t *config) macp->m_callbacks = &xgell_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = hldev->config.mtu; + macp->m_margin = VLAN_TAGSZ; /* * Finally, we're ready to register ourselves with the Nemo * interface; if this succeeds, we're all ready to start() diff --git a/usr/src/uts/common/os/dacf.c b/usr/src/uts/common/os/dacf.c index 91e34dabbf..1ab2afa986 100644 --- a/usr/src/uts/common/os/dacf.c +++ b/usr/src/uts/common/os/dacf.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 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1181,6 +1180,19 @@ dacf_minor_number(dacf_infohdl_t info_hdl) } /* + * dacf_get_dev() + * given a dacf_infohdl_t, obtain the dev_t of the instance being + * configured. + */ +dev_t +dacf_get_dev(dacf_infohdl_t info_hdl) +{ + struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; + + return (dmdp->ddm_dev); +} + +/* * dacf_driver_name() * given a dacf_infohdl_t, obtain the device driver name of the device * instance being configured. @@ -1269,7 +1281,7 @@ dacf_retrieve_info(dacf_infohdl_t info_hdl) void *data; if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp, - (mod_hash_val_t *)&data) != 0) { + (mod_hash_val_t *)&data) != 0) { return (NULL); } diff --git a/usr/src/uts/common/os/dacf_clnt.c b/usr/src/uts/common/os/dacf_clnt.c index 58c57b5224..e40509d33b 100644 --- a/usr/src/uts/common/os/dacf_clnt.c +++ b/usr/src/uts/common/os/dacf_clnt.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,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -75,7 +74,10 @@ dacfc_match_create_minor(char *name, char *node_type, dev_info_t *dip, char *dev_path, *dev_pathp, *drv_mname = NULL; dacf_rsrvlist_t *pa_rsrv, *pd_rsrv; - if (flag & CLONE_DEV) { + /* + * Check the dacf rule for non-clone devices or for network devices. + */ + if ((flag & CLONE_DEV) && (strcmp(node_type, DDI_NT_NET) != 0)) { return; } diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c index 48ce29785d..bfc829934f 100644 --- a/usr/src/uts/common/os/devcfg.c +++ b/usr/src/uts/common/os/devcfg.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. */ @@ -6637,6 +6637,20 @@ i_ddi_devs_attached(major_t major) return (error); } +int +i_ddi_minor_node_count(dev_info_t *ddip, const char *node_type) +{ + struct ddi_minor_data *dp; + int count = 0; + + mutex_enter(&(DEVI(ddip)->devi_lock)); + for (dp = DEVI(ddip)->devi_minor; dp != NULL; dp = dp->next) + if (strcmp(dp->ddm_node_type, node_type) == 0) + count++; + mutex_exit(&(DEVI(ddip)->devi_lock)); + return (count); +} + /* * ddi_hold_installed_driver configures and attaches all * instances of the specified driver. To accomplish this diff --git a/usr/src/uts/common/os/streamio.c b/usr/src/uts/common/os/streamio.c index 2bbbca12b6..d80fa67f56 100644 --- a/usr/src/uts/common/os/streamio.c +++ b/usr/src/uts/common/os/streamio.c @@ -77,9 +77,9 @@ #include <sys/sunldi_impl.h> #include <sys/autoconf.h> #include <sys/policy.h> +#include <sys/dld.h> #include <sys/zone.h> - /* * This define helps improve the readability of streams code while * still maintaining a very old streams performance enhancement. The @@ -239,8 +239,9 @@ stropen(vnode_t *vp, dev_t *devp, int flag, cred_t *crp) struct stdata *stp; queue_t *qp; int s; - dev_t dummydev; + dev_t dummydev, savedev; struct autopush *ap; + struct dlautopush dlap; int error = 0; ssize_t rmin, rmax; int cloneopen; @@ -439,6 +440,7 @@ ckreturn: /* * Open driver and create stream to it (via qattach). */ + savedev = *devp; cloneopen = (getmajor(*devp) == clone_major); if ((error = qattach(qp, devp, flag, crp, NULL, B_FALSE)) != 0) { mutex_enter(&vp->v_lock); @@ -476,15 +478,53 @@ ckreturn: " streams module"); } + if (!NETWORK_DRV(major)) { + savedev = *devp; + } else { + /* + * For network devices, process differently based on the + * return value from dld_autopush(): + * + * 0: the passed-in device points to a GLDv3 datalink with + * per-link autopush configuration; use that configuration + * and ignore any per-driver autopush configuration. + * + * 1: the passed-in device points to a physical GLDv3 + * datalink without per-link autopush configuration. The + * passed in device was changed to refer to the actual + * physical device (if it's not already); we use that new + * device to look up any per-driver autopush configuration. + * + * -1: neither of the above cases applied; use the initial + * device to look up any per-driver autopush configuration. + */ + switch (dld_autopush(&savedev, &dlap)) { + case 0: + zoneid = crgetzoneid(crp); + for (s = 0; s < dlap.dap_npush; s++) { + error = push_mod(qp, &dummydev, stp, + dlap.dap_aplist[s], dlap.dap_anchor, crp, + zoneid); + if (error != 0) + break; + } + goto opendone; + case 1: + break; + case -1: + savedev = *devp; + break; + } + } /* - * Check for autopush. Start with the global zone. If not found - * check in the local zone. + * Find the autopush configuration based on "savedev". Start with the + * global zone. If not found check in the local zone. */ zoneid = GLOBAL_ZONEID; retryap: ss = netstack_find_by_stackid(zoneid_to_netstackid(zoneid))-> netstack_str; - if ((ap = sad_ap_find_by_dev(*devp, ss)) == NULL) { + if ((ap = sad_ap_find_by_dev(savedev, ss)) == NULL) { netstack_rele(ss->ss_netstack); if (zoneid == GLOBAL_ZONEID) { /* @@ -507,6 +547,8 @@ retryap: sad_ap_rele(ap, ss); netstack_rele(ss->ss_netstack); +opendone: + /* * let specfs know that open failed part way through */ @@ -516,8 +558,6 @@ retryap: mutex_exit(&stp->sd_lock); } -opendone: - /* * Wake up others that are waiting for stream to be created. */ diff --git a/usr/src/uts/common/os/swapgeneric.c b/usr/src/uts/common/os/swapgeneric.c index 33ce90b489..d4217c77f3 100644 --- a/usr/src/uts/common/os/swapgeneric.c +++ b/usr/src/uts/common/os/swapgeneric.c @@ -20,7 +20,7 @@ */ /* ONC_PLUS EXTRACT START */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -360,7 +360,6 @@ loadrootmodules(void) if ((err = load_boot_driver(this)) != 0) { cmn_err(CE_WARN, "Cannot load drv/%s", this); return (err); - /* NOTREACHED */ } } /* @@ -371,7 +370,6 @@ loadrootmodules(void) if ((err = load_boot_platform_modules(this)) != 0) { cmn_err(CE_WARN, "Cannot load drv/%s", this); return (err); - /* NOTREACHED */ } } @@ -407,7 +405,6 @@ loop: if (err != 0) { cmn_err(CE_CONT, "Cannot load drivers for %s\n", name); goto out; - /* NOTREACHED */ } /* @@ -474,34 +471,38 @@ loop: if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) { ++netboot; + /* + * Preload (load-only, no init) the dacf module. We cannot + * init the module because one of its requisite modules is + * dld whose _init function will call taskq_create(), which + * will panic the system at this point. + */ + if ((err = modloadonly("dacf", "net_dacf")) < 0) { + cmn_err(CE_CONT, "Cannot load dacf/net_dacf\n"); + goto out; + } if ((err = modload("misc", "tlimod")) < 0) { cmn_err(CE_CONT, "Cannot load misc/tlimod\n"); goto out; - /* NOTREACHED */ } if ((err = modload("strmod", "rpcmod")) < 0) { cmn_err(CE_CONT, "Cannot load strmod/rpcmod\n"); goto out; - /* NOTREACHED */ } if ((err = modload("misc", "nfs_dlboot")) < 0) { cmn_err(CE_CONT, "Cannot load misc/nfs_dlboot\n"); goto out; - /* NOTREACHED */ } if ((err = modload("mac", "mac_ether")) < 0) { cmn_err(CE_CONT, "Cannot load mac/mac_ether\n"); goto out; - /* NOTREACHED */ } if ((err = modload("misc", "strplumb")) < 0) { cmn_err(CE_CONT, "Cannot load misc/strplumb\n"); goto out; - /* NOTREACHED */ } if ((err = strplumb_load()) < 0) { goto out; - /* NOTREACHED */ } } diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index 75354330ef..2721748a7c 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -6149,3 +6149,26 @@ zone_find_by_id_nolock(zoneid_t zoneid) mutex_exit(&zonehash_lock); return (zone); } + +/* + * Walk the datalinks for a given zone + */ +int +zone_datalink_walk(zoneid_t zoneid, int (*cb)(const char *, void *), void *data) +{ + zone_t *zone; + struct dlnamelist *dlnl; + int ret = 0; + + if ((zone = zone_find_by_id(zoneid)) == NULL) + return (ENOENT); + + mutex_enter(&zone->zone_lock); + for (dlnl = zone->zone_dl_list; dlnl != NULL; dlnl = dlnl->dlnl_next) { + if ((ret = (*cb)(dlnl->dlnl_name, data)) != 0) + break; + } + mutex_exit(&zone->zone_lock); + zone_rele(zone); + return (ret); +} diff --git a/usr/src/uts/common/sys/aggr.h b/usr/src/uts/common/sys/aggr.h index 1b6f14b5ce..c89cca4d46 100644 --- a/usr/src/uts/common/sys/aggr.h +++ b/usr/src/uts/common/sys/aggr.h @@ -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. */ @@ -30,6 +30,8 @@ #include <sys/types.h> #include <sys/ethernet.h> +#include <sys/mac.h> +#include <sys/dls.h> #include <sys/param.h> #ifdef __cplusplus @@ -74,6 +76,13 @@ typedef enum { #define AGGR_MAX_PORTS 256 /* + * The largest configurable aggregation key. Because by default the key is + * used as the DLPI device PPA and default VLAN PPA's are calculated as + * ((1000 * vid) + PPA), the largest key can't be > 999. + */ +#define AGGR_MAX_KEY 999 + +/* * LACP port state. */ typedef union { @@ -107,31 +116,37 @@ typedef union { /* one of the ports of a link aggregation group */ typedef struct laioc_port { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; } laioc_port_t; #define LAIOC_CREATE LAIOC(1) typedef struct laioc_create { + datalink_id_t lc_linkid; uint32_t lc_key; uint32_t lc_nports; uint32_t lc_policy; uchar_t lc_mac[ETHERADDRL]; - boolean_t lc_mac_fixed; aggr_lacp_mode_t lc_lacp_mode; aggr_lacp_timer_t lc_lacp_timer; + uint32_t lc_mac_fixed : 1, + lc_force : 1, + lc_pad_bits : 30; } laioc_create_t; #ifdef _SYSCALL32 typedef struct laioc_create32 { + datalink_id_t lc_linkid; uint32_t lc_key; uint32_t lc_nports; uint32_t lc_policy; uchar_t lc_mac[ETHERADDRL]; - boolean_t lc_mac_fixed; aggr_lacp_mode_t lc_lacp_mode; aggr_lacp_timer_t lc_lacp_timer; + uint32_t lc_mac_fixed : 1, + lc_force : 1, + lc_pad_bits : 30; } laioc_create32_t; #endif /* _SYSCALL32 */ @@ -139,13 +154,13 @@ typedef struct laioc_create32 { #define LAIOC_DELETE LAIOC(2) typedef struct laioc_delete { - uint32_t ld_key; + datalink_id_t ld_linkid; } laioc_delete_t; #ifdef _SYSCALL32 typedef struct laioc_delete32 { - uint32_t ld_key; + datalink_id_t ld_linkid; } laioc_delete32_t; #endif /* _SYSCALL32 */ @@ -165,16 +180,18 @@ typedef enum aggr_link_state { } aggr_link_state_t; typedef struct laioc_info_port { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; uchar_t lp_mac[ETHERADDRL]; aggr_port_state_t lp_state; aggr_lacp_state_t lp_lacp_state; } laioc_info_port_t; typedef struct laioc_info_group { + datalink_id_t lg_linkid; uint32_t lg_key; uchar_t lg_mac[ETHERADDRL]; boolean_t lg_mac_fixed; + boolean_t lg_force; uint32_t lg_policy; uint32_t lg_nports; aggr_lacp_mode_t lg_lacp_mode; @@ -182,23 +199,25 @@ typedef struct laioc_info_group { } laioc_info_group_t; typedef struct laioc_info { - uint32_t li_ngroups; - uint32_t li_group_key; /* 0 returns all */ + /* Must not be DLADM_INVALID_LINKID */ + datalink_id_t li_group_linkid; } laioc_info_t; #define LAIOC_ADD LAIOC(4) #define LAIOC_REMOVE LAIOC(5) typedef struct laioc_add_rem { - uint32_t la_key; + datalink_id_t la_linkid; uint32_t la_nports; + uint32_t la_force; } laioc_add_rem_t; #ifdef _SYSCALL32 typedef struct laioc_add_rem32 { - uint32_t la_key; + datalink_id_t la_linkid; uint32_t la_nports; + uint32_t la_force; } laioc_add_rem32_t; #endif /* _SYSCALL32 */ @@ -211,7 +230,7 @@ typedef struct laioc_add_rem32 { #define LAIOC_MODIFY_LACP_TIMER 0x08 typedef struct laioc_modify { - uint32_t lu_key; + datalink_id_t lu_linkid; uint8_t lu_modify_mask; uint32_t lu_policy; uchar_t lu_mac[ETHERADDRL]; @@ -223,7 +242,7 @@ typedef struct laioc_modify { #ifdef _SYSCALL32 typedef struct laioc_modify32 { - uint32_t lu_key; + datalink_id_t lu_linkid; uint8_t lu_modify_mask; uint32_t lu_policy; uchar_t lu_mac[ETHERADDRL]; diff --git a/usr/src/uts/common/sys/aggr_impl.h b/usr/src/uts/common/sys/aggr_impl.h index e114624a06..7bc12b3d31 100644 --- a/usr/src/uts/common/sys/aggr_impl.h +++ b/usr/src/uts/common/sys/aggr_impl.h @@ -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. */ @@ -55,7 +55,7 @@ extern "C" { typedef struct aggr_port_s { struct aggr_port_s *lp_next; struct aggr_grp_s *lp_grp; /* back ptr to group */ - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; uint16_t lp_portid; uint8_t lp_addr[ETHERADDRL]; /* port MAC address */ uint32_t lp_refs; /* refcount */ @@ -64,7 +64,8 @@ typedef struct aggr_port_s { lp_tx_enabled : 1, lp_collector_enabled : 1, lp_promisc_on : 1, - lp_pad_bits : 28; + lp_no_link_update : 1, + lp_pad_bits : 27; uint32_t lp_closing; mac_handle_t lp_mh; const mac_info_t *lp_mip; @@ -80,6 +81,7 @@ typedef struct aggr_port_s { aggr_lacp_port_t lp_lacp; /* LACP state */ lacp_stats_t lp_lacp_stats; const mac_txinfo_t *lp_txinfo; + uint32_t lp_margin; } aggr_port_t; /* @@ -100,6 +102,7 @@ typedef struct aggr_port_s { */ typedef struct aggr_grp_s { krwlock_t lg_lock; + datalink_id_t lg_linkid; uint16_t lg_key; /* key (group port number) */ uint32_t lg_refs; /* refcount */ uint16_t lg_nports; /* number of MAC ports */ @@ -110,7 +113,10 @@ typedef struct aggr_grp_s { lg_started : 1, /* group started? */ lg_promisc : 1, /* in promiscuous mode? */ lg_gldv3_polling : 1, - lg_pad_bits : 11; + lg_zcopy : 1, + lg_vlan : 1, + lg_force : 1, + lg_pad_bits : 8; aggr_port_t *lg_ports; /* list of configured ports */ aggr_port_t *lg_mac_addr_port; mac_handle_t lg_mh; @@ -129,6 +135,7 @@ typedef struct aggr_grp_s { Agg_t aggr; /* 802.3ad data */ uint32_t lg_hcksum_txflags; uint_t lg_max_sdu; + uint32_t lg_margin; } aggr_grp_t; #define AGGR_LACP_LOCK(grp) mutex_enter(&(grp)->aggr.gl_lock); @@ -162,36 +169,39 @@ typedef struct aggr_grp_s { extern dev_info_t *aggr_dip; extern void aggr_ioctl(queue_t *, mblk_t *); -typedef int (*aggr_grp_info_new_grp_fn_t)(void *, uint32_t, uchar_t *, - boolean_t, uint32_t, uint32_t, aggr_lacp_mode_t, aggr_lacp_timer_t); -typedef int (*aggr_grp_info_new_port_fn_t)(void *, char *, uchar_t *, +typedef int (*aggr_grp_info_new_grp_fn_t)(void *, datalink_id_t, uint32_t, + uchar_t *, boolean_t, boolean_t, uint32_t, uint32_t, aggr_lacp_mode_t, + aggr_lacp_timer_t); +typedef int (*aggr_grp_info_new_port_fn_t)(void *, datalink_id_t, uchar_t *, aggr_port_state_t, aggr_lacp_state_t *); extern void aggr_grp_init(void); extern void aggr_grp_fini(void); -extern int aggr_grp_create(uint32_t, uint_t, laioc_port_t *, uint32_t, - boolean_t, uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t); -extern int aggr_grp_delete(uint32_t); +extern int aggr_grp_create(datalink_id_t, uint32_t, uint_t, laioc_port_t *, + uint32_t, boolean_t, boolean_t, uchar_t *, aggr_lacp_mode_t, + aggr_lacp_timer_t); +extern int aggr_grp_delete(datalink_id_t); extern void aggr_grp_free(aggr_grp_t *); -extern int aggr_grp_info(uint_t *, uint32_t, void *, - aggr_grp_info_new_grp_fn_t, aggr_grp_info_new_port_fn_t); +extern int aggr_grp_info(datalink_id_t, void *, aggr_grp_info_new_grp_fn_t, + aggr_grp_info_new_port_fn_t); extern void aggr_grp_notify(aggr_grp_t *, uint32_t); extern boolean_t aggr_grp_attach_port(aggr_grp_t *, aggr_port_t *); extern boolean_t aggr_grp_detach_port(aggr_grp_t *, aggr_port_t *); extern void aggr_grp_port_mac_changed(aggr_grp_t *, aggr_port_t *, boolean_t *, boolean_t *); -extern int aggr_grp_add_ports(uint32_t, uint_t, laioc_port_t *); -extern int aggr_grp_rem_ports(uint32_t, uint_t, laioc_port_t *); +extern int aggr_grp_add_ports(datalink_id_t, uint_t, boolean_t, + laioc_port_t *); +extern int aggr_grp_rem_ports(datalink_id_t, uint_t, laioc_port_t *); extern boolean_t aggr_grp_update_ports_mac(aggr_grp_t *); -extern int aggr_grp_modify(uint32_t, aggr_grp_t *, uint8_t, uint32_t, +extern int aggr_grp_modify(datalink_id_t, aggr_grp_t *, uint8_t, uint32_t, boolean_t, const uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t); extern void aggr_grp_multicst_port(aggr_port_t *, boolean_t); extern uint_t aggr_grp_count(void); extern void aggr_port_init(void); extern void aggr_port_fini(void); -extern int aggr_port_create(const char *, aggr_port_t **); +extern int aggr_port_create(const datalink_id_t, boolean_t, aggr_port_t **); extern void aggr_port_delete(aggr_port_t *); extern void aggr_port_free(aggr_port_t *); extern int aggr_port_start(aggr_port_t *); diff --git a/usr/src/uts/common/sys/dacf.h b/usr/src/uts/common/sys/dacf.h index b014d98767..b6b7124870 100644 --- a/usr/src/uts/common/sys/dacf.h +++ b/usr/src/uts/common/sys/dacf.h @@ -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 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -76,6 +75,7 @@ extern struct dacfsw kmod_dacfsw; /* kernel provided module */ const char *dacf_minor_name(dacf_infohdl_t); minor_t dacf_minor_number(dacf_infohdl_t); +dev_t dacf_get_dev(dacf_infohdl_t); const char *dacf_driver_name(dacf_infohdl_t); dev_info_t *dacf_devinfo_node(dacf_infohdl_t); const char *dacf_get_arg(dacf_arghdl_t, char *); diff --git a/usr/src/uts/common/sys/ddi_implfuncs.h b/usr/src/uts/common/sys/ddi_implfuncs.h index 4aa213c1b2..1a9a84384a 100644 --- a/usr/src/uts/common/sys/ddi_implfuncs.h +++ b/usr/src/uts/common/sys/ddi_implfuncs.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. */ @@ -248,6 +248,7 @@ int i_ddi_attach_node_hierarchy(dev_info_t *); dev_info_t *i_ddi_attach_pseudo_node(char *); int i_ddi_attach_hw_nodes(char *); int i_ddi_devs_attached(major_t); +int i_ddi_minor_node_count(dev_info_t *, const char *); /* non-DDI functions: wrapper around mod_hold/rele_dev_by_major() */ struct dev_ops *ddi_hold_driver(major_t); diff --git a/usr/src/uts/common/sys/dld.h b/usr/src/uts/common/sys/dld.h index 71555d364b..8cc70e52f9 100644 --- a/usr/src/uts/common/sys/dld.h +++ b/usr/src/uts/common/sys/dld.h @@ -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. */ @@ -36,6 +36,8 @@ #include <sys/stream.h> #include <sys/mac.h> #include <sys/dls.h> +#include <sys/conf.h> +#include <sys/sad.h> #include <net/if.h> #ifdef __cplusplus @@ -47,9 +49,6 @@ extern "C" { */ #define DLD_INFO "Data-Link Driver v%I%" -#define DLD_MAX_PPA 999 -#define DLD_MAX_MINOR (DLD_MAX_PPA + 1) - /* * Options: To enable an option set the property name to a non-zero value * in kernel/drv/dld.conf. @@ -93,31 +92,33 @@ extern "C" { */ #define DLDIOC ('D' << 24 | 'L' << 16 | 'D' << 8) -#define DLDIOCATTR (DLDIOC | 0x03) +#define DLDIOC_ATTR (DLDIOC | 0x03) typedef struct dld_ioc_attr { - char dia_name[IFNAMSIZ]; - char dia_dev[MAXNAMELEN]; + datalink_id_t dia_linkid; uint_t dia_max_sdu; - uint16_t dia_vid; } dld_ioc_attr_t; -#define DLDIOCVLAN (DLDIOC | 0x04) - -typedef struct dld_ioc_vlan { - char div_name[IFNAMSIZ]; - uint_t div_count; -} dld_ioc_vlan_t; - -typedef struct dld_vlan_info { - char dvi_name[IFNAMSIZ]; -} dld_vlan_info_t; - -typedef struct dld_hold_vlan { - char dhv_name[IFNAMSIZ]; - zoneid_t dhv_zid; - boolean_t dhv_docheck; -} dld_hold_vlan_t; +#define DLDIOC_VLAN_ATTR (DLDIOC | 0x04) +typedef struct dld_ioc_vlan_attr { + datalink_id_t div_vlanid; + uint16_t div_vid; + datalink_id_t div_linkid; + boolean_t div_force; + boolean_t div_implicit; +} dld_ioc_vlan_attr_t; + +#define DLDIOC_PHYS_ATTR (DLDIOC | 0x05) +typedef struct dld_ioc_phys_attr { + datalink_id_t dip_linkid; + /* + * Whether this physical link supports vanity naming. Note that + * physical links whose media type is not supported by GLDv3 + * can not support vanity naming. + */ + boolean_t dip_novanity; + char dip_dev[MAXLINKNAMELEN]; +} dld_ioc_phys_attr_t; /* * Secure objects ioctls @@ -137,33 +138,90 @@ typedef struct dld_secobj { uint_t so_len; } dld_secobj_t; -#define DLDIOCSECOBJSET (DLDIOC | 0x05) +#define DLDIOC_SECOBJ_SET (DLDIOC | 0x06) typedef struct dld_ioc_secobj_set { dld_secobj_t ss_obj; uint_t ss_flags; } dld_ioc_secobj_set_t; -#define DLDIOCSECOBJGET (DLDIOC | 0x06) +#define DLDIOC_SECOBJ_GET (DLDIOC | 0x07) typedef struct dld_ioc_secobj_get { dld_secobj_t sg_obj; uint_t sg_count; } dld_ioc_secobj_get_t; -#define DLDIOCSECOBJUNSET (DLDIOC | 0x07) +/* + * The following two slots were used outside of ON, so don't reuse them. + * + * #define DLDIOCHOLDVLAN (DLDIOC | 0x08) + * #define DLDIOCRELEVLAN (DLDIOC | 0x09) + */ + +#define DLDIOC_SECOBJ_UNSET (DLDIOC | 0x0a) typedef struct dld_ioc_secobj_unset { char su_name[DLD_SECOBJ_NAME_MAX]; } dld_ioc_secobj_unset_t; +#define DLDIOC_CREATE_VLAN (DLDIOC | 0x0b) +typedef struct dld_ioc_create_vlan { + datalink_id_t dic_vlanid; + datalink_id_t dic_linkid; + uint16_t dic_vid; + boolean_t dic_force; +} dld_ioc_create_vlan_t; + +#define DLDIOC_DELETE_VLAN (DLDIOC | 0x0c) +typedef struct dld_ioc_delete_vlan { + datalink_id_t did_linkid; +} dld_ioc_delete_vlan_t; + +#define DLDIOC_SETAUTOPUSH (DLDIOC | 0x0d) +#define DLDIOC_GETAUTOPUSH (DLDIOC | 0x0e) +#define DLDIOC_CLRAUTOPUSH (DLDIOC | 0x0f) +typedef struct dld_ioc_ap { + datalink_id_t dia_linkid; + uint_t dia_anchor; + uint_t dia_npush; + char dia_aplist[MAXAPUSH][FMNAMESZ+1]; +} dld_ioc_ap_t; + +#define DLDIOC_DOORSERVER (DLDIOC | 0x10) +typedef struct dld_ioc_door { + boolean_t did_start_door; +} dld_ioc_door_t; + +#define DLDIOC_RENAME (DLDIOC | 0x11) +typedef struct dld_ioc_rename { + datalink_id_t dir_linkid1; + datalink_id_t dir_linkid2; + char dir_link[MAXLINKNAMELEN]; +} dld_ioc_rename_t; + /* - * DLDIOCHOLDVLAN/DLDIOCRELEVLAN are added to support a "hold/release" - * operation on a VLAN. A hold will cause a VLAN to be created or the - * reference count will be increased, release will do the reverse. + * DLDIOC_SETZID sets the zoneid of a given link. It could cause a VLAN to be + * implicitly created. Note that we will hold a reference for the given link + * whenever it has a zoneid other than the global zone. */ -#define DLDIOCHOLDVLAN (DLDIOC | 0x08) +#define DLDIOC_SETZID (DLDIOC | 0x12) +typedef struct dld_ioc_setzid { + char dis_link[MAXLINKNAMELEN]; + zoneid_t dis_zid; +} dld_ioc_setzid_t; + +#define DLDIOC_GETZID (DLDIOC | 0x13) +typedef struct dld_ioc_getzid { + datalink_id_t dig_linkid; + zoneid_t dig_zid; +} dld_ioc_getzid_t; -#define DLDIOCRELEVLAN (DLDIOC | 0x09) - -#define DLDIOCZIDGET (DLDIOC | 0x0a) +/* + * data-link autopush configuration. + */ +struct dlautopush { + uint_t dap_anchor; + uint_t dap_npush; + char dap_aplist[MAXAPUSH][FMNAMESZ+1]; +}; #ifdef _KERNEL int dld_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); @@ -173,6 +231,7 @@ void dld_wput(queue_t *, mblk_t *); void dld_wsrv(queue_t *); void dld_init_ops(struct dev_ops *, const char *); void dld_fini_ops(struct dev_ops *); +int dld_autopush(dev_t *, struct dlautopush *); #endif #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/dld_impl.h b/usr/src/uts/common/sys/dld_impl.h index 14f799dcd9..1df8c8e1cf 100644 --- a/usr/src/uts/common/sys/dld_impl.h +++ b/usr/src/uts/common/sys/dld_impl.h @@ -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. */ @@ -29,6 +29,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/types.h> +#include <sys/conf.h> #include <sys/ethernet.h> #include <sys/stream.h> #include <sys/dlpi.h> @@ -56,6 +57,7 @@ typedef enum { } dld_passivestate_t; typedef struct dld_str dld_str_t; +typedef void (*dld_tx_t)(struct dld_str *, mblk_t *); /* * dld_str_t object definition. @@ -72,11 +74,6 @@ struct dld_str { minor_t ds_minor; /* - * PPA number this stream is attached to. - */ - t_uscalar_t ds_ppa; - - /* * Read/write queues for the stream which the object represents. */ queue_t *ds_rq; @@ -200,21 +197,60 @@ struct dld_str { mblk_t *ds_tx_list_tail; uint_t ds_tx_cnt; uint_t ds_tx_msgcnt; + timeout_id_t ds_tx_qdepth_tid; boolean_t ds_tx_qbusy; + dld_tx_t ds_tx; + dld_tx_t ds_unitdata_tx; + kmutex_t ds_tx_lock; + kcondvar_t ds_tx_cv; + uint32_t ds_intx_cnt; + boolean_t ds_detaching; + + /* + * Pending control messages to be processed. + */ + mblk_t *ds_pending_head; + mblk_t *ds_pending_tail; + + taskqid_t ds_tid; + kmutex_t ds_disp_lock; + kcondvar_t ds_disp_cv; + boolean_t ds_closing; + /* - * Number of threads currently in dld. If there is a pending - * request, it is placed in ds_pending_req and the operation - * will finish when dld becomes single-threaded. + * Used to process ioctl message for control node. See comments + * above dld_ioctl(). */ - kmutex_t ds_thr_lock; - uint_t ds_thr; - uint_t ds_pending_cnt; - mblk_t *ds_pending_req; - task_func_t *ds_pending_op; - kcondvar_t ds_pending_cv; + void (*ds_ioctl)(queue_t *, mblk_t *); } dld_str; +#define DLD_TX_ENTER(dsp) { \ + mutex_enter(&(dsp)->ds_tx_lock); \ + (dsp)->ds_intx_cnt++; \ + mutex_exit(&(dsp)->ds_tx_lock); \ +} + +#define DLD_TX_EXIT(dsp) { \ + mutex_enter(&(dsp)->ds_tx_lock); \ + if ((--(dsp)->ds_intx_cnt == 0) && (dsp)->ds_detaching) \ + cv_signal(&(dsp)->ds_tx_cv); \ + mutex_exit(&(dsp)->ds_tx_lock); \ +} + +/* + * Quiesce the traffic. + */ +#define DLD_TX_QUIESCE(dsp) { \ + mutex_enter(&(dsp)->ds_tx_lock); \ + (dsp)->ds_tx = (dsp)->ds_unitdata_tx = NULL; \ + (dsp)->ds_detaching = B_TRUE; \ + while ((dsp)->ds_intx_cnt != 0) \ + cv_wait(&(dsp)->ds_tx_cv, &(dsp)->ds_tx_lock); \ + (dsp)->ds_detaching = B_FALSE; \ + mutex_exit(&(dsp)->ds_tx_lock); \ +} + /* * dld_str.c module. */ @@ -232,22 +268,26 @@ extern void dld_str_rx_fastpath(void *, mac_resource_handle_t, mblk_t *, mac_header_info_t *); extern void dld_str_rx_unitdata(void *, mac_resource_handle_t, mblk_t *, mac_header_info_t *); + extern void dld_tx_flush(dld_str_t *); -extern void dld_tx_enqueue(dld_str_t *, mblk_t *, boolean_t); extern void dld_str_notify_ind(dld_str_t *); -extern void str_mdata_fastpath_put(dld_str_t *, mblk_t *); extern void dld_tx_single(dld_str_t *, mblk_t *); +extern void str_mdata_fastpath_put(dld_str_t *, mblk_t *); +extern void str_mdata_raw_put(dld_str_t *, mblk_t *); + +extern void dld_ioctl(queue_t *, mblk_t *); +extern void dld_finish_pending_task(dld_str_t *); /* * dld_proto.c */ -extern void dld_proto(dld_str_t *, mblk_t *); -extern void dld_finish_pending_ops(dld_str_t *); +extern void dld_wput_proto_nondata(dld_str_t *, mblk_t *); +extern void dld_wput_proto_data(dld_str_t *, mblk_t *); extern void dld_capabilities_disable(dld_str_t *); /* * Options: there should be a separate bit defined here for each - * DLD_PROP... defined in dld.h. + * DLD_PROP... defined in dld.h. */ #define DLD_OPT_NO_FASTPATH 0x00000001 #define DLD_OPT_NO_POLL 0x00000002 @@ -257,34 +297,23 @@ extern void dld_capabilities_disable(dld_str_t *); extern uint32_t dld_opt; /* - * Useful macros. + * autopush information */ +typedef struct dld_ap { + datalink_id_t da_linkid; + struct dlautopush da_ap; -#define IMPLY(p, c) (!(p) || (c)) +#define da_anchor da_ap.dap_anchor +#define da_npush da_ap.dap_npush +#define da_aplist da_ap.dap_aplist -#define DLD_ENTER(dsp) { \ - mutex_enter(&dsp->ds_thr_lock); \ - ++dsp->ds_thr; \ - ASSERT(dsp->ds_thr != 0); \ - mutex_exit(&dsp->ds_thr_lock); \ -} +} dld_ap_t; -#define DLD_EXIT(dsp) { \ - mutex_enter(&dsp->ds_thr_lock); \ - ASSERT(dsp->ds_thr > 0); \ - if (--dsp->ds_thr == 0 && dsp->ds_pending_req != NULL) \ - dld_finish_pending_ops(dsp); \ - else \ - mutex_exit(&dsp->ds_thr_lock); \ -} +/* + * Useful macros. + */ -#define DLD_WAKEUP(dsp) { \ - mutex_enter(&dsp->ds_thr_lock); \ - ASSERT(dsp->ds_pending_cnt > 0); \ - if (--dsp->ds_pending_cnt == 0) \ - cv_signal(&dsp->ds_pending_cv); \ - mutex_exit(&dsp->ds_thr_lock); \ -} +#define IMPLY(p, c) (!(p) || (c)) #ifdef DEBUG #define DLD_DBG cmn_err diff --git a/usr/src/uts/common/sys/dlpi.h b/usr/src/uts/common/sys/dlpi.h index 1d1451c082..355280f920 100644 --- a/usr/src/uts/common/sys/dlpi.h +++ b/usr/src/uts/common/sys/dlpi.h @@ -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. */ @@ -50,6 +50,7 @@ extern "C" { #define DLIOC ('D' << 8) #define DLIOCRAW (DLIOC|1) /* M_DATA "raw" mode */ #define DLIOCNATIVE (DLIOC|2) /* Native traffic mode */ +#define DLIOCMARGININFO (DLIOC|3) /* margin size info */ #define DLIOCHDRINFO (DLIOC|10) /* IP fast-path */ #define DL_IOC_HDR_INFO DLIOCHDRINFO @@ -1663,6 +1664,26 @@ extern void dlphysaddrack(queue_t *, mblk_t *, void *, t_uscalar_t); extern void dlcapabsetqid(dl_mid_t *, const queue_t *); extern boolean_t dlcapabcheckqid(const dl_mid_t *, const queue_t *); extern void dlnotifyack(queue_t *, mblk_t *, uint32_t); + +/* + * The ldi_handle_t typedef is in <sys/sunldi.h>, which in turn requires + * <sys/sunddi.h>, which pulls in <sys/cmn_err.h>, which declares kernel + * versions of the printf() functions that conflict with the libc ones. + * This causes conflicts when building MDB modules like ARP that #define + * _KERNEL. So we use `struct __ldi_handle *' instead. + */ +struct __ldi_handle; +extern int dl_attach(struct __ldi_handle *, int, dl_error_ack_t *); +extern int dl_bind(struct __ldi_handle *, uint_t, dl_error_ack_t *); +extern int dl_phys_addr(struct __ldi_handle *, uchar_t *, size_t *, + dl_error_ack_t *); +extern int dl_info(struct __ldi_handle *, dl_info_ack_t *, uchar_t *, size_t *, + dl_error_ack_t *); +extern int dl_notify(struct __ldi_handle *, uint32_t *, dl_error_ack_t *); +extern const char *dl_errstr(t_uscalar_t); +extern const char *dl_primstr(t_uscalar_t); +extern const char *dl_mactypestr(t_uscalar_t); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/dls.h b/usr/src/uts/common/sys/dls.h index 77bf2c1e58..f69a14e740 100644 --- a/usr/src/uts/common/sys/dls.h +++ b/usr/src/uts/common/sys/dls.h @@ -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. */ @@ -30,6 +30,7 @@ #include <sys/types.h> #include <sys/stream.h> +#include <net/if.h> #include <sys/mac.h> /* @@ -54,28 +55,172 @@ extern "C" { * Macros for converting ppas to instance #s, Vlan ID, or minor. */ #define DLS_PPA2INST(ppa) ((int)((ppa) % 1000)) -#define DLS_PPA2VID(ppa) ((uint16_t)((ppa) / 1000)) -#define DLS_PPA2MINOR(ppa) ((minor_t)((DLS_PPA2INST(ppa)) + 1)) +#define DLS_PPA2VID(ppa) ((ppa) / 1000) /* - * Maps a (VID, INST) pair to ppa + * Converts a minor to an instance#; makes sense only when minor <= 1000. */ -#define DLS_VIDINST2PPA(vid, inst) ((minor_t)((vid) * 1000 + (inst))) +#define DLS_MINOR2INST(minor) ((int)((minor) - 1)) + +typedef enum { + DATALINK_CLASS_PHYS = 0x01, + DATALINK_CLASS_VLAN = 0x02, + DATALINK_CLASS_AGGR = 0x04, + DATALINK_CLASS_VNIC = 0x08 +} datalink_class_t; + +#define DATALINK_CLASS_ALL (DATALINK_CLASS_PHYS | \ + DATALINK_CLASS_VLAN | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC) /* - * Converts a minor to an instance#; makes sense only when minor <= 1000. + * A combination of flags and media. + * flags is the higher 32 bits, and if it is 0x01, it indicates all media + * types can be accepted; otherwise, only the given media type (specified + * in the lower 32 bits) is accepted. */ -#define DLS_MINOR2INST(minor) ((int)((minor) - 1)) +typedef uint64_t datalink_media_t; + +#define DATALINK_ANY_MEDIATYPE \ + ((datalink_media_t)(((datalink_media_t)0x01) << 32)) + +#define DATALINK_MEDIA_ACCEPTED(dmedia, media) \ + (((uint32_t)(((dmedia) >> 32) & 0xfffffffful) & 0x01) ? \ + B_TRUE : ((uint32_t)((dmedia) & 0xfffffffful) == (media))) + +#define MAXLINKATTRLEN 32 + +/* + * Link attributes used by the kernel. + */ +/* + * The major number and instance number of the underlying physical device + * are kept as FPHYMAJ and FPHYINST (major, instance + 1). + * + * Set for physical links only. + */ +#define FPHYMAJ "phymaj" /* uint64_t */ +#define FPHYINST "phyinst" /* uint64_t */ + +/* + * The devname of the physical link. For example, bge0, ce1. Set for physical + * links only. + */ +#define FDEVNAME "devname" /* string */ + +#define DLMGMT_DOOR "/etc/.dlmgmt_door" +/* + * Door upcall command. + */ +#define DLMGMT_CMD_DLS_CREATE 1 +#define DLMGMT_CMD_DLS_GETATTR 2 +#define DLMGMT_CMD_DLS_DESTROY 3 +#define DLMGMT_CMD_GETNAME 4 +#define DLMGMT_CMD_GETLINKID 5 +#define DLMGMT_CMD_GETNEXT 6 +#define DLMGMT_CMD_DLS_UPDATE 7 +#define DLMGMT_CMD_BASE 128 + +/* + * Indicate the link mapping is active or persistent + */ +#define DLMGMT_ACTIVE 0x01 +#define DLMGMT_PERSIST 0x02 + +/* upcall argument */ +typedef struct dlmgmt_upcall_arg_create { + int ld_cmd; + datalink_class_t ld_class; + uint32_t ld_media; + boolean_t ld_persist; + uint64_t ld_phymaj; + uint64_t ld_phyinst; + char ld_devname[MAXNAMELEN]; +} dlmgmt_upcall_arg_create_t; + +typedef struct dlmgmt_upcall_arg_destroy { + int ld_cmd; + datalink_id_t ld_linkid; + boolean_t ld_persist; + int ld_reserved; +} dlmgmt_upcall_arg_destroy_t; + +typedef struct dlmgmt_upcall_arg_update { + int ld_cmd; + boolean_t ld_novanity; + uint32_t ld_media; + uint32_t ld_reserved; + char ld_devname[MAXNAMELEN]; +} dlmgmt_upcall_arg_update_t; + +typedef struct dlmgmt_upcall_arg_getattr { + int ld_cmd; + datalink_id_t ld_linkid; + char ld_attr[MAXLINKATTRLEN]; +} dlmgmt_upcall_arg_getattr_t; + +typedef struct dlmgmt_door_getname { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_getname_t; + +typedef struct dlmgmt_door_getlinkid { + int ld_cmd; + char ld_link[MAXLINKNAMELEN]; +} dlmgmt_door_getlinkid_t; + +typedef struct dlmgmt_door_getnext_s { + int ld_cmd; + datalink_id_t ld_linkid; + datalink_class_t ld_class; + uint32_t ld_flags; + datalink_media_t ld_dmedia; +} dlmgmt_door_getnext_t; + +/* upcall return value */ +struct dlmgmt_linkid_retval_s { + uint_t lr_err; + datalink_id_t lr_linkid; + uint32_t lr_flags; + datalink_class_t lr_class; + uint32_t lr_media; + uint32_t lr_reserved; +}; + +typedef struct dlmgmt_linkid_retval_s dlmgmt_create_retval_t, + dlmgmt_update_retval_t, + dlmgmt_getlinkid_retval_t, + dlmgmt_getnext_retval_t; + +typedef struct dlmgmt_getname_retval_s { + uint_t lr_err; + char lr_link[MAXLINKNAMELEN]; + datalink_class_t lr_class; + uint32_t lr_media; + uint32_t lr_flags; +} dlmgmt_getname_retval_t; + +struct dlmgmt_null_retval_s { + uint_t lr_err; +}; + +typedef struct dlmgmt_null_retval_s dlmgmt_destroy_retval_t; + +typedef struct dlmgmt_getattr_retval_s { + uint_t lr_err; + uint_t lr_type; + char lr_attr[1]; +} dlmgmt_getattr_retval_t; #ifdef _KERNEL -extern int dls_create(const char *, const char *); -extern int dls_destroy(const char *); +#define DLS_MAX_PPA 999 +#define DLS_MAX_MINOR (DLS_MAX_PPA + 1) -typedef struct dls_t *dls_channel_t; +typedef struct dls_t *dls_channel_t; -extern int dls_open(const char *, dls_channel_t *); -extern void dls_close(dls_channel_t); +extern int dls_open_style2_vlan(major_t, uint_t, dls_channel_t *); +extern int dls_open_by_dev(dev_t, dls_channel_t *); +extern void dls_close(dls_channel_t); extern mac_handle_t dls_mac(dls_channel_t); extern uint16_t dls_vid(dls_channel_t); @@ -83,26 +228,27 @@ extern uint16_t dls_vid(dls_channel_t); #define DLS_SAP_LLC 0 #define DLS_SAP_PROMISC (1 << 16) -extern int dls_bind(dls_channel_t, uint32_t); -extern void dls_unbind(dls_channel_t); +extern int dls_bind(dls_channel_t, uint32_t); +extern void dls_unbind(dls_channel_t); #define DLS_PROMISC_SAP 0x00000001 #define DLS_PROMISC_MULTI 0x00000002 #define DLS_PROMISC_PHYS 0x00000004 -extern int dls_promisc(dls_channel_t, uint32_t); +extern int dls_promisc(dls_channel_t, uint32_t); -extern int dls_multicst_add(dls_channel_t, const uint8_t *); -extern int dls_multicst_remove(dls_channel_t, const uint8_t *); +extern int dls_multicst_add(dls_channel_t, const uint8_t *); +extern int dls_multicst_remove(dls_channel_t, const uint8_t *); -extern mblk_t *dls_header(dls_channel_t, const uint8_t *, uint16_t, uint_t, - mblk_t **); -extern int dls_header_info(dls_channel_t, mblk_t *, mac_header_info_t *); +extern mblk_t *dls_header(dls_channel_t, const uint8_t *, + uint16_t, uint_t, mblk_t **); +extern int dls_header_info(dls_channel_t, mblk_t *, + mac_header_info_t *); -typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *, - mac_header_info_t *); +typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *, + mac_header_info_t *); -extern void dls_rx_set(dls_channel_t, dls_rx_t, void *); +extern void dls_rx_set(dls_channel_t, dls_rx_t, void *); extern mblk_t *dls_tx(dls_channel_t, mblk_t *); @@ -110,7 +256,47 @@ extern boolean_t dls_active_set(dls_channel_t); extern void dls_active_clear(dls_channel_t); extern dev_info_t *dls_finddevinfo(dev_t); -extern int dls_ppa_from_minor(minor_t, t_uscalar_t *); + +typedef struct dls_devnet_s *dls_dl_handle_t; +typedef struct dls_dev_t *dls_dev_handle_t; + +extern int dls_devnet_open(const char *, + dls_dl_handle_t *, dev_t *); +extern void dls_devnet_close(dls_dl_handle_t); +extern boolean_t dls_devnet_rebuild(); + +extern int dls_devnet_rename(datalink_id_t, datalink_id_t, + const char *); +extern int dls_devnet_create(mac_handle_t, datalink_id_t); +extern int dls_devnet_destroy(mac_handle_t, datalink_id_t *); +extern int dls_devnet_recreate(mac_handle_t, datalink_id_t); +extern int dls_devnet_create_vlan(datalink_id_t, + datalink_id_t, uint16_t, boolean_t); +extern int dls_devnet_destroy_vlan(datalink_id_t); +extern int dls_devnet_hold_tmp(datalink_id_t, dls_dl_handle_t *); +extern void dls_devnet_rele_tmp(dls_dl_handle_t); + +extern const char *dls_devnet_mac(dls_dl_handle_t); +extern uint16_t dls_devnet_vid(dls_dl_handle_t); +extern datalink_id_t dls_devnet_linkid(dls_dl_handle_t); +extern boolean_t dls_devnet_is_explicit(dls_dl_handle_t); +extern int dls_devnet_dev2linkid(dev_t, datalink_id_t *); +extern int dls_devnet_phydev(datalink_id_t, dev_t *); +extern int dls_devnet_setzid(const char *, zoneid_t); +extern int dls_devnet_getzid(datalink_id_t, zoneid_t *); + +extern int dls_mgmt_door_set(boolean_t); +extern int dls_mgmt_create(const char *, dev_t, datalink_class_t, + uint32_t, boolean_t, datalink_id_t *); +extern int dls_mgmt_destroy(datalink_id_t, boolean_t); +extern int dls_mgmt_update(const char *, uint32_t, boolean_t, + uint32_t *, datalink_id_t *); +extern int dls_mgmt_get_linkinfo(datalink_id_t, char *, + datalink_class_t *, uint32_t *, uint32_t *); +extern int dls_mgmt_get_linkid(const char *, datalink_id_t *); +extern datalink_id_t dls_mgmt_get_next(datalink_id_t, datalink_class_t, + datalink_media_t, uint32_t); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/dls_impl.h b/usr/src/uts/common/sys/dls_impl.h index c2a2dcf24c..83bccd20bb 100644 --- a/usr/src/uts/common/sys/dls_impl.h +++ b/usr/src/uts/common/sys/dls_impl.h @@ -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. */ @@ -71,16 +71,56 @@ struct dls_link_s { typedef struct dls_impl_s dls_impl_t; typedef struct dls_head_s dls_head_t; +/* + * The maximum length of an SPA (subnetwork point of attachment). It is of + * the form <macname/vid>. + */ +#define MAXSPALEN (MAXNAMELEN + 5) + typedef struct dls_vlan_s { - char dv_name[IFNAMSIZ]; - uint_t dv_ref; + /* + * The following fields will not change after dls_vlan_t creation. + */ dls_link_t *dv_dlp; uint16_t dv_id; + + /* + * Unique SPA (of the form <macname/vid>) identifying a data-link; + * is needed to avoid name collisions between an explicitly and + * implicitly created VLANs. + */ + char dv_spa[MAXSPALEN]; + + /* + * The ppa value of the associated device. Used to derive this link's + * devfs node name. + */ + uint_t dv_ppa; + + /* + * The dev_t used to access this dls_vlan_t. + */ + dev_t dv_dev; + + dev_info_t *dv_dip; kstat_t *dv_ksp; - minor_t dv_minor; - t_uscalar_t dv_ppa; + uint32_t dv_force : 1; + + /* + * The following fields are protected by dv_lock. + */ + kmutex_t dv_lock; + + /* + * Reference count of dls_impl_t plus explicit creation of the link + */ + uint_t dv_ref; + + /* + * The reference count of this vlan is opened in its own zone. + */ + uint_t dv_zone_ref; zoneid_t dv_zid; - dls_impl_t *dv_impl_list; } dls_vlan_t; struct dls_impl_s { @@ -98,14 +138,15 @@ struct dls_impl_s { void *di_rx_arg; mac_resource_add_t di_ring_add; const mac_txinfo_t *di_txinfo; - boolean_t di_bound; - boolean_t di_removing; - boolean_t di_active; + uint_t di_bound : 1, + di_removing : 1, + di_active : 1, + di_local : 1; + uint8_t di_unicst_addr[MAXMACADDRLEN]; soft_ring_t **di_soft_ring_list; uint_t di_soft_ring_size; - zoneid_t di_zid; - dls_impl_t *di_next_impl; + dls_dl_handle_t di_ddh; }; struct dls_head_s { @@ -121,37 +162,43 @@ extern void dls_link_rele(dls_link_t *); extern void dls_link_add(dls_link_t *, uint32_t, dls_impl_t *); extern void dls_link_remove(dls_link_t *, dls_impl_t *); extern int dls_link_header_info(dls_link_t *, mblk_t *, - mac_header_info_t *); + mac_header_info_t *); extern int dls_mac_hold(dls_link_t *); extern void dls_mac_rele(dls_link_t *); +extern boolean_t dls_mac_active_set(dls_link_t *); +extern void dls_mac_active_clear(dls_link_t *); extern void dls_mac_stat_create(dls_vlan_t *); extern void dls_mac_stat_destroy(dls_vlan_t *); extern void dls_vlan_init(void); extern int dls_vlan_fini(void); -extern int dls_vlan_create(const char *, const char *, uint16_t); -extern int dls_vlan_destroy(const char *); -extern int dls_vlan_hold(const char *, dls_vlan_t **, boolean_t); +extern int dls_vlan_hold(const char *, uint16_t, dls_vlan_t **, + boolean_t, boolean_t); +extern int dls_vlan_hold_by_dev(dev_t, dls_vlan_t **); extern void dls_vlan_rele(dls_vlan_t *); -extern int dls_vlan_walk(int (*)(dls_vlan_t *, void *), void *); -extern dev_info_t *dls_vlan_finddevinfo(dev_t); -extern int dls_vlan_ppa_from_minor(minor_t, t_uscalar_t *); -extern int dls_vlan_rele_by_name(const char *); -extern minor_t dls_minor_hold(boolean_t); -extern void dls_minor_rele(minor_t); -extern int dls_vlan_setzoneid(char *, zoneid_t, boolean_t); -extern int dls_vlan_getzoneid(char *, zoneid_t *); -extern void dls_vlan_add_impl(dls_vlan_t *, dls_impl_t *); -extern void dls_vlan_remove_impl(dls_vlan_t *, dls_impl_t *); +extern int dls_vlan_destroy(const char *, uint16_t); +extern int dls_vlan_create(const char *, uint16_t, boolean_t); +extern int dls_vlan_setzid(const char *, uint16_t, zoneid_t); +extern int dls_stat_update(kstat_t *, dls_vlan_t *, int); +extern int dls_stat_create(const char *, int, const char *, + int (*)(struct kstat *, int), void *, kstat_t **); + +extern int dls_devnet_open_by_dev(dev_t, dls_vlan_t **, + dls_dl_handle_t *); extern void dls_init(void); extern int dls_fini(void); extern void dls_link_txloop(void *, mblk_t *); extern boolean_t dls_accept(dls_impl_t *, mac_header_info_t *, - dls_rx_t *, void **); + dls_rx_t *, void **); extern boolean_t dls_accept_loopback(dls_impl_t *, mac_header_info_t *, - dls_rx_t *, void **); + dls_rx_t *, void **); + +extern void dls_mgmt_init(void); +extern void dls_mgmt_fini(void); + +extern int dls_mgmt_get_phydev(datalink_id_t, dev_t *); #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/dls_soft_ring.h b/usr/src/uts/common/sys/dls_soft_ring.h index 9a1a833eb7..403623853a 100644 --- a/usr/src/uts/common/sys/dls_soft_ring.h +++ b/usr/src/uts/common/sys/dls_soft_ring.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. */ @@ -88,8 +88,6 @@ extern void soft_ring_unbind(void *); extern void dls_soft_ring_fanout(void *, void *, mblk_t *, mac_header_info_t *); extern boolean_t dls_soft_ring_enable(dls_channel_t, dl_capab_dls_t *); extern void dls_soft_ring_disable(dls_channel_t); -extern boolean_t dls_soft_ring_workers(dls_channel_t); -extern void dls_soft_ring_rx_set(dls_channel_t, dls_rx_t, void *, int); #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/fs/sdev_impl.h b/usr/src/uts/common/sys/fs/sdev_impl.h index 281bc2faf7..7e5f75d7f7 100644 --- a/usr/src/uts/common/sys/fs/sdev_impl.h +++ b/usr/src/uts/common/sys/fs/sdev_impl.h @@ -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. */ @@ -193,6 +193,8 @@ typedef struct sdev_node { struct sdev_global_data sdev_globaldata; struct sdev_local_data sdev_localdata; } sdev_instance_data; + + void *sdev_private; } sdev_node_t; #define sdev_ldata sdev_instance_data.sdev_localdata @@ -245,13 +247,16 @@ typedef enum { } sdev_node_state_t; /* sdev_flags */ -#define SDEV_BUILD 0x0001 /* directory cache out-of-date */ -#define SDEV_STALE 0x0002 /* stale sdev nodes */ -#define SDEV_GLOBAL 0x0004 /* global /dev nodes */ -#define SDEV_PERSIST 0x0008 /* backing store persisted node */ -#define SDEV_NO_NCACHE 0x0010 /* do not include in neg. cache */ -#define SDEV_DYNAMIC 0x0020 /* special-purpose vnode ops (ex: pts) */ -#define SDEV_VTOR 0x0040 /* validate sdev_nodes during search */ +#define SDEV_BUILD 0x0001 /* directory cache out-of-date */ +#define SDEV_STALE 0x0002 /* stale sdev nodes */ +#define SDEV_GLOBAL 0x0004 /* global /dev nodes */ +#define SDEV_PERSIST 0x0008 /* backing store persisted node */ +#define SDEV_NO_NCACHE 0x0010 /* do not include in neg. cache */ +#define SDEV_DYNAMIC 0x0020 /* special-purpose vnode ops */ + /* (ex: pts) */ +#define SDEV_VTOR 0x0040 /* validate sdev_nodes during search */ +#define SDEV_ATTR_INVALID 0x0080 /* invalid node attributes, */ + /* need update */ /* sdev_lookup_flags */ #define SDEV_LOOKUP 0x0001 /* node creation in progress */ @@ -339,6 +344,12 @@ extern int devname_setattr_func(struct vnode *, struct vattr *, int, struct cred *, int (*)(struct sdev_node *, struct vattr *, int), int); /* + * devname_inactive_func() + */ +extern void devname_inactive_func(struct vnode *, struct cred *, + void (*)(struct vnode *)); + +/* * /dev file system instance defines */ /* @@ -607,6 +618,7 @@ extern int sdev_reserve_subdirs(struct sdev_node *); extern int prof_lookup(); extern void prof_filldir(struct sdev_node *); extern int devpts_validate(struct sdev_node *dv); +extern int devnet_validate(struct sdev_node *dv); extern void *sdev_get_vtor(struct sdev_node *dv); /* @@ -616,7 +628,6 @@ extern int sdev_modctl_readdir(const char *, char ***, int *, int *); extern void sdev_modctl_readdir_free(char **, int, int); extern int sdev_modctl_devexists(const char *); - /* * ncache handlers */ @@ -637,9 +648,11 @@ extern int devtype; extern kmem_cache_t *sdev_node_cache; extern struct vnodeops *sdev_vnodeops; extern struct vnodeops *devpts_vnodeops; +extern struct vnodeops *devnet_vnodeops; extern struct sdev_data *sdev_origins; /* mount info for global /dev instance */ extern const fs_operation_def_t sdev_vnodeops_tbl[]; extern const fs_operation_def_t devpts_vnodeops_tbl[]; +extern const fs_operation_def_t devnet_vnodeops_tbl[]; extern const fs_operation_def_t devsys_vnodeops_tbl[]; extern const fs_operation_def_t devpseudo_vnodeops_tbl[]; @@ -669,6 +682,7 @@ extern int sdev_debug; #define SDEV_DEBUG_PROFILE 0x200 /* trace sdev_profile */ #define SDEV_DEBUG_MODCTL 0x400 /* trace modctl activity */ #define SDEV_DEBUG_FLK 0x800 /* trace failed lookups */ +#define SDEV_DEBUG_NET 0x1000 /* /dev/net tracing */ #define sdcmn_err(args) if (sdev_debug & SDEV_DEBUG) printf args #define sdcmn_err2(args) if (sdev_debug & SDEV_DEBUG_VOPS) printf args @@ -681,6 +695,7 @@ extern int sdev_debug; #define sdcmn_err9(args) if (sdev_debug & SDEV_DEBUG_SDEV_NODE) printf args #define sdcmn_err10(args) if (sdev_debug & SDEV_DEBUG_PROFILE) printf args #define sdcmn_err11(args) if (sdev_debug & SDEV_DEBUG_MODCTL) printf args +#define sdcmn_err12(args) if (sdev_debug & SDEV_DEBUG_NET) printf args #define impossible(args) printf args #else #define sdcmn_err(args) /* does nothing */ @@ -694,6 +709,7 @@ extern int sdev_debug; #define sdcmn_err9(args) /* does nothing */ #define sdcmn_err10(args) /* does nothing */ #define sdcmn_err11(args) /* does nothing */ +#define sdcmn_err12(args) /* does nothing */ #define impossible(args) /* does nothing */ #endif diff --git a/usr/src/uts/common/sys/gld.h b/usr/src/uts/common/sys/gld.h index 3f3c01848e..fd7b8d37d2 100644 --- a/usr/src/uts/common/sys/gld.h +++ b/usr/src/uts/common/sys/gld.h @@ -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. */ @@ -176,7 +176,7 @@ typedef struct gld_mac_info { uchar_t *gldm_broadcast_addr; /* SET BY DRIVER */ gld_lock_t gldm_lock; /* GLD PRIVATE */ ddi_iblock_cookie_t gldm_cookie; /* SET BY DRIVER */ - uint32_t reserved3; /* GLD PRIVATE */ + uint32_t gldm_margin; /* SET BY DRIVER */ uint32_t reserved4; /* GLD PRIVATE */ uint32_t gldm_maxpkt; /* SET BY DRIVER */ uint32_t gldm_minpkt; /* SET BY DRIVER */ diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h index 63d7ff42a0..4fd83059c4 100644 --- a/usr/src/uts/common/sys/mac.h +++ b/usr/src/uts/common/sys/mac.h @@ -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. */ @@ -84,6 +84,11 @@ typedef enum { LINK_DUPLEX_FULL } link_duplex_t; +typedef uint32_t datalink_id_t; +#define DATALINK_INVALID_LINKID 0 +#define DATALINK_ALL_LINKID 0 +#define DATALINK_MAX_LINKID 0xffffffff + /* * Maximum MAC address length */ @@ -113,6 +118,16 @@ typedef struct mac_stat_info_s { #define IS_MACTYPE_STAT(stat) (stat >= MACTYPE_STAT_MIN) /* + * Statistics maintained by the mac module, and possibly populated as link + * statistics. + */ +enum mac_mod_stat { + MAC_STAT_LINK_STATE, + MAC_STAT_LINK_UP, + MAC_STAT_PROMISC +}; + +/* * Do not reorder, and add only to the end of this list. */ enum mac_driver_stat { @@ -191,6 +206,20 @@ typedef struct mac_capab_lso_s { } mac_capab_lso_t; /* + * Information for legacy devices. + */ +typedef struct mac_capab_legacy_s { + /* + * Notifications that the legacy device does not support. + */ + uint32_t ml_unsup_note; + /* + * dev_t of the legacy device; can be held to force attach. + */ + dev_t ml_dev; +} mac_capab_legacy_t; + +/* * MAC layer capabilities. These capabilities are handled by the drivers' * mc_capab_get() callbacks. Some capabilities require the driver to fill * in a given data structure, and others are simply boolean capabilities. @@ -199,11 +228,16 @@ typedef struct mac_capab_lso_s { * care about by keeping a bitfield of these things around somewhere. */ typedef enum { - MAC_CAPAB_HCKSUM = 0x01, /* data is a uint32_t for the txflags */ + MAC_CAPAB_HCKSUM = 0x01, /* data is a uint32_t for the txflags */ MAC_CAPAB_POLL = 0x02, /* boolean only, no data */ - MAC_CAPAB_MULTIADDRESS = 0x04, /* data is multiaddress_capab_t */ - MAC_CAPAB_LSO = 0x08 /* data is mac_capab_lso_t */ + MAC_CAPAB_MULTIADDRESS = 0x04, /* data is multiaddress_capab_t */ + MAC_CAPAB_LSO = 0x08, /* data is mac_capab_lso_t */ + MAC_CAPAB_NO_NATIVEVLAN = 0x10, /* boolean only, no data */ + MAC_CAPAB_NO_ZCOPY = 0x20, /* boolean only, no data */ /* add new capabilities here */ + + /* The following capabilities are specific to softmac. */ + MAC_CAPAB_LEGACY = 0x8001, /* data is mac_capab_legacy_t */ } mac_capab_t; typedef int mac_addr_slot_t; @@ -256,6 +290,8 @@ typedef void (*mac_ioctl_t)(void *, queue_t *, mblk_t *); typedef void (*mac_resources_t)(void *); typedef mblk_t *(*mac_tx_t)(void *, mblk_t *); typedef boolean_t (*mac_getcapab_t)(void *, mac_capab_t, void *); +typedef int (*mac_open_t)(void *); +typedef void (*mac_close_t)(void *); /* * Drivers must set all of these callbacks except for mc_resources, @@ -277,6 +313,8 @@ typedef struct mac_callbacks_s { mac_resources_t mc_resources; /* Get the device resources */ mac_ioctl_t mc_ioctl; /* Process an unknown ioctl */ mac_getcapab_t mc_getcapab; /* Get capability information */ + mac_open_t mc_open; /* Open the device */ + mac_close_t mc_close; /* Close the device */ } mac_callbacks_t; /* @@ -288,6 +326,10 @@ typedef struct mac_callbacks_s { #define MC_RESOURCES 0x001 #define MC_IOCTL 0x002 #define MC_GETCAPAB 0x004 +#define MC_OPEN 0x008 +#define MC_CLOSE 0x010 + +#define MAC_MAX_MINOR 1000 typedef struct mac_register_s { uint_t m_version; /* set by mac_alloc() */ @@ -302,6 +344,7 @@ typedef struct mac_register_s { uint_t m_max_sdu; void *m_pdata; size_t m_pdata_size; + uint32_t m_margin; } mac_register_t; /* @@ -325,6 +368,7 @@ typedef enum { MAC_NOTE_DEVPROMISC, MAC_NOTE_FASTPATH_FLUSH, MAC_NOTE_VNIC, + MAC_NOTE_MARGIN, MAC_NNOTE /* must be the last entry */ } mac_notify_type_t; @@ -382,8 +426,9 @@ typedef struct mac_header_info_s { uint32_t mhi_origsap; uint32_t mhi_bindsap; mac_addrtype_t mhi_dsttype; - boolean_t mhi_istagged; uint16_t mhi_tci; + uint_t mhi_istagged:1, + mhi_prom_looped:1; } mac_header_info_t; /* @@ -493,6 +538,10 @@ typedef struct mactype_register_s { * Client interface functions. */ extern int mac_open(const char *, mac_handle_t *); +extern int mac_open_by_linkid(datalink_id_t, + mac_handle_t *); +extern int mac_open_by_linkname(const char *, + mac_handle_t *); extern void mac_close(mac_handle_t); extern const mac_info_t *mac_info(mac_handle_t); extern boolean_t mac_info_get(const char *, mac_info_t *); @@ -500,14 +549,14 @@ extern uint64_t mac_stat_get(mac_handle_t, uint_t); extern int mac_start(mac_handle_t); extern void mac_stop(mac_handle_t); extern int mac_promisc_set(mac_handle_t, boolean_t, - mac_promisc_type_t); + mac_promisc_type_t); extern boolean_t mac_promisc_get(mac_handle_t, - mac_promisc_type_t); + mac_promisc_type_t); extern int mac_multicst_add(mac_handle_t, const uint8_t *); extern int mac_multicst_remove(mac_handle_t, - const uint8_t *); + const uint8_t *); extern boolean_t mac_unicst_verify(mac_handle_t, - const uint8_t *, uint_t); + const uint8_t *, uint_t); extern int mac_unicst_set(mac_handle_t, const uint8_t *); extern void mac_unicst_get(mac_handle_t, uint8_t *); extern void mac_dest_get(mac_handle_t, uint8_t *); @@ -517,44 +566,48 @@ extern const mac_txinfo_t *mac_tx_get(mac_handle_t); extern const mac_txinfo_t *mac_vnic_tx_get(mac_handle_t); extern link_state_t mac_link_get(mac_handle_t); extern mac_notify_handle_t mac_notify_add(mac_handle_t, mac_notify_t, - void *); + void *); extern void mac_notify_remove(mac_handle_t, - mac_notify_handle_t); + mac_notify_handle_t); extern void mac_notify(mac_handle_t); extern mac_rx_handle_t mac_rx_add(mac_handle_t, mac_rx_t, void *); extern mac_rx_handle_t mac_active_rx_add(mac_handle_t, mac_rx_t, - void *); + void *); extern void mac_rx_remove(mac_handle_t, mac_rx_handle_t, - boolean_t); + boolean_t); extern void mac_rx_remove_wait(mac_handle_t); extern mblk_t *mac_txloop(void *, mblk_t *); extern mac_txloop_handle_t mac_txloop_add(mac_handle_t, mac_txloop_t, - void *); + void *); extern void mac_txloop_remove(mac_handle_t, - mac_txloop_handle_t); + mac_txloop_handle_t); extern boolean_t mac_active_set(mac_handle_t); extern boolean_t mac_active_shareable_set(mac_handle_t); extern void mac_active_clear(mac_handle_t); extern void mac_active_rx(void *, mac_resource_handle_t, - mblk_t *); + mblk_t *); extern boolean_t mac_vnic_set(mac_handle_t, mac_txinfo_t *, - mac_getcapab_t, void *); + mac_getcapab_t, void *); extern void mac_vnic_clear(mac_handle_t); extern void mac_resource_set(mac_handle_t, - mac_resource_add_t, void *); + mac_resource_add_t, void *); extern dev_info_t *mac_devinfo_get(mac_handle_t); +extern const char *mac_name(mac_handle_t); +extern minor_t mac_minor(mac_handle_t); extern boolean_t mac_capab_get(mac_handle_t, mac_capab_t, - void *); + void *); extern boolean_t mac_vnic_capab_get(mac_handle_t, mac_capab_t, - void *); + void *); extern boolean_t mac_sap_verify(mac_handle_t, uint32_t, - uint32_t *); + uint32_t *); extern mblk_t *mac_header(mac_handle_t, const uint8_t *, - uint32_t, mblk_t *, size_t); + uint32_t, mblk_t *, size_t); extern int mac_header_info(mac_handle_t, mblk_t *, - mac_header_info_t *); + mac_header_info_t *); extern mblk_t *mac_header_cook(mac_handle_t, mblk_t *); extern mblk_t *mac_header_uncook(mac_handle_t, mblk_t *); +extern minor_t mac_minor_hold(boolean_t); +extern void mac_minor_rele(minor_t); /* * Driver interface functions. @@ -565,31 +618,38 @@ extern int mac_register(mac_register_t *, mac_handle_t *); extern int mac_disable(mac_handle_t); extern int mac_unregister(mac_handle_t); extern void mac_rx(mac_handle_t, mac_resource_handle_t, - mblk_t *); + mblk_t *); extern void mac_link_update(mac_handle_t, link_state_t); extern void mac_unicst_update(mac_handle_t, - const uint8_t *); + const uint8_t *); extern void mac_tx_update(mac_handle_t); extern void mac_resource_update(mac_handle_t); extern mac_resource_handle_t mac_resource_add(mac_handle_t, - mac_resource_t *); + mac_resource_t *); extern int mac_pdata_update(mac_handle_t, void *, - size_t); + size_t); extern void mac_multicst_refresh(mac_handle_t, - mac_multicst_t, void *, boolean_t); + mac_multicst_t, void *, boolean_t); extern void mac_unicst_refresh(mac_handle_t, mac_unicst_t, - void *); + void *); extern void mac_promisc_refresh(mac_handle_t, - mac_setpromisc_t, void *); + mac_setpromisc_t, void *); +extern boolean_t mac_margin_update(mac_handle_t, uint32_t); +extern void mac_margin_get(mac_handle_t, uint32_t *); +extern int mac_margin_remove(mac_handle_t, uint32_t); +extern int mac_margin_add(mac_handle_t, uint32_t *, + boolean_t); extern void mac_init_ops(struct dev_ops *, const char *); extern void mac_fini_ops(struct dev_ops *); +extern uint32_t mac_no_notification(mac_handle_t); +extern boolean_t mac_is_legacy(mac_handle_t); +extern int mac_hold_exclusive(mac_handle_t); +extern void mac_rele_exclusive(mac_handle_t); + extern mactype_register_t *mactype_alloc(uint_t); extern void mactype_free(mactype_register_t *); extern int mactype_register(mactype_register_t *); extern int mactype_unregister(const char *); -extern int mac_vlan_create(mac_handle_t, const char *, - minor_t); -extern void mac_vlan_remove(mac_handle_t, const char *); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h index d8fdcaf8dc..c0acfc5c37 100644 --- a/usr/src/uts/common/sys/mac_impl.h +++ b/usr/src/uts/common/sys/mac_impl.h @@ -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. */ @@ -35,15 +35,6 @@ extern "C" { #endif -/* - * Statistics maintained internally by the mac module. - */ -enum mac_mod_stat { - MAC_STAT_LINK_STATE, - MAC_STAT_LINK_UP, - MAC_STAT_PROMISC -}; - typedef struct mac_multicst_addr_s mac_multicst_addr_t; struct mac_multicst_addr_s { @@ -52,6 +43,14 @@ struct mac_multicst_addr_s { uint8_t mma_addr[MAXMACADDRLEN]; }; +typedef struct mac_margin_req_s mac_margin_req_t; + +struct mac_margin_req_s { + mac_margin_req_t *mmr_nextp; + uint_t mmr_ref; + uint32_t mmr_margin; +}; + typedef struct mac_notify_fn_s mac_notify_fn_t; struct mac_notify_fn_s { @@ -118,9 +117,11 @@ typedef struct mac_vnic_tx_s { * Each registered MAC is associated with a mac_t structure. */ typedef struct mac_impl_s { + /* + * The following fields are set in mac_register() and will not be + * changed until mac_unregister(). No lock is needed to access them. + */ char mi_name[LIFNAMSIZ]; - const char *mi_drvname; - uint_t mi_instance; void *mi_driver; /* Driver private data */ mac_info_t mi_info; mactype_t *mi_type; @@ -128,10 +129,22 @@ typedef struct mac_impl_s { size_t mi_pdata_size; mac_callbacks_t *mi_callbacks; dev_info_t *mi_dip; + minor_t mi_minor; + dev_t mi_phy_dev; + kstat_t *mi_ksp; + uint_t mi_kstat_count; + mac_txinfo_t mi_txinfo; + mac_txinfo_t mi_txloopinfo; + + krwlock_t mi_gen_lock; + uint32_t mi_oref; uint32_t mi_ref; boolean_t mi_disabled; + boolean_t mi_exclusive; + krwlock_t mi_state_lock; uint_t mi_active; + krwlock_t mi_data_lock; link_state_t mi_linkstate; link_state_t mi_lastlinkstate; @@ -140,25 +153,26 @@ typedef struct mac_impl_s { uint8_t mi_addr[MAXMACADDRLEN]; uint8_t mi_dstaddr[MAXMACADDRLEN]; mac_multicst_addr_t *mi_mmap; + krwlock_t mi_notify_lock; uint32_t mi_notify_bits; kmutex_t mi_notify_bits_lock; kthread_t *mi_notify_thread; mac_notify_fn_t *mi_mnfp; kcondvar_t mi_notify_cv; + krwlock_t mi_rx_lock; mac_rx_fn_t *mi_mrfp; krwlock_t mi_tx_lock; mac_txloop_fn_t *mi_mtfp; + krwlock_t mi_resource_lock; mac_resource_add_t mi_resource_add; void *mi_resource_add_arg; - kstat_t *mi_ksp; - uint_t mi_kstat_count; + kmutex_t mi_activelink_lock; boolean_t mi_activelink; - mac_txinfo_t mi_txinfo; - mac_txinfo_t mi_txloopinfo; + uint32_t mi_rx_ref; /* #threads in mac_rx() */ uint32_t mi_rx_removed; /* #callbacks marked */ /* for removal */ @@ -171,11 +185,23 @@ typedef struct mac_impl_s { mac_txinfo_t mi_vnic_txloopinfo; mac_getcapab_t mi_vnic_getcapab_fn; void *mi_vnic_getcapab_arg; + + boolean_t mi_legacy; + uint32_t mi_unsup_note; + uint32_t mi_margin; + + /* + * List of margin value requests added by mac clients. This list is + * sorted: the first one has the greatest value. + */ + mac_margin_req_t *mi_mmrp; } mac_impl_t; #define mi_getstat mi_callbacks->mc_getstat #define mi_start mi_callbacks->mc_start #define mi_stop mi_callbacks->mc_stop +#define mi_open mi_callbacks->mc_open +#define mi_close mi_callbacks->mc_close #define mi_setpromisc mi_callbacks->mc_setpromisc #define mi_multicst mi_callbacks->mc_multicst #define mi_unicst mi_callbacks->mc_unicst diff --git a/usr/src/uts/common/sys/param.h b/usr/src/uts/common/sys/param.h index d73d4cf8be..bfd895e137 100644 --- a/usr/src/uts/common/sys/param.h +++ b/usr/src/uts/common/sys/param.h @@ -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. */ @@ -188,6 +188,13 @@ extern "C" { #define MAXSYMLINKS 20 #define MAXNAMELEN 256 +/* + * MAXLINKNAMELEN defines the longest possible permitted datalink name, + * including the terminating NUL. Note that this must not be larger + * than related networking constants such as LIFNAMSIZ. + */ +#define MAXLINKNAMELEN 32 + #ifndef NADDR #define NADDR 13 #endif diff --git a/usr/src/lib/libinetcfg/common/inetcfg_nic.h b/usr/src/uts/common/sys/softmac.h index 7351150ec1..c82a27c0d8 100644 --- a/usr/src/lib/libinetcfg/common/inetcfg_nic.h +++ b/usr/src/uts/common/sys/softmac.h @@ -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,25 +19,32 @@ * CDDL HEADER END */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _INETCFG_NIC_H -#define _INETCFG_NIC_H +#ifndef _SYS_SOFTMAC_H +#define _SYS_SOFTMAC_H #pragma ident "%Z%%M% %I% %E% SMI" -#include <inetcfg.h> +#include <sys/types.h> +#include <sys/sunddi.h> +#include <sys/mac.h> +#include <sys/dls.h> #ifdef __cplusplus extern "C" { #endif -extern int nic_get_list(icfg_if_t **, int *); +int softmac_create(dev_info_t *, dev_t); +int softmac_destroy(dev_info_t *, dev_t); +int softmac_hold_device(dev_t, dls_dev_handle_t *); +void softmac_rele_device(dls_dev_handle_t); +void softmac_recreate(); #ifdef __cplusplus } #endif -#endif /* _INETCFG_NIC_H */ +#endif /* _SYS_SOFTMAC_H */ diff --git a/usr/src/uts/common/sys/softmac_impl.h b/usr/src/uts/common/sys/softmac_impl.h new file mode 100644 index 0000000000..93071c17a9 --- /dev/null +++ b/usr/src/uts/common/sys/softmac_impl.h @@ -0,0 +1,234 @@ +/* + * 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. + */ + +#ifndef _SYS_SOFTMAC_IMPL_H +#define _SYS_SOFTMAC_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/ethernet.h> +#include <sys/taskq.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/strsun.h> +#include <sys/stream.h> +#include <sys/dlpi.h> +#include <sys/mac.h> +#include <sys/mac_ether.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct softmac_lower_s { + struct softmac *sl_softmac; + queue_t *sl_wq; + + /* + * sl_ctl_inprogress is used to serialize the control path. It will + * be set when either an ioctl or an M_{PC,}PROTO message is received + * from the upper layer, and will be cleared when processing done. + */ + kmutex_t sl_ctl_mutex; + kcondvar_t sl_ctl_cv; + boolean_t sl_ctl_inprogress; + + /* + * When a control message is processed, either sl_pending_prim or + * sl_pending_ioctl will be set. They will be cleared when the + * acknowledgement of the specific control message is received + * from the underlying legacy driver. + */ + kmutex_t sl_mutex; + kcondvar_t sl_cv; + t_uscalar_t sl_pending_prim; + boolean_t sl_pending_ioctl; + mblk_t *sl_ack_mp; + + mac_resource_handle_t sl_handle; + ldi_handle_t sl_lh; +} softmac_lower_t; + +enum softmac_state { + SOFTMAC_INITIALIZED, + SOFTMAC_READY +}; + +typedef struct softmac_dev_s { + dev_t sd_dev; +} softmac_dev_t; + +/* + * smac_flag values. + */ +#define SOFTMAC_GLDV3 0x01 +#define SOFTMAC_NOSUPP 0x02 +#define SOFTMAC_ATTACH_DONE 0x04 +#define SOFTMAC_NEED_RECREATE 0x08 + +/* + * The softmac structure allows all minor nodes (at most two, style-1 and + * style-2) for the same device to be processed. A softmac_dev_t will be + * created for each minor node. + * + * We try to "register" the mac after all the softmac_dev_t's are processed so + * that even if DLPI operations fail (because of driver bugs) for one minor + * node, the other minor node can still be used to register the mac. + * (Specifically, an incorrect xxx_getinfo() implementation will cause style-2 + * minor node mac registration to fail.) + */ +typedef struct softmac { + /* + * The following fields will be set when the softmac is created and + * will not change. No lock is required. + */ + char smac_devname[MAXNAMELEN]; + major_t smac_umajor; + int smac_uppa; + uint32_t smac_cnt; /* # of minor nodes for this device */ + + /* + * The following fields are protected by softmac_hash_lock. + */ + /* + * The smac_hold_cnt field increases when softmac_hold_device() is + * called to force the dls_vlan_t of the device to be created. The + * device pre-detach fails if this counter is not 0. + */ + uint32_t smac_hold_cnt; + + /* + * The following fields are protected by smac_lock. + */ + kmutex_t smac_mutex; + kcondvar_t smac_cv; + uint32_t smac_flags; + int smac_attacherr; + mac_handle_t smac_mh; + softmac_dev_t *smac_softmac[2]; + taskqid_t smac_taskq; + /* + * Number of minor nodes whose post-attach routine has succeeded. + * This should be the same as the numbers of softmac_dev_t. + * Note that it does not imply SOFTMAC_ATTACH_DONE as the taskq might + * be still ongoing. + */ + uint32_t smac_attachok_cnt; + /* + * Number of softmac_dev_t left when pre-detach fails. This is used + * to indicate whether postattach is called because of a failed + * pre-detach. + */ + uint32_t smac_attached_left; + + /* + * This field is set and cleared by users of softmac (who calls + * softmac_hold/rele_device()). It is protected by smac_mutex. + */ + dev_info_t *smac_udip; + + /* + * The remaining fields are used to register the MAC for a legacy + * device. They are set in softmac_mac_register() and do not change. + * One can access them when mac_register() is done without locks. + */ + + /* + * media type is needed for create <link name, linkid> mapping, so + * it is set for GLDv3 device as well + */ + uint_t smac_media; + /* DLPI style of the underlying device */ + int smac_style; + dev_t smac_dev; + size_t smac_saplen; + size_t smac_addrlen; + uchar_t smac_unicst_addr[MAXMACADDRLEN]; + uint_t smac_min_sdu; + uint_t smac_max_sdu; + uint32_t smac_margin; + + /* Notifications the underlying driver can support. */ + uint32_t smac_notifications; + + /* + * Capabilities of the underlying driver. + */ + uint32_t smac_capab_flags; + uint32_t smac_hcksum_txflags; + boolean_t smac_no_capability_req; + dl_capab_mdt_t smac_mdt_capab; + boolean_t smac_mdt; + + /* + * The following fields are protected by smac_lock + */ + krwlock_t smac_lock; + enum softmac_state smac_state; + /* Lower stream structure */ + softmac_lower_t *smac_lower; +} softmac_t; + +typedef struct smac_ioc_start_s { + softmac_lower_t *si_slp; +} smac_ioc_start_t; + +#define SMAC_IOC ('S' << 24 | 'M' << 16 | 'C' << 8) +#define SMAC_IOC_START (SMAC_IOC | 0x01) + +#define SOFTMAC_BLANK_TICKS 128 +#define SOFTMAC_BLANK_PKT_COUNT 8 + +extern dev_info_t *softmac_dip; +#define SOFTMAC_DEV_NAME "softmac" + +extern int softmac_send_bind_req(softmac_lower_t *, uint_t); +extern int softmac_send_notify_req(softmac_lower_t *, uint32_t); +extern int softmac_send_promisc_req(softmac_lower_t *, t_uscalar_t, + boolean_t); +extern void softmac_init(void); +extern void softmac_fini(void); +extern boolean_t softmac_busy(void); +extern int softmac_fill_capab(ldi_handle_t, softmac_t *); +extern int softmac_capab_enable(softmac_lower_t *); +extern void softmac_rput_process_notdata(queue_t *, mblk_t *); +extern void softmac_rput_process_data(softmac_lower_t *, mblk_t *); + +extern int softmac_m_promisc(void *, boolean_t); +extern int softmac_m_multicst(void *, boolean_t, const uint8_t *); +extern int softmac_m_unicst(void *, const uint8_t *); +extern void softmac_m_ioctl(void *, queue_t *, mblk_t *); +extern int softmac_m_stat(void *, uint_t, uint64_t *); +extern mblk_t *softmac_m_tx(void *, mblk_t *); +extern void softmac_m_resources(void *); +extern int softmac_proto_tx(softmac_lower_t *, mblk_t *, mblk_t **); +extern void softmac_ioctl_tx(softmac_lower_t *, mblk_t *, mblk_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SOFTMAC_IMPL_H */ diff --git a/usr/src/uts/common/sys/vnic.h b/usr/src/uts/common/sys/vnic.h index 16cfbf85fc..58622037b3 100644 --- a/usr/src/uts/common/sys/vnic.h +++ b/usr/src/uts/common/sys/vnic.h @@ -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,9 +54,9 @@ typedef enum { #define VNIC_IOC_CREATE VNIC_IOC(1) typedef struct vnic_ioc_create { - uint_t vc_vnic_id; + datalink_id_t vc_vnic_id; + datalink_id_t vc_link_id; uint_t vc_mac_len; - uchar_t vc_dev_name[MAXNAMELEN]; vnic_mac_addr_type_t vc_mac_addr_type; uchar_t vc_mac_addr[MAXMACADDRLEN]; } vnic_ioc_create_t; @@ -64,9 +64,9 @@ typedef struct vnic_ioc_create { #ifdef _SYSCALL32 typedef struct vnic_ioc_create32 { - uint32_t vc_vnic_id; + datalink_id_t vc_vnic_id; + datalink_id_t vc_link_id; uint32_t vc_mac_len; - uchar_t vc_dev_name[MAXNAMELEN]; vnic_mac_addr_type_t vc_mac_addr_type; uchar_t vc_mac_addr[MAXMACADDRLEN]; } vnic_ioc_create32_t; @@ -76,13 +76,13 @@ typedef struct vnic_ioc_create32 { #define VNIC_IOC_DELETE VNIC_IOC(2) typedef struct vnic_ioc_delete { - uint_t vd_vnic_id; + datalink_id_t vd_vnic_id; } vnic_ioc_delete_t; #ifdef _SYSCALL32 typedef struct vnic_ioc_delete32 { - uint32_t vd_vnic_id; + datalink_id_t vd_vnic_id; } vnic_ioc_delete32_t; #endif /* _SYSCALL32 */ @@ -90,25 +90,25 @@ typedef struct vnic_ioc_delete32 { #define VNIC_IOC_INFO VNIC_IOC(3) typedef struct vnic_ioc_info_vnic { - uint32_t vn_vnic_id; + datalink_id_t vn_vnic_id; + datalink_id_t vn_link_id; uint32_t vn_mac_len; uchar_t vn_mac_addr[MAXMACADDRLEN]; - char vn_dev_name[MAXNAMELEN]; vnic_mac_addr_type_t vn_mac_addr_type; } vnic_ioc_info_vnic_t; typedef struct vnic_ioc_info { uint_t vi_nvnics; - uint_t vi_vnic_id; /* 0 returns all */ - char vi_dev_name[MAXNAMELEN]; + datalink_id_t vi_vnic_id; /* DATALINK_ALL_LINKID returns all */ + datalink_id_t vi_linkid; } vnic_ioc_info_t; #ifdef _SYSCALL32 typedef struct vnic_ioc_info32 { uint32_t vi_nvnics; - uint32_t vi_vnic_id; /* 0 returns all */ - char vi_dev_name[MAXNAMELEN]; + datalink_id_t vi_vnic_id; /* DATALINK_ALL_LINKID returns all */ + datalink_id_t vi_linkid; } vnic_ioc_info32_t; #endif /* _SYSCALL32 */ @@ -118,7 +118,7 @@ typedef struct vnic_ioc_info32 { #define VNIC_IOC_MODIFY_ADDR 0x01 typedef struct vnic_ioc_modify { - uint_t vm_vnic_id; + datalink_id_t vm_vnic_id; uint_t vm_modify_mask; uchar_t vm_mac_addr[MAXMACADDRLEN]; vnic_mac_addr_type_t vm_mac_addr_type; @@ -128,7 +128,7 @@ typedef struct vnic_ioc_modify { #ifdef _SYSCALL32 typedef struct vnic_ioc_modify32 { - uint32_t vm_vnic_id; + datalink_id_t vm_vnic_id; uint32_t vm_modify_mask; uchar_t vm_mac_addr[MAXMACADDRLEN]; vnic_mac_addr_type_t vm_mac_addr_type; diff --git a/usr/src/uts/common/sys/vnic_impl.h b/usr/src/uts/common/sys/vnic_impl.h index 3cab13b96c..6cb64523a8 100644 --- a/usr/src/uts/common/sys/vnic_impl.h +++ b/usr/src/uts/common/sys/vnic_impl.h @@ -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. */ @@ -65,7 +65,7 @@ typedef struct vnic_flow_tab_s { typedef struct vnic_mac_s { mac_handle_t va_mh; uint_t va_refs; - char va_dev_name[MAXNAMELEN]; + datalink_id_t va_linkid; const mac_txinfo_t *va_txinfo; struct vnic_bcast_grp_s *va_bcast_grp; krwlock_t va_bcast_grp_lock; @@ -81,7 +81,7 @@ typedef struct vnic_mac_s { } vnic_mac_t; typedef struct vnic_s { - uint_t vn_id; + datalink_id_t vn_id; uint32_t vn_started : 1, vn_promisc : 1, @@ -96,6 +96,7 @@ typedef struct vnic_s { vnic_mac_addr_type_t vn_addr_type; mac_handle_t vn_mh; + uint32_t vn_margin; vnic_mac_t *vn_vnic_mac; vnic_flow_t *vn_flow_ent; uint32_t vn_hcksum_txflags; @@ -140,20 +141,20 @@ typedef struct vnic_s { mutex_exit(&(flow)->vf_lock); \ } -extern int vnic_dev_create(uint_t, char *, int, uchar_t *); -extern int vnic_dev_modify(uint_t, uint_t, vnic_mac_addr_type_t, +extern int vnic_dev_create(datalink_id_t, datalink_id_t, int, uchar_t *); +extern int vnic_dev_modify(datalink_id_t, uint_t, vnic_mac_addr_type_t, uint_t, uchar_t *); -extern int vnic_dev_delete(uint_t); +extern int vnic_dev_delete(datalink_id_t); -typedef int (*vnic_info_new_vnic_fn_t)(void *, uint32_t, vnic_mac_addr_type_t, - uint_t, uint8_t *, char *); +typedef int (*vnic_info_new_vnic_fn_t)(void *, datalink_id_t, + vnic_mac_addr_type_t, uint_t, uint8_t *, datalink_id_t); extern void vnic_dev_init(void); extern void vnic_dev_fini(void); extern uint_t vnic_dev_count(void); extern dev_info_t *vnic_get_dip(void); -extern int vnic_info(uint_t *, uint32_t, char *, void *, +extern int vnic_info(uint_t *, datalink_id_t, datalink_id_t, void *, vnic_info_new_vnic_fn_t); extern void vnic_rx(void *, void *, mblk_t *); diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h index 0a93e8651e..34cdf78a33 100644 --- a/usr/src/uts/common/sys/zone.h +++ b/usr/src/uts/common/sys/zone.h @@ -455,6 +455,7 @@ extern zone_t *zone_find_by_any_path(const char *, boolean_t); extern zone_t *zone_find_by_path(const char *); extern zoneid_t getzoneid(void); extern zone_t *zone_find_by_id_nolock(zoneid_t); +extern int zone_datalink_walk(zoneid_t, int (*)(const char *, void *), void *); /* * Zone-specific data (ZSD) APIs diff --git a/usr/src/uts/common/xen/io/xnbo.c b/usr/src/uts/common/xen/io/xnbo.c index 723d650c55..91714e9117 100644 --- a/usr/src/uts/common/xen/io/xnbo.c +++ b/usr/src/uts/common/xen/io/xnbo.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. */ @@ -248,9 +248,9 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) xsname = xvdi_get_xsname(xnbp->xnb_devinfo); - if ((err = mac_open(mac, &xnbop->o_mh)) != 0) { + if ((err = mac_open_by_linkname(mac, &xnbop->o_mh)) != 0) { cmn_err(CE_WARN, "xnbo_open_mac: " - "cannot open mac device %s (%d)", mac, err); + "cannot open mac for link %s (%d)", mac, err); return (B_FALSE); } ASSERT(xnbop->o_mh != NULL); @@ -260,13 +260,13 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) if (mi->mi_media != DL_ETHER) { cmn_err(CE_WARN, "xnbo_open_mac: " - "mac device is not DL_ETHER (%d)", mi->mi_media); + "device is not DL_ETHER (%d)", mi->mi_media); xnbo_close_mac(xnbop); return (B_FALSE); } if (mi->mi_media != mi->mi_nativemedia) { cmn_err(CE_WARN, "xnbo_open_mac: " - "mac device media and native media mismatch (%d != %d)", + "device media and native media mismatch (%d != %d)", mi->mi_media, mi->mi_nativemedia); xnbo_close_mac(xnbop); return (B_FALSE); diff --git a/usr/src/uts/common/xen/io/xnbu.c b/usr/src/uts/common/xen/io/xnbu.c index fa9604194b..f7e84987a1 100644 --- a/usr/src/uts/common/xen/io/xnbu.c +++ b/usr/src/uts/common/xen/io/xnbu.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. */ @@ -432,6 +432,12 @@ xnbu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) mr->m_callbacks = &xnb_callbacks; mr->m_min_sdu = 0; mr->m_max_sdu = XNBMAXPKT; + /* + * xnbu is a virtual device, and it is not associated with any + * physical device. Its margin size is determined by the maximum + * packet size it can handle, which is PAGESIZE. + */ + mr->m_margin = PAGESIZE - XNBMAXPKT - sizeof (struct ether_header); (void) memset(xnbp->xnb_mac_addr, 0xff, ETHERADDRL); xnbp->xnb_mac_addr[0] &= 0xfe; diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared index d82da0c29e..6a3ab2e8b9 100644 --- a/usr/src/uts/intel/Makefile.intel.shared +++ b/usr/src/uts/intel/Makefile.intel.shared @@ -296,6 +296,7 @@ DRV_KMODS += sd DRV_KMODS += sgen DRV_KMODS += si3124 DRV_KMODS += smbios +DRV_KMODS += softmac DRV_KMODS += spdsock DRV_KMODS += smbsrv DRV_KMODS += smp @@ -654,3 +655,8 @@ DEVNAME_KMODS += sdev_nsconfig_mod # kiconv modules (/kernel/kiconv): # KICONV_KMODS += kiconv_emea + +# +# 'Dacf' Modules (/kernel/dacf): +# +DACF_KMODS += net_dacf diff --git a/usr/src/uts/intel/aggr/Makefile b/usr/src/uts/intel/aggr/Makefile index 284f7b8c50..3a14fcfe92 100644 --- a/usr/src/uts/intel/aggr/Makefile +++ b/usr/src/uts/intel/aggr/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" @@ -55,7 +55,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Ndrv/dld -Nmisc/mac +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Nmisc/dls # # For now, disable these lint checks; maintainers should endeavor diff --git a/usr/src/uts/intel/dev/Makefile b/usr/src/uts/intel/dev/Makefile index b0674572cf..78e6685df7 100644 --- a/usr/src/uts/intel/dev/Makefile +++ b/usr/src/uts/intel/dev/Makefile @@ -20,7 +20,7 @@ # # uts/intel/dev/Makefile # -# 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" @@ -61,7 +61,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # MODSTUBS_DIR = $(OBJS_DIR) CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Nfs/devfs +LDFLAGS += -dy -Nfs/devfs -Nmisc/dls # # Default build targets. diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s index bf631b8978..e49fe5c4b8 100644 --- a/usr/src/uts/intel/ia32/ml/modstubs.s +++ b/usr/src/uts/intel/ia32/ml/modstubs.s @@ -1218,24 +1218,41 @@ fcnname/**/_info: \ /* * The following stubs are used by the mac module. - * Since dls and dld already depend on mac, these + * Since dld already depends on mac, these * stubs are needed to avoid circular dependencies. */ -#ifndef DLS_MODULE - MODULE(dls,misc); - STUB(dls, dls_create, nomod_einval); - STUB(dls, dls_destroy, nomod_einval); - END_MODULE(dls); -#endif - #ifndef DLD_MODULE MODULE(dld,drv); STUB(dld, dld_init_ops, nomod_void); STUB(dld, dld_fini_ops, nomod_void); + STUB(dld, dld_autopush, nomod_minus_one); END_MODULE(dld); #endif /* + * The following stubs are used by the mac module. + * Since dls already depends on mac, these + * stubs are needed to avoid circular dependencies. + */ +#ifndef DLS_MODULE + MODULE(dls,misc); + STUB(dls, dls_devnet_vid, nomod_zero); + STUB(dls, dls_devnet_mac, nomod_zero); + STUB(dls, dls_devnet_hold_tmp, nomod_einval); + STUB(dls, dls_devnet_rele_tmp, nomod_void); + STUB(dls, dls_mgmt_get_linkid, nomod_einval); + END_MODULE(dls); +#endif + +#ifndef SOFTMAC_MODULE + MODULE(softmac,drv); + STUB(softmac, softmac_hold_device, nomod_einval); + STUB(softmac, softmac_rele_device, nomod_void); + STUB(softmac, softmac_recreate, nomod_void); + END_MODULE(softmac); +#endif + +/* * Stubs for SDP-IB driver. */ #ifndef SDPIB_MODULE diff --git a/usr/src/uts/intel/io/amd8111s/amd8111s_main.c b/usr/src/uts/intel/io/amd8111s/amd8111s_main.c index 78d728741a..bb27ce64f3 100755 --- a/usr/src/uts/intel/io/amd8111s/amd8111s_main.c +++ b/usr/src/uts/intel/io/amd8111s/amd8111s_main.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. */ @@ -81,6 +81,7 @@ /* include files */ #include <sys/disp.h> #include <sys/atomic.h> +#include <sys/vlan.h> #include "amd8111s_main.h" /* Global macro Definations */ @@ -1837,6 +1838,7 @@ amd8111s_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) macp->m_min_sdu = 0; /* 1518 - 14 (ether header) - 4 (CRC) */ macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; /* * Finally, we're ready to register ourselves with the MAC layer diff --git a/usr/src/uts/intel/net_dacf/Makefile b/usr/src/uts/intel/net_dacf/Makefile new file mode 100644 index 0000000000..8b0e8cd9d7 --- /dev/null +++ b/usr/src/uts/intel/net_dacf/Makefile @@ -0,0 +1,81 @@ +# +# 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 +# +# +# uts/intel/net_dacf/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = net_dacf +OBJECTS = $(NET_DACF_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NET_DACF_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DACF_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) +LDFLAGS += -dy -Ndrv/softmac + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/os/dacf.conf b/usr/src/uts/intel/os/dacf.conf index 5b8f1f1320..9ccb1b8282 100644 --- a/usr/src/uts/intel/os/dacf.conf +++ b/usr/src/uts/intel/os/dacf.conf @@ -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. # # @@ -67,3 +66,9 @@ driver-minorname="mouse8042:internal_mouse" consconfig_dacf:ms_config pre-detach # driver-minorname="usb_ac:mux" usb_ac_dacf:usb_audio_config post-attach - driver-minorname="usb_ac:mux" usb_ac_dacf:usb_audio_config pre-detach - + +# +# Configure and/or unconfigure DDI_NT_NET devices. +# +minor-nodetype="ddi_network" net_dacf:net_config post-attach - +minor-nodetype="ddi_network" net_dacf:net_config pre-detach - diff --git a/usr/src/uts/intel/os/device_policy b/usr/src/uts/intel/os/device_policy index 510a855f01..118fae1eaf 100644 --- a/usr/src/uts/intel/os/device_policy +++ b/usr/src/uts/intel/os/device_policy @@ -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. # # CDDL HEADER START @@ -62,6 +62,7 @@ pcelx read_priv_set=net_rawaccess write_priv_set=net_rawaccess spwr read_priv_set=net_rawaccess write_priv_set=net_rawaccess aggr read_priv_set=net_rawaccess write_priv_set=net_rawaccess vnic read_priv_set=net_rawaccess write_priv_set=net_rawaccess +softmac read_priv_set=net_rawaccess write_priv_set=net_rawaccess # # Virtual network interface access permission # diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major index 56e10ff720..d9fc868ae5 100644 --- a/usr/src/uts/intel/os/name_to_major +++ b/usr/src/uts/intel/os/name_to_major @@ -147,3 +147,4 @@ xnbu 251 vnic 252 pit_beep 253 vscan 254 +softmac 255 diff --git a/usr/src/uts/intel/softmac/Makefile b/usr/src/uts/intel/softmac/Makefile new file mode 100644 index 0000000000..163ab0e7c1 --- /dev/null +++ b/usr/src/uts/intel/softmac/Makefile @@ -0,0 +1,92 @@ +# +# 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" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = softmac +OBJECTS = $(SOFTMAC_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SOFTMAC_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/softmac + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides +# +CFLAGS += $(CCVERBOSE) +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Nmisc/strplumb -Nmisc/dls + +# +# For now, disable these lint checks as it is a generic STREAMS problem; +# maintainers should endeavor to investigate and remove these for maximum +# lint coverage. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN +LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/strplumb/Makefile b/usr/src/uts/intel/strplumb/Makefile index 321696983b..c7cccb236e 100644 --- a/usr/src/uts/intel/strplumb/Makefile +++ b/usr/src/uts/intel/strplumb/Makefile @@ -21,7 +21,7 @@ # # uts/intel/strplumb/Makefile # -# 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" @@ -57,9 +57,6 @@ ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) -# overrides -LDFLAGS += -dy -Nmisc/mac - # # For now, disable these lint checks; maintainers should endeavor # to investigate and remove these for maximum lint coverage. diff --git a/usr/src/uts/intel/vnic/Makefile b/usr/src/uts/intel/vnic/Makefile index 2b72585c21..e72dfeb434 100644 --- a/usr/src/uts/intel/vnic/Makefile +++ b/usr/src/uts/intel/vnic/Makefile @@ -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" @@ -55,7 +55,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Ndrv/ip +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Ndrv/ip -Nmisc/dls # # For now, disable these lint checks; maintainers should endeavor diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared index d747b59a74..4b7acadf5c 100644 --- a/usr/src/uts/sparc/Makefile.sparc.shared +++ b/usr/src/uts/sparc/Makefile.sparc.shared @@ -223,7 +223,7 @@ DRV_KMODS += ipsecesp iwscn keysock kmdb kstat ksyms llc1 DRV_KMODS += lofi DRV_KMODS += log logindmux kssl mm nca physmem pm poll pool DRV_KMODS += pseudo ptc ptm pts ptsl ramdisk random rsm rts sad -DRV_KMODS += sppp sppptun sy sysevent sysmsg +DRV_KMODS += softmac sppp sppptun sy sysevent sysmsg DRV_KMODS += spdsock DRV_KMODS += tcp tcp6 tl tnf ttymux udp udp6 wc winlock zcons DRV_KMODS += ippctl sctp sctp6 @@ -450,7 +450,7 @@ $(CLOSED_BUILD)CLOSED_XMODS = \ # # 'Dacf' Modules (/kernel/dacf): # -DACF_KMODS += usb_ac_dacf +DACF_KMODS += usb_ac_dacf net_dacf # # MAC-Type Plugin Modules (/kernel/mac) diff --git a/usr/src/uts/sparc/aggr/Makefile b/usr/src/uts/sparc/aggr/Makefile index 5c17d3578f..e914a5de11 100644 --- a/usr/src/uts/sparc/aggr/Makefile +++ b/usr/src/uts/sparc/aggr/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" @@ -55,7 +55,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Ndrv/dld -Nmisc/mac +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Nmisc/dls # # For now, disable these lint checks; maintainers should endeavor diff --git a/usr/src/uts/sparc/dev/Makefile b/usr/src/uts/sparc/dev/Makefile index eb6230b478..ab70028322 100644 --- a/usr/src/uts/sparc/dev/Makefile +++ b/usr/src/uts/sparc/dev/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" @@ -62,7 +62,7 @@ MODSTUBS_DIR = $(OBJS_DIR) # $(MODSTUBS_O) := AS_CPPFLAGS += -DDEVFS_MODULE # CLEANFILES += $(MODSTUBS_O) CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Nfs/devfs +LDFLAGS += -dy -Nfs/devfs -Nmisc/dls # # Default build targets. diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s index 2cf38c9a18..abc8c124f6 100644 --- a/usr/src/uts/sparc/ml/modstubs.s +++ b/usr/src/uts/sparc/ml/modstubs.s @@ -1182,23 +1182,40 @@ stubs_base: /* * The following stubs are used by the mac module. - * Since dls and dld already depend on mac, these + * Since dld already depends on mac, these * stubs are needed to avoid circular dependencies. */ -#ifndef DLS_MODULE - MODULE(dls,misc); - STUB(dls, dls_create, nomod_einval); - STUB(dls, dls_destroy, nomod_einval); - END_MODULE(dls); -#endif - #ifndef DLD_MODULE MODULE(dld,drv); STUB(dld, dld_init_ops, nomod_void); STUB(dld, dld_fini_ops, nomod_void); + STUB(dld, dld_autopush, nomod_minus_one); END_MODULE(dld); #endif +/* + * The following stubs are used by the mac module. + * Since dls already depends on mac, these + * stubs are needed to avoid circular dependencies. + */ +#ifndef DLS_MODULE + MODULE(dls,misc); + STUB(dls, dls_devnet_vid, nomod_zero); + STUB(dls, dls_devnet_mac, nomod_zero); + STUB(dls, dls_devnet_hold_tmp, nomod_einval); + STUB(dls, dls_devnet_rele_tmp, nomod_void); + STUB(dls, dls_mgmt_get_linkid, nomod_einval); + END_MODULE(dls); +#endif + +#ifndef SOFTMAC_MODULE + MODULE(softmac,drv); + STUB(softmac, softmac_hold_device, nomod_einval); + STUB(softmac, softmac_rele_device, nomod_void); + STUB(softmac, softmac_recreate, nomod_void); + END_MODULE(softmac); +#endif + #ifndef SDPIB_MODULE MODULE(sdpib,drv); STUB(sdpib, sdp_create, nomod_zero); diff --git a/usr/src/uts/sparc/net_dacf/Makefile b/usr/src/uts/sparc/net_dacf/Makefile new file mode 100644 index 0000000000..5dfe832d72 --- /dev/null +++ b/usr/src/uts/sparc/net_dacf/Makefile @@ -0,0 +1,81 @@ +# +# 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 +# +# +# uts/sparc/net_dacf/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = net_dacf +OBJECTS = $(NET_DACF_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NET_DACF_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DACF_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) +LDFLAGS += -dy -Ndrv/softmac + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/os/dacf.conf b/usr/src/uts/sparc/os/dacf.conf index 33c45a42ae..de9e672a68 100644 --- a/usr/src/uts/sparc/os/dacf.conf +++ b/usr/src/uts/sparc/os/dacf.conf @@ -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. # # @@ -73,3 +72,9 @@ driver-minorname="usb_ac:mux" usb_ac_dacf:usb_audio_config pre-detach - # minor-nodetype="ddi_keyboard" consconfig_dacf:kb_config post-attach - minor-nodetype="ddi_keyboard" consconfig_dacf:kb_config pre-detach - + +# +# Configure and/or unconfigure DDI_NT_NET devices. +# +minor-nodetype="ddi_network" net_dacf:net_config post-attach - +minor-nodetype="ddi_network" net_dacf:net_config pre-detach - diff --git a/usr/src/uts/sparc/os/device_policy b/usr/src/uts/sparc/os/device_policy index b4185a58ae..2667ba50b3 100644 --- a/usr/src/uts/sparc/os/device_policy +++ b/usr/src/uts/sparc/os/device_policy @@ -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. # # CDDL HEADER START @@ -65,6 +65,7 @@ pcelx read_priv_set=net_rawaccess write_priv_set=net_rawaccess qfe read_priv_set=net_rawaccess write_priv_set=net_rawaccess aggr read_priv_set=net_rawaccess write_priv_set=net_rawaccess vnic read_priv_set=net_rawaccess write_priv_set=net_rawaccess +softmac read_priv_set=net_rawaccess write_priv_set=net_rawaccess # # Virtual network interface access permission # diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major index 190fad1a20..fc4efd835f 100644 --- a/usr/src/uts/sparc/os/name_to_major +++ b/usr/src/uts/sparc/os/name_to_major @@ -220,3 +220,4 @@ ds_snmp 271 ds_pri 272 vnic 273 vscan 274 +softmac 275 diff --git a/usr/src/uts/sparc/softmac/Makefile b/usr/src/uts/sparc/softmac/Makefile new file mode 100644 index 0000000000..a7bfd6315d --- /dev/null +++ b/usr/src/uts/sparc/softmac/Makefile @@ -0,0 +1,92 @@ +# +# 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" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = softmac +OBJECTS = $(SOFTMAC_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SOFTMAC_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/softmac + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides +# +CFLAGS += $(CCVERBOSE) +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Nmisc/strplumb -Nmisc/dls + +# +# For now, disable these lint checks as it is a generic STREAMS problem; +# maintainers should endeavor to investigate and remove these for maximum +# lint coverage. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN +LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/vnic/Makefile b/usr/src/uts/sparc/vnic/Makefile index e8d4bc5507..b62599331f 100644 --- a/usr/src/uts/sparc/vnic/Makefile +++ b/usr/src/uts/sparc/vnic/Makefile @@ -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" @@ -55,7 +55,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) # Overrides # CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Ndrv/ip +LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Ndrv/ip -Nmisc/dls # # For now, disable these lint checks; maintainers should endeavor diff --git a/usr/src/uts/sun/io/eri.c b/usr/src/uts/sun/io/eri.c index 43ab9379fb..7a50fb8114 100644 --- a/usr/src/uts/sun/io/eri.c +++ b/usr/src/uts/sun/io/eri.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. */ @@ -48,6 +48,7 @@ #include <inet/mi.h> #include <inet/nd.h> #include <sys/ethernet.h> +#include <sys/vlan.h> #include <sys/policy.h> #include <sys/mac.h> #include <sys/mac_ether.h> @@ -722,6 +723,7 @@ eri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) macp->m_callbacks = &eri_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; /* * Map in the device registers. diff --git a/usr/src/uts/sun/io/hme.c b/usr/src/uts/sun/io/hme.c index b5512c0f98..f57bcd697b 100644 --- a/usr/src/uts/sun/io/hme.c +++ b/usr/src/uts/sun/io/hme.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. */ @@ -48,6 +48,7 @@ #include <sys/mac.h> #include <sys/mac_ether.h> #include <sys/ethernet.h> +#include <sys/vlan.h> #include <sys/pci.h> #include <sys/policy.h> #include <sys/ddi.h> @@ -3054,6 +3055,7 @@ hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) macp->m_callbacks = &hme_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; + macp->m_margin = VLAN_TAGSZ; if (mac_register(macp, &hmep->hme_mh) != 0) { mac_free(macp); goto error_intr; diff --git a/usr/src/uts/sun4v/io/vsw_phys.c b/usr/src/uts/sun4v/io/vsw_phys.c index 55eb290a6d..6c8776ab81 100644 --- a/usr/src/uts/sun4v/io/vsw_phys.c +++ b/usr/src/uts/sun4v/io/vsw_phys.c @@ -328,17 +328,16 @@ vsw_mac_open(vsw_t *vswp) return (EIO); } - rv = mac_open(vswp->physname, &vswp->mh); - if (rv != 0) { + if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) { /* - * If mac_open() failed and the error indicates that the - * device is not available yet, then, we return EAGAIN to - * indicate that it needs to be retried. - * For example, this may happen during boot up, as the - * required link aggregation groups(devices) have not been - * created yet. + * If mac_open() failed and the error indicates that either + * the dlmgmtd door or the device is not available yet, we + * return EAGAIN to indicate that mac_open() needs to be + * retried. For example, this may happen during boot up, if + * the required link aggregation groups(devices) have not + * been created yet. */ - if (rv == ENOENT) { + if (rv == ENOENT || rv == EBADF) { return (EAGAIN); } else { cmn_err(CE_WARN, "vsw%d: mac_open %s failed rv:%x", |