Print this page
10052 "dladm show-ether" should pick one kstat snapshot and stick with it
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gergo Doma <domag02@gmail.com>
Reviewed by: Andy Fiddaman <andy@omniosce.org>


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 




  26 #include <stddef.h>
  27 #include <stdio.h>
  28 #include <stdlib.h>
  29 #include <strings.h>
  30 #include <err.h>
  31 #include <errno.h>
  32 #include <fcntl.h>
  33 #include <kstat.h>
  34 #include <limits.h>
  35 #include <unistd.h>
  36 #include <signal.h>
  37 #include <sys/dld.h>
  38 #include <sys/ddi.h>
  39 
  40 #include <libdllink.h>
  41 #include <libdlflow.h>
  42 #include <libdlstat.h>
  43 #include <libdlaggr.h>
  44 
  45 struct flowlist {


 152                 return (-1);
 153 
 154         switch (type) {
 155         case KSTAT_DATA_UINT64:
 156                 *(uint64_t *)buf = knp->value.ui64;
 157                 break;
 158         case KSTAT_DATA_UINT32:
 159                 *(uint32_t *)buf = knp->value.ui32;
 160                 break;
 161         default:
 162                 return (-1);
 163         }
 164 
 165         return (0);
 166 }
 167 
 168 dladm_status_t
 169 dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
 170     const char *name, uint8_t type, void *val)
 171 {
 172         kstat_ctl_t     *kcp;
 173         char            module[DLPI_LINKNAME_MAX];
 174         uint_t          instance;
 175         char            link[DLPI_LINKNAME_MAX];
 176         dladm_status_t  status;
 177         uint32_t        flags, media;
 178         kstat_t         *ksp;
 179         dladm_phys_attr_t dpap;
 180 
 181         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
 182             &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
 183                 return (status);
 184 
 185         if (media != DL_ETHER)
 186                 return (DLADM_STATUS_LINKINVAL);
 187 
 188         status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
 189 
 190         if (status != DLADM_STATUS_OK)
 191                 return (status);
 192 
 193         status = dladm_parselink(dpap.dp_dev, module, &instance);
 194 
 195         if (status != DLADM_STATUS_OK)
 196                 return (status);
 197 
 198         if ((kcp = kstat_open()) == NULL) {
 199                 warn("kstat_open operation failed");
 200                 return (-1);
 201         }
 202 
 203         /*
 204          * The kstat query could fail if the underlying MAC
 205          * driver was already detached.
 206          */
 207         if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
 208             (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL)







 209                 goto bail;
 210 
 211         if (kstat_read(kcp, ksp, NULL) == -1)
 212                 goto bail;
 213 
 214         if (dladm_kstat_value(ksp, name, type, val) < 0)
 215                 goto bail;
 216 
 217         (void) kstat_close(kcp);
 218         return (DLADM_STATUS_OK);
 219 
 220 bail:
 221         (void) kstat_close(kcp);
 222         return (dladm_errno2status(errno));
 223 }
 224 
 225 /* Compute sum of 2 pktsums (s1 = s2 + s3) */
 226 void
 227 dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
 228 {
 229         s1->rbytes    = s2->rbytes    + s3->rbytes;
 230         s1->ipackets  = s2->ipackets  + s3->ipackets;
 231         s1->ierrors   = s2->ierrors   + s3->ierrors;
 232         s1->obytes    = s2->obytes    + s3->obytes;
 233         s1->opackets  = s2->opackets  + s3->opackets;
 234         s1->oerrors   = s2->oerrors   + s3->oerrors;
 235         s1->snaptime  = s2->snaptime;
 236 }
 237 
 238 #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
 239 
 240 
 241 /* Compute differences between 2 pktsums (s1 = s2 - s3) */


 701         DLSTAT_RX_HWLANE_IDLIST,
 702         DLSTAT_TX_HWLANE_IDLIST,
 703         DLSTAT_FANOUT_IDLIST
 704 } dlstat_idlist_type_t;
 705 
 706 void
 707 dladm_sort_index_list(uint_t idlist[], uint_t size)
 708 {
 709         int     i, j;
 710 
 711         for (j = 1; j < size; j++) {
 712                 int key = idlist[j];
 713                 for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
 714                         idlist[i + 1] = idlist[i];
 715                 idlist[i + 1] = key;
 716         }
 717 }
 718 
 719 /* Support for legacy drivers */
 720 void
 721 i_query_legacy_stats(const char *linkname, pktsum_t *stats)
 722 {
 723         kstat_ctl_t     *kcp;
 724         kstat_t         *ksp;
 725 
 726         bzero(stats, sizeof (*stats));
 727 
 728         if ((kcp = kstat_open()) == NULL)
 729                 return;
 730 
 731         ksp = dladm_kstat_lookup(kcp, "link", 0, linkname, NULL);
 732 
 733         if (ksp != NULL)
 734                 dladm_get_stats(kcp, ksp, stats);
 735 
 736         (void) kstat_close(kcp);
 737 }
 738 
 739 void *
 740 i_dlstat_legacy_rx_lane_stats(const char *linkname)
 741 {
 742         dladm_stat_chain_t      *head = NULL;
 743         pktsum_t                stats;
 744         rx_lane_stat_entry_t    *rx_lane_stat_entry;
 745 
 746         bzero(&stats, sizeof (pktsum_t));
 747 
 748         /* Query for dls stats */
 749         i_query_legacy_stats(linkname, &stats);
 750 
 751         /* Convert to desired data type */
 752         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
 753         if (rx_lane_stat_entry == NULL)
 754                 goto done;
 755 
 756         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
 757         rx_lane_stat_entry->rle_id = L_SWLANE;
 758 
 759         rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
 760         rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
 761         rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
 762 
 763         /* Allocate memory for wrapper */
 764         head = malloc(sizeof (dladm_stat_chain_t));
 765         if (head == NULL) {
 766                 free(rx_lane_stat_entry);
 767                 goto done;
 768         }
 769 
 770         head->dc_statentry = rx_lane_stat_entry;
 771         head->dc_next = NULL;
 772 done:
 773         return (head);
 774 }
 775 
 776 void *
 777 i_dlstat_legacy_tx_lane_stats(const char *linkname)
 778 {
 779         dladm_stat_chain_t      *head = NULL;
 780         pktsum_t                stats;
 781         tx_lane_stat_entry_t    *tx_lane_stat_entry;
 782 
 783         bzero(&stats, sizeof (pktsum_t));
 784 
 785         /* Query for dls stats */
 786         i_query_legacy_stats(linkname, &stats);
 787 
 788         /* Convert to desired data type */
 789         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
 790         if (tx_lane_stat_entry == NULL)
 791                 goto done;
 792 
 793         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
 794         tx_lane_stat_entry->tle_id = L_SWLANE;
 795 
 796         tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
 797         tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
 798 
 799         /* Allocate memory for wrapper */
 800         head = malloc(sizeof (dladm_stat_chain_t));
 801         if (head == NULL) {
 802                 free(tx_lane_stat_entry);
 803                 goto done;
 804         }
 805 
 806         head->dc_statentry = tx_lane_stat_entry;


 875 typedef struct dladm_extract_idlist_s {
 876         dlstat_idlist_type_t    di_type;
 877         char                    *di_prefix;
 878         dladm_search_kstat_t    *di_searchkstat;
 879 } dladm_extract_idlist_t;
 880 
 881 static dladm_extract_idlist_t dladm_extract_idlist[] = {
 882 { DLSTAT_RX_RING_IDLIST,        DLSTAT_MAC_RX_RING,
 883     i_dlstat_rx_ring_search},
 884 { DLSTAT_TX_RING_IDLIST,        DLSTAT_MAC_TX_RING,
 885     i_dlstat_tx_ring_search},
 886 { DLSTAT_RX_HWLANE_IDLIST,      DLSTAT_MAC_RX_HWLANE,
 887     i_dlstat_rx_hwlane_search},
 888 { DLSTAT_TX_HWLANE_IDLIST,      DLSTAT_MAC_TX_HWLANE,
 889     i_dlstat_tx_hwlane_search},
 890 { DLSTAT_FANOUT_IDLIST,         DLSTAT_MAC_FANOUT,
 891     i_dlstat_fanout_search}
 892 };
 893 
 894 static void
 895 i_dlstat_get_idlist(const char *modname, dlstat_idlist_type_t idlist_type,

 896     uint_t idlist[], uint_t *size)
 897 {
 898         kstat_ctl_t     *kcp;
 899         kstat_t         *ksp;
 900         char            *prefix;
 901         int             prefixlen;
 902         boolean_t       (*fptr_searchkstat)(kstat_t *);
 903 
 904         *size = 0;
 905 
 906         if ((kcp = kstat_open()) == NULL) {
 907                 warn("kstat_open operation failed");
 908                 goto done;
 909         }
 910 
 911         prefix = dladm_extract_idlist[idlist_type].di_prefix;
 912         fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
 913         prefixlen = strlen(prefix);
 914         for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
 915                 if ((strcmp(ksp->ks_module, modname) == 0) &&
 916                     fptr_searchkstat(ksp)) {
 917                         idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
 918                 }
 919         }
 920         dladm_sort_index_list(idlist, *size);
 921 
 922 done:
 923         (void) kstat_close(kcp);
 924 }
 925 
 926 static dladm_stat_chain_t *
 927 i_dlstat_query_stats(const char *modname, const char *prefix,
 928     uint_t idlist[], uint_t idlist_size,
 929     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
 930 {
 931         kstat_ctl_t             *kcp;
 932         kstat_t                 *ksp;
 933         char                    statname[MAXLINKNAMELEN];
 934         int                     i = 0;
 935         dladm_stat_chain_t      *head = NULL, *prev = NULL;
 936         dladm_stat_chain_t      *curr;
 937 
 938         if ((kcp = kstat_open()) == NULL) {
 939                 warn("kstat_open operation failed");
 940                 return (NULL);
 941         }
 942 
 943         for (i = 0; i < idlist_size; i++) {
 944                 uint_t  index = idlist[i];
 945 
 946                 (void) snprintf(statname, sizeof (statname), "%s%d", prefix,
 947                     index);
 948 
 949                 ksp = dladm_kstat_lookup(kcp, modname, 0, statname, NULL);

 950                 if (ksp == NULL)
 951                         continue;
 952 
 953                 curr = malloc(sizeof (dladm_stat_chain_t));
 954                 if (curr == NULL)
 955                         break;
 956 
 957                 curr->dc_statentry = fn(kcp, ksp, index);
 958                 if (curr->dc_statentry == NULL) {
 959                         free(curr);
 960                         break;
 961                 }
 962 
 963                 (void) strlcpy(curr->dc_statheader, statname,
 964                     sizeof (curr->dc_statheader));
 965                 curr->dc_next = NULL;
 966 
 967                 if (head == NULL)       /* First node */
 968                         head = curr;
 969                 else
 970                         prev->dc_next = curr;
 971 
 972                 prev = curr;
 973         }
 974 done:
 975         (void) kstat_close(kcp);
 976         return (head);
 977 }
 978 
 979 static misc_stat_entry_t *
 980 i_dlstat_misc_stats(const char *linkname)
 981 {
 982         kstat_ctl_t             *kcp;
 983         kstat_t                 *ksp;
 984         misc_stat_entry_t       *misc_stat_entry = NULL;
 985 
 986         if ((kcp = kstat_open()) == NULL)
 987                 return (NULL);
 988 
 989         ksp = dladm_kstat_lookup(kcp, linkname, 0, DLSTAT_MAC_MISC_STAT, NULL);

 990         if (ksp == NULL)
 991                 goto done;
 992 
 993         misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
 994         if (misc_stat_entry == NULL)
 995                 goto done;
 996 
 997         i_dlstat_get_stats(kcp, ksp, &misc_stat_entry->mse_stats,

 998             misc_stats_list, MISC_STAT_SIZE);
 999 done:
1000         (void) kstat_close(kcp);
1001         return (misc_stat_entry);
1002 }
1003 
1004 /* Rx lane statistic specific functions */
1005 static boolean_t
1006 i_dlstat_rx_lane_match(void *arg1, void *arg2)
1007 {
1008         rx_lane_stat_entry_t *s1 = arg1;
1009         rx_lane_stat_entry_t *s2 = arg2;
1010 
1011         return (s1->rle_index == s2->rle_index &&
1012             s1->rle_id == s2->rle_id);
1013 }
1014 
1015 static void *
1016 i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
1017 {
1018         rx_lane_stat_entry_t *s1 = arg1;
1019         rx_lane_stat_entry_t *s2 = arg2;
1020         rx_lane_stat_entry_t *diff_entry;


1091         if (local_stat_entry == NULL)
1092                 goto done;
1093 
1094         local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1095         local_stat_entry->rle_id = L_LOCAL;
1096 
1097         i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1098             rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1099 
1100         local_stat_entry->rle_stats.rl_ipackets =
1101             rx_lane_stat_entry->rle_stats.rl_lclpackets;
1102         local_stat_entry->rle_stats.rl_rbytes =
1103             rx_lane_stat_entry->rle_stats.rl_lclbytes;
1104 
1105 done:
1106         free(rx_lane_stat_entry);
1107         return (local_stat_entry);
1108 }
1109 
1110 static dladm_stat_chain_t *
1111 i_dlstat_rx_local_stats(const char *linkname)
1112 {
1113         dladm_stat_chain_t      *local_stats = NULL;
1114 
1115         local_stats = i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,

1116             default_idlist, default_idlist_size,
1117             i_dlstat_rx_local_retrieve_stat);
1118 
1119         if (local_stats != NULL) {
1120                 (void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
1121                     sizeof (local_stats->dc_statheader));
1122         }
1123         return (local_stats);
1124 }
1125 
1126 static dladm_stat_chain_t *
1127 i_dlstat_rx_bcast_stats(const char *linkname)
1128 {
1129         misc_stat_entry_t       *misc_stat_entry;
1130         dladm_stat_chain_t      *head = NULL;
1131         rx_lane_stat_entry_t    *rx_lane_stat_entry;
1132 
1133         misc_stat_entry = i_dlstat_misc_stats(linkname);
1134         if (misc_stat_entry == NULL)
1135                 goto done;
1136 
1137         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1138         if (rx_lane_stat_entry == NULL)
1139                 goto done;
1140 
1141         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1142         rx_lane_stat_entry->rle_id = L_BCAST;
1143 
1144         rx_lane_stat_entry->rle_stats.rl_ipackets =
1145             misc_stat_entry->mse_stats.ms_brdcstrcv +
1146             misc_stat_entry->mse_stats.ms_multircv;
1147         rx_lane_stat_entry->rle_stats.rl_intrs =
1148             misc_stat_entry->mse_stats.ms_brdcstrcv +
1149             misc_stat_entry->mse_stats.ms_multircv;
1150         rx_lane_stat_entry->rle_stats.rl_rbytes =
1151             misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
1152             misc_stat_entry->mse_stats.ms_multircvbytes;
1153 
1154         head = malloc(sizeof (dladm_stat_chain_t));
1155         if (head == NULL) {
1156                 free(rx_lane_stat_entry);
1157                 goto done;
1158         }
1159 
1160         head->dc_statentry = rx_lane_stat_entry;
1161         head->dc_next = NULL;
1162 
1163         free(misc_stat_entry);
1164 done:
1165         return (head);
1166 }
1167 
1168 static dladm_stat_chain_t *
1169 i_dlstat_rx_defunctlane_stats(const char *linkname)
1170 {
1171         misc_stat_entry_t       *misc_stat_entry;
1172         dladm_stat_chain_t      *head = NULL;
1173         rx_lane_stat_entry_t    *rx_lane_stat_entry;
1174 
1175         misc_stat_entry = i_dlstat_misc_stats(linkname);
1176         if (misc_stat_entry == NULL)
1177                 goto done;
1178 
1179         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1180         if (rx_lane_stat_entry == NULL)
1181                 goto done;
1182 
1183         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1184         rx_lane_stat_entry->rle_id = L_DFNCT;
1185 
1186         rx_lane_stat_entry->rle_stats.rl_ipackets =
1187             misc_stat_entry->mse_stats.ms_ipackets;
1188         rx_lane_stat_entry->rle_stats.rl_rbytes =
1189             misc_stat_entry->mse_stats.ms_rbytes;
1190         rx_lane_stat_entry->rle_stats.rl_intrs =
1191             misc_stat_entry->mse_stats.ms_intrs;
1192         rx_lane_stat_entry->rle_stats.rl_polls =
1193             misc_stat_entry->mse_stats.ms_polls;
1194         rx_lane_stat_entry->rle_stats.rl_sdrops =
1195             misc_stat_entry->mse_stats.ms_rxsdrops;


1197             misc_stat_entry->mse_stats.ms_chainunder10;
1198         rx_lane_stat_entry->rle_stats.rl_ch10_50 =
1199             misc_stat_entry->mse_stats.ms_chain10to50;
1200         rx_lane_stat_entry->rle_stats.rl_chg50 =
1201             misc_stat_entry->mse_stats.ms_chainover50;
1202 
1203         head = malloc(sizeof (dladm_stat_chain_t));
1204         if (head == NULL) {
1205                 free(rx_lane_stat_entry);
1206                 goto done;
1207         }
1208 
1209         head->dc_statentry = rx_lane_stat_entry;
1210         head->dc_next = NULL;
1211 
1212 done:
1213         return (head);
1214 }
1215 
1216 static dladm_stat_chain_t *
1217 i_dlstat_rx_hwlane_stats(const char *linkname)
1218 {
1219         uint_t  rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1220         uint_t  rx_hwlane_idlist_size;
1221 
1222         i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
1223             rx_hwlane_idlist, &rx_hwlane_idlist_size);
1224 
1225         return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_HWLANE,
1226             rx_hwlane_idlist, rx_hwlane_idlist_size,
1227             i_dlstat_rx_hwlane_retrieve_stat));
1228 }
1229 
1230 /*ARGSUSED*/
1231 static dladm_stat_chain_t *
1232 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1233     const char *linkname)
1234 {
1235         return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,
1236             default_idlist, default_idlist_size,
1237             i_dlstat_rx_swlane_retrieve_stat));
1238 }
1239 
1240 void *
1241 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1242 {
1243         dladm_stat_chain_t      *head = NULL;
1244         dladm_stat_chain_t      *local_stats = NULL;
1245         dladm_stat_chain_t      *bcast_stats = NULL;
1246         dladm_stat_chain_t      *defunctlane_stats = NULL;
1247         dladm_stat_chain_t      *lane_stats = NULL;
1248         char                    linkname[MAXLINKNAMELEN];
1249         boolean_t               is_legacy_driver;
1250 
1251         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1252             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1253                 goto done;
1254         }
1255 
1256         /* Check if it is legacy driver */
1257         if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1258             "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1259                 goto done;
1260         }
1261 
1262         if (is_legacy_driver) {
1263                 head = i_dlstat_legacy_rx_lane_stats(linkname);
1264                 goto done;
1265         }
1266 
1267         local_stats = i_dlstat_rx_local_stats(linkname);
1268         bcast_stats = i_dlstat_rx_bcast_stats(linkname);
1269         defunctlane_stats = i_dlstat_rx_defunctlane_stats(linkname);
1270         lane_stats = i_dlstat_rx_hwlane_stats(linkname);
1271         if (lane_stats == NULL)
1272                 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1273 
1274         head = i_dlstat_join_lists(local_stats, bcast_stats);
1275         head = i_dlstat_join_lists(head, defunctlane_stats);
1276         head = i_dlstat_join_lists(head, lane_stats);
1277 done:
1278         return (head);
1279 }
1280 
1281 /* Tx lane statistic specific functions */
1282 static boolean_t
1283 i_dlstat_tx_lane_match(void *arg1, void *arg2)
1284 {
1285         tx_lane_stat_entry_t *s1 = arg1;
1286         tx_lane_stat_entry_t *s2 = arg2;
1287 
1288         return (s1->tle_index == s2->tle_index &&
1289             s1->tle_id == s2->tle_id);
1290 }


1333 static void *
1334 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1335 {
1336         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1337 
1338         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1339         if (tx_lane_stat_entry == NULL)
1340                 goto done;
1341 
1342         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1343         tx_lane_stat_entry->tle_id = L_SWLANE;
1344 
1345         i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1346             tx_lane_stats_list, TX_LANE_STAT_SIZE);
1347 
1348 done:
1349         return (tx_lane_stat_entry);
1350 }
1351 
1352 static dladm_stat_chain_t *
1353 i_dlstat_tx_bcast_stats(const char *linkname)
1354 {
1355         misc_stat_entry_t       *misc_stat_entry;
1356         dladm_stat_chain_t      *head = NULL;
1357         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1358 
1359         misc_stat_entry = i_dlstat_misc_stats(linkname);
1360         if (misc_stat_entry == NULL)
1361                 goto done;
1362 
1363         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1364         if (tx_lane_stat_entry == NULL)
1365                 goto done;
1366 
1367         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1368         tx_lane_stat_entry->tle_id = L_BCAST;
1369 
1370         tx_lane_stat_entry->tle_stats.tl_opackets =
1371             misc_stat_entry->mse_stats.ms_brdcstxmt +
1372             misc_stat_entry->mse_stats.ms_multixmt;
1373 
1374         tx_lane_stat_entry->tle_stats.tl_obytes =
1375             misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1376             misc_stat_entry->mse_stats.ms_multixmtbytes;
1377 
1378         head = malloc(sizeof (dladm_stat_chain_t));
1379         if (head == NULL) {
1380                 free(tx_lane_stat_entry);
1381                 goto done;
1382         }
1383 
1384         head->dc_statentry = tx_lane_stat_entry;
1385         head->dc_next = NULL;
1386 
1387         free(misc_stat_entry);
1388 done:
1389         return (head);
1390 }
1391 
1392 static dladm_stat_chain_t *
1393 i_dlstat_tx_defunctlane_stats(const char *linkname)
1394 {
1395         misc_stat_entry_t       *misc_stat_entry;
1396         dladm_stat_chain_t      *head = NULL;
1397         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1398 
1399         misc_stat_entry = i_dlstat_misc_stats(linkname);
1400         if (misc_stat_entry == NULL)
1401                 goto done;
1402 
1403         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1404         if (tx_lane_stat_entry == NULL)
1405                 goto done;
1406 
1407         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1408         tx_lane_stat_entry->tle_id = L_DFNCT;
1409 
1410         tx_lane_stat_entry->tle_stats.tl_opackets =
1411             misc_stat_entry->mse_stats.ms_opackets;
1412         tx_lane_stat_entry->tle_stats.tl_obytes =
1413             misc_stat_entry->mse_stats.ms_obytes;
1414         tx_lane_stat_entry->tle_stats.tl_sdrops =
1415             misc_stat_entry->mse_stats.ms_txsdrops;
1416 
1417         head = malloc(sizeof (dladm_stat_chain_t));
1418         if (head == NULL) {
1419                 free(tx_lane_stat_entry);
1420                 goto done;
1421         }
1422 
1423         head->dc_statentry = tx_lane_stat_entry;
1424         head->dc_next = NULL;
1425 
1426 done:
1427         return (head);
1428 }
1429 
1430 static dladm_stat_chain_t *
1431 i_dlstat_tx_hwlane_stats(const char *linkname)
1432 {
1433         uint_t  tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1434         uint_t  tx_hwlane_idlist_size;
1435 
1436         i_dlstat_get_idlist(linkname, DLSTAT_TX_HWLANE_IDLIST,
1437             tx_hwlane_idlist, &tx_hwlane_idlist_size);
1438 
1439         return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_HWLANE,
1440             tx_hwlane_idlist, tx_hwlane_idlist_size,
1441             i_dlstat_tx_hwlane_retrieve_stat));
1442 }
1443 
1444 /*ARGSUSED*/
1445 static dladm_stat_chain_t *
1446 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1447     const char *linkname)
1448 {
1449         return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_SWLANE,
1450             default_idlist, default_idlist_size,
1451             i_dlstat_tx_swlane_retrieve_stat));
1452 }
1453 
1454 void *
1455 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1456 {
1457         dladm_stat_chain_t      *head = NULL;
1458         dladm_stat_chain_t      *bcast_stats = NULL;
1459         dladm_stat_chain_t      *defunctlane_stats = NULL;
1460         dladm_stat_chain_t      *lane_stats;
1461         char                    linkname[MAXLINKNAMELEN];
1462         boolean_t               is_legacy_driver;
1463 
1464         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1465             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1466                 goto done;
1467         }
1468 
1469         /* Check if it is legacy driver */
1470         if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1471             "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1472                 goto done;
1473         }
1474 
1475         if (is_legacy_driver) {
1476                 head = i_dlstat_legacy_tx_lane_stats(linkname);
1477                 goto done;
1478         }
1479 
1480         bcast_stats = i_dlstat_tx_bcast_stats(linkname);
1481         defunctlane_stats = i_dlstat_tx_defunctlane_stats(linkname);
1482         lane_stats = i_dlstat_tx_hwlane_stats(linkname);
1483         if (lane_stats == NULL)
1484                 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1485 
1486         head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1487         head = i_dlstat_join_lists(head, lane_stats);
1488 
1489 done:
1490         return (head);
1491 }
1492 
1493 /* Rx lane total statistic specific functions */
1494 void *
1495 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1496 {
1497         dladm_stat_chain_t      *total_head = NULL;
1498         dladm_stat_chain_t      *rx_lane_head, *curr;
1499         rx_lane_stat_entry_t    *total_stats;
1500 
1501         /* Get per rx lane stats */
1502         rx_lane_head = dlstat_rx_lane_stats(dh, linkid);


1635 }
1636 
1637 static void *
1638 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
1639     uint_t idlist[], uint_t idlist_size,
1640     const char *modname, const char *prefix)
1641 {
1642         int                     i;
1643         char                    statprefix[MAXLINKNAMELEN];
1644         char                    linkname[MAXLINKNAMELEN];
1645         dladm_stat_chain_t      *curr, *curr_head;
1646         dladm_stat_chain_t      *head = NULL, *prev = NULL;
1647         uint_t                  fanout_idlist[MAX_RINGS_PER_GROUP];
1648         uint_t                  fanout_idlist_size;
1649 
1650         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1651             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1652                 return (NULL);
1653         }
1654 
1655         i_dlstat_get_idlist(linkname, DLSTAT_FANOUT_IDLIST,
1656             fanout_idlist, &fanout_idlist_size);
1657 
1658         for (i = 0; i < idlist_size; i++) {
1659                 uint_t  index = idlist[i];
1660 
1661                 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
1662                     prefix, index);
1663 
1664                 curr_head = i_dlstat_query_stats(modname, statprefix,
1665                     fanout_idlist, fanout_idlist_size,
1666                     i_dlstat_fanout_retrieve_stat);
1667 
1668                 if (curr_head == NULL)  /* Last lane */
1669                         break;
1670 
1671                 if (head == NULL)       /* First lane */
1672                         head = curr_head;
1673                 else    /* Link new lane list to end of previous lane list */
1674                         prev->dc_next = curr_head;
1675 
1676                 /* Walk new lane list and set ids */
1677                 for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
1678                         fanout_stat_entry_t *curr_stats = curr->dc_statentry;
1679 
1680                         curr_stats->fe_index = index;
1681                         curr_stats->fe_id = L_HWLANE;
1682                         /*
1683                          * Save last pointer of previous linked list.
1684                          * This pointer is used to chain linked lists


1690 
1691         return (head);
1692 }
1693 
1694 void *
1695 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
1696     const char *linkname)
1697 {
1698         return (i_dlstat_query_fanout_stats(dh, linkid,
1699             default_idlist, default_idlist_size, linkname,
1700             DLSTAT_MAC_RX_SWLANE));
1701 }
1702 
1703 void *
1704 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1705     const char *linkname)
1706 {
1707         uint_t  rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1708         uint_t  rx_hwlane_idlist_size;
1709 
1710         i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
1711             rx_hwlane_idlist, &rx_hwlane_idlist_size);
1712 
1713         return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
1714             rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
1715 }
1716 
1717 void *
1718 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
1719 {
1720         dladm_stat_chain_t      *head = NULL;
1721         dladm_stat_chain_t      *fout_hwlane_stats;
1722         dladm_stat_chain_t      *fout_swlane_and_local_stats;
1723         fanout_stat_entry_t     *fout_stats;
1724         char                    linkname[MAXLINKNAMELEN];
1725 
1726         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1727             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1728                 goto done;
1729         }
1730 


1816          * kstats corresponding to physical device rings continue to use
1817          * device names even if the link is renamed using dladm rename-link.
1818          * Thus, given a linkid, we lookup the physical device name.
1819          * However, if an aggr is renamed, kstats corresponding to its
1820          * pseudo rings are renamed as well.
1821          */
1822         if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1823             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1824                 return (NULL);
1825         }
1826 
1827         if (class != DATALINK_CLASS_AGGR) {
1828                 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1829                     DLADM_STATUS_OK) {
1830                         return (NULL);
1831                 }
1832                 modname = dpa.dp_dev;
1833         } else
1834                 modname = linkname;
1835 
1836         i_dlstat_get_idlist(modname, DLSTAT_RX_RING_IDLIST,
1837             rx_ring_idlist, &rx_ring_idlist_size);
1838 
1839         return (i_dlstat_query_stats(modname, DLSTAT_MAC_RX_RING,
1840             rx_ring_idlist, rx_ring_idlist_size,
1841             i_dlstat_rx_ring_retrieve_stat));
1842 }
1843 
1844 /* Tx ring statistic specific functions */
1845 static boolean_t
1846 i_dlstat_tx_ring_match(void *arg1, void *arg2)
1847 {
1848         tx_lane_stat_entry_t    *s1 = arg1;
1849         tx_lane_stat_entry_t    *s2 = arg2;
1850 
1851         return (s1->tle_index == s2->tle_index);
1852 }
1853 
1854 static void *
1855 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
1856 {
1857         ring_stat_entry_t       *s1 = arg1;
1858         ring_stat_entry_t       *s2 = arg2;
1859         ring_stat_entry_t       *diff_entry;


1903          * kstats corresponding to physical device rings continue to use
1904          * device names even if the link is renamed using dladm rename-link.
1905          * Thus, given a linkid, we lookup the physical device name.
1906          * However, if an aggr is renamed, kstats corresponding to its
1907          * pseudo rings are renamed as well.
1908          */
1909         if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1910             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1911                 return (NULL);
1912         }
1913 
1914         if (class != DATALINK_CLASS_AGGR) {
1915                 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1916                     DLADM_STATUS_OK) {
1917                         return (NULL);
1918                 }
1919                 modname = dpa.dp_dev;
1920         } else
1921                 modname = linkname;
1922 
1923         i_dlstat_get_idlist(modname, DLSTAT_TX_RING_IDLIST,
1924             tx_ring_idlist, &tx_ring_idlist_size);
1925 
1926         return (i_dlstat_query_stats(modname, DLSTAT_MAC_TX_RING,
1927             tx_ring_idlist, tx_ring_idlist_size,
1928             i_dlstat_tx_ring_retrieve_stat));
1929 }
1930 
1931 /* Rx ring total statistic specific functions */
1932 void *
1933 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1934 {
1935         dladm_stat_chain_t      *total_head = NULL;
1936         dladm_stat_chain_t      *rx_ring_head, *curr;
1937         ring_stat_entry_t       *total_stats;
1938 
1939         /* Get per rx ring stats */
1940         rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
1941         if (rx_ring_head == NULL)
1942                 goto done;
1943 
1944         total_stats = calloc(1, sizeof (ring_stat_entry_t));
1945         if (total_stats == NULL)
1946                 goto done;


2153         aggr_port_stat_entry_t  *diff_entry;
2154 
2155         diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2156         if (diff_entry == NULL)
2157                 goto done;
2158 
2159         diff_entry->ape_portlinkid = s1->ape_portlinkid;
2160 
2161         DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2162             AGGR_PORT_STAT_SIZE);
2163 
2164 done:
2165         return (diff_entry);
2166 }
2167 
2168 /*
2169  * Query dls stats for the aggr port. This results in query for stats into
2170  * the corresponding device driver.
2171  */
2172 static aggr_port_stat_entry_t *
2173 i_dlstat_single_port_stats(const char *portname, datalink_id_t linkid)

2174 {
2175         kstat_ctl_t             *kcp;
2176         kstat_t                 *ksp;
2177         char                    module[DLPI_LINKNAME_MAX];
2178         uint_t                  instance;
2179         aggr_port_stat_entry_t  *aggr_port_stat_entry = NULL;
2180 
2181         if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2182                 goto done;
2183 
2184         if ((kcp = kstat_open()) == NULL) {
2185                 warn("kstat open operation failed");
2186                 return (NULL);
2187         }
2188 
2189         ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);

2190         if (ksp == NULL)
2191                 goto done;
2192 
2193         aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2194         if (aggr_port_stat_entry == NULL)
2195                 goto done;
2196 
2197         /* Save port's linkid */
2198         aggr_port_stat_entry->ape_portlinkid = linkid;
2199 
2200         i_dlstat_get_stats(kcp, ksp, &aggr_port_stat_entry->ape_stats,

2201             aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2202 done:
2203         (void) kstat_close(kcp);
2204         return (aggr_port_stat_entry);
2205 }
2206 
2207 void *
2208 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2209 {
2210         dladm_aggr_grp_attr_t   ginfo;
2211         int                     i;
2212         dladm_aggr_port_attr_t   *portp;
2213         dladm_phys_attr_t       dpa;
2214         aggr_port_stat_entry_t  *aggr_port_stat_entry;
2215         dladm_stat_chain_t      *head = NULL, *prev = NULL, *curr;
2216         dladm_stat_chain_t      *total_stats;
2217 
2218         /* Get aggr info */
2219         bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2220         if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2221             != DLADM_STATUS_OK)
2222                 goto done;
2223         /* For every port that is member of this aggr do */
2224         for (i = 0; i < ginfo.lg_nports; i++) {
2225                 portp = &(ginfo.lg_ports[i]);
2226                 if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2227                     DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2228                         goto done;
2229                 }
2230 
2231                 aggr_port_stat_entry = i_dlstat_single_port_stats(dpa.dp_dev,
2232                     portp->lp_linkid);
2233 
2234                 /* Create dladm_stat_chain_t object for this stat */
2235                 curr = malloc(sizeof (dladm_stat_chain_t));
2236                 if (curr == NULL) {
2237                         free(aggr_port_stat_entry);
2238                         goto done;
2239                 }
2240                 (void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2241                     sizeof (curr->dc_statheader));
2242                 curr->dc_statentry = aggr_port_stat_entry;
2243                 curr->dc_next = NULL;
2244 
2245                 /* Chain this aggr port stat entry */
2246                 /* head of the stat list */
2247                 if (prev == NULL)
2248                         head = curr;
2249                 else
2250                         prev->dc_next = curr;
2251                 prev = curr;
2252         }


2262         }
2263 
2264 done:
2265         free(ginfo.lg_ports);
2266         return (head);
2267 }
2268 
2269 /* Misc stat specific functions */
2270 void *
2271 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2272 {
2273         misc_stat_entry_t       *misc_stat_entry;
2274         dladm_stat_chain_t      *head = NULL;
2275         char                    linkname[MAXLINKNAMELEN];
2276 
2277         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2278             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2279                 goto done;
2280         }
2281 
2282         misc_stat_entry = i_dlstat_misc_stats(linkname);
2283         if (misc_stat_entry == NULL)
2284                 goto done;
2285 
2286         head = malloc(sizeof (dladm_stat_chain_t));
2287         if (head == NULL) {
2288                 free(misc_stat_entry);
2289                 goto done;
2290         }
2291 
2292         head->dc_statentry = misc_stat_entry;
2293         (void) strlcpy(head->dc_statheader, "mac_misc_stat",
2294             sizeof (head->dc_statheader));
2295         head->dc_next = NULL;
2296 
2297 done:
2298         return (head);
2299 }
2300 
2301 /* Exported functions */
2302 dladm_stat_chain_t *


2496         while (curr != NULL) {
2497                 dladm_stat_chain_t      *tofree = curr;
2498                 name_value_stat_entry_t *nv_entry = curr->dc_statentry;
2499                 name_value_stat_t       *nv_curr = nv_entry->nve_stats;
2500 
2501                 while (nv_curr != NULL) {
2502                         name_value_stat_t       *nv_tofree = nv_curr;
2503 
2504                         nv_curr = nv_curr->nv_nextstat;
2505                         free(nv_tofree);
2506                 }
2507 
2508                 curr = curr->dc_next;
2509                 free(nv_entry);
2510                 free(tofree);
2511         }
2512 }
2513 
2514 /* flow stats specific routines */
2515 flow_stat_t *
2516 dladm_flow_stat_query(const char *flowname)
2517 {
2518         kstat_ctl_t     *kcp;
2519         kstat_t         *ksp;
2520         flow_stat_t     *flow_stat = NULL;
2521 
2522         if ((kcp = kstat_open()) == NULL)
2523                 return (NULL);
2524 
2525         flow_stat = calloc(1, sizeof (flow_stat_t));
2526         if (flow_stat == NULL)
2527                 goto done;
2528 
2529         ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow");

2530 
2531         if (ksp != NULL) {
2532                 i_dlstat_get_stats(kcp, ksp, flow_stat, flow_stats_list,
2533                     FLOW_STAT_SIZE);
2534         }
2535 
2536 done:
2537         (void) kstat_close(kcp);
2538         return (flow_stat);
2539 }
2540 
2541 flow_stat_t *
2542 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
2543 {
2544         flow_stat_t     *diff_stat;
2545 
2546         diff_stat = calloc(1, sizeof (flow_stat_t));
2547         if (diff_stat == NULL)
2548                 goto done;
2549 
2550         if (op2 == NULL) {
2551                 bcopy(op1, diff_stat, sizeof (flow_stat_t));
2552         } else {
2553                 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
2554                     FLOW_STAT_SIZE);
2555         }
2556 done:
2557         return (diff_stat);
2558 }
2559 
2560 void
2561 dladm_flow_stat_free(flow_stat_t *curr)
2562 {
2563         free(curr);
2564 }
2565 
2566 /* Query all flow stats */
2567 name_value_stat_entry_t *
2568 dladm_flow_stat_query_all(const char *flowname)
2569 {
2570         flow_stat_t             *flow_stat;
2571         name_value_stat_entry_t *name_value_stat_entry = NULL;
2572 
2573         /* Query flow stats */
2574         flow_stat =  dladm_flow_stat_query(flowname);
2575         if (flow_stat == NULL)
2576                 goto done;
2577 
2578         /* Allocate memory for query all stat entry */
2579         name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2580         if (name_value_stat_entry == NULL) {
2581                 dladm_flow_stat_free(flow_stat);
2582                 goto done;
2583         }
2584 
2585         /* Header for these stat fields */
2586         (void) strncpy(name_value_stat_entry->nve_header, flowname,
2587             MAXFLOWNAMELEN);
2588 
2589         /* Convert every statfield in flow_stat to <statname, statval> pair */
2590         name_value_stat_entry->nve_stats =
2591             i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
2592 
2593         /* Free flow_stat */
2594         dladm_flow_stat_free(flow_stat);


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  28  */
  29 
  30 #include <stddef.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <strings.h>
  34 #include <err.h>
  35 #include <errno.h>
  36 #include <fcntl.h>
  37 #include <kstat.h>
  38 #include <limits.h>
  39 #include <unistd.h>
  40 #include <signal.h>
  41 #include <sys/dld.h>
  42 #include <sys/ddi.h>
  43 
  44 #include <libdllink.h>
  45 #include <libdlflow.h>
  46 #include <libdlstat.h>
  47 #include <libdlaggr.h>
  48 
  49 struct flowlist {


 156                 return (-1);
 157 
 158         switch (type) {
 159         case KSTAT_DATA_UINT64:
 160                 *(uint64_t *)buf = knp->value.ui64;
 161                 break;
 162         case KSTAT_DATA_UINT32:
 163                 *(uint32_t *)buf = knp->value.ui32;
 164                 break;
 165         default:
 166                 return (-1);
 167         }
 168 
 169         return (0);
 170 }
 171 
 172 dladm_status_t
 173 dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
 174     const char *name, uint8_t type, void *val)
 175 {

 176         char            module[DLPI_LINKNAME_MAX];
 177         uint_t          instance;
 178         char            link[DLPI_LINKNAME_MAX];
 179         dladm_status_t  status;
 180         uint32_t        flags, media;
 181         kstat_t         *ksp;
 182         dladm_phys_attr_t dpap;
 183 
 184         if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
 185             &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
 186                 return (status);
 187 
 188         if (media != DL_ETHER)
 189                 return (DLADM_STATUS_LINKINVAL);
 190 
 191         status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
 192 
 193         if (status != DLADM_STATUS_OK)
 194                 return (status);
 195 
 196         status = dladm_parselink(dpap.dp_dev, module, &instance);
 197 
 198         if (status != DLADM_STATUS_OK)
 199                 return (status);
 200 





 201         /*
 202          * The kstat query could fail if the underlying MAC
 203          * driver was already detached.
 204          */
 205         if (dladm_dld_kcp(handle) == NULL) {
 206                 warn("kstat_open operation failed");
 207                 return (-1);
 208         }
 209 
 210         if ((ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
 211             "mac")) == NULL &&
 212             (ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
 213             NULL)) == NULL)
 214                 goto bail;
 215 
 216         if (kstat_read(dladm_dld_kcp(handle), ksp, NULL) == -1)
 217                 goto bail;
 218 
 219         if (dladm_kstat_value(ksp, name, type, val) < 0)
 220                 goto bail;
 221 

 222         return (DLADM_STATUS_OK);
 223 
 224 bail:

 225         return (dladm_errno2status(errno));
 226 }
 227 
 228 /* Compute sum of 2 pktsums (s1 = s2 + s3) */
 229 void
 230 dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
 231 {
 232         s1->rbytes    = s2->rbytes    + s3->rbytes;
 233         s1->ipackets  = s2->ipackets  + s3->ipackets;
 234         s1->ierrors   = s2->ierrors   + s3->ierrors;
 235         s1->obytes    = s2->obytes    + s3->obytes;
 236         s1->opackets  = s2->opackets  + s3->opackets;
 237         s1->oerrors   = s2->oerrors   + s3->oerrors;
 238         s1->snaptime  = s2->snaptime;
 239 }
 240 
 241 #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
 242 
 243 
 244 /* Compute differences between 2 pktsums (s1 = s2 - s3) */


 704         DLSTAT_RX_HWLANE_IDLIST,
 705         DLSTAT_TX_HWLANE_IDLIST,
 706         DLSTAT_FANOUT_IDLIST
 707 } dlstat_idlist_type_t;
 708 
 709 void
 710 dladm_sort_index_list(uint_t idlist[], uint_t size)
 711 {
 712         int     i, j;
 713 
 714         for (j = 1; j < size; j++) {
 715                 int key = idlist[j];
 716                 for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
 717                         idlist[i + 1] = idlist[i];
 718                 idlist[i + 1] = key;
 719         }
 720 }
 721 
 722 /* Support for legacy drivers */
 723 void
 724 i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats)
 725 {

 726         kstat_t         *ksp;
 727 
 728         bzero(stats, sizeof (*stats));
 729 
 730         if (dladm_dld_kcp(dh) == NULL)
 731                 return;
 732 
 733         ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL);
 734 
 735         if (ksp != NULL)
 736                 dladm_get_stats(dladm_dld_kcp(dh), ksp, stats);


 737 }
 738 
 739 void *
 740 i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname)
 741 {
 742         dladm_stat_chain_t      *head = NULL;
 743         pktsum_t                stats;
 744         rx_lane_stat_entry_t    *rx_lane_stat_entry;
 745 
 746         bzero(&stats, sizeof (pktsum_t));
 747 
 748         /* Query for dls stats */
 749         i_query_legacy_stats(dh, linkname, &stats);
 750 
 751         /* Convert to desired data type */
 752         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
 753         if (rx_lane_stat_entry == NULL)
 754                 goto done;
 755 
 756         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
 757         rx_lane_stat_entry->rle_id = L_SWLANE;
 758 
 759         rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
 760         rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
 761         rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
 762 
 763         /* Allocate memory for wrapper */
 764         head = malloc(sizeof (dladm_stat_chain_t));
 765         if (head == NULL) {
 766                 free(rx_lane_stat_entry);
 767                 goto done;
 768         }
 769 
 770         head->dc_statentry = rx_lane_stat_entry;
 771         head->dc_next = NULL;
 772 done:
 773         return (head);
 774 }
 775 
 776 void *
 777 i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname)
 778 {
 779         dladm_stat_chain_t      *head = NULL;
 780         pktsum_t                stats;
 781         tx_lane_stat_entry_t    *tx_lane_stat_entry;
 782 
 783         bzero(&stats, sizeof (pktsum_t));
 784 
 785         /* Query for dls stats */
 786         i_query_legacy_stats(dh, linkname, &stats);
 787 
 788         /* Convert to desired data type */
 789         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
 790         if (tx_lane_stat_entry == NULL)
 791                 goto done;
 792 
 793         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
 794         tx_lane_stat_entry->tle_id = L_SWLANE;
 795 
 796         tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
 797         tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
 798 
 799         /* Allocate memory for wrapper */
 800         head = malloc(sizeof (dladm_stat_chain_t));
 801         if (head == NULL) {
 802                 free(tx_lane_stat_entry);
 803                 goto done;
 804         }
 805 
 806         head->dc_statentry = tx_lane_stat_entry;


 875 typedef struct dladm_extract_idlist_s {
 876         dlstat_idlist_type_t    di_type;
 877         char                    *di_prefix;
 878         dladm_search_kstat_t    *di_searchkstat;
 879 } dladm_extract_idlist_t;
 880 
 881 static dladm_extract_idlist_t dladm_extract_idlist[] = {
 882 { DLSTAT_RX_RING_IDLIST,        DLSTAT_MAC_RX_RING,
 883     i_dlstat_rx_ring_search},
 884 { DLSTAT_TX_RING_IDLIST,        DLSTAT_MAC_TX_RING,
 885     i_dlstat_tx_ring_search},
 886 { DLSTAT_RX_HWLANE_IDLIST,      DLSTAT_MAC_RX_HWLANE,
 887     i_dlstat_rx_hwlane_search},
 888 { DLSTAT_TX_HWLANE_IDLIST,      DLSTAT_MAC_TX_HWLANE,
 889     i_dlstat_tx_hwlane_search},
 890 { DLSTAT_FANOUT_IDLIST,         DLSTAT_MAC_FANOUT,
 891     i_dlstat_fanout_search}
 892 };
 893 
 894 static void
 895 i_dlstat_get_idlist(dladm_handle_t handle, const char *modname,
 896     dlstat_idlist_type_t idlist_type,
 897     uint_t idlist[], uint_t *size)
 898 {
 899         kstat_ctl_t     *kcp = dladm_dld_kcp(handle);
 900         kstat_t         *ksp;
 901         char            *prefix;
 902         int             prefixlen;
 903         boolean_t       (*fptr_searchkstat)(kstat_t *);
 904 
 905         *size = 0;
 906 
 907         if (kcp == NULL) {
 908                 warn("kstat_open operation failed");
 909                 return;
 910         }
 911 
 912         prefix = dladm_extract_idlist[idlist_type].di_prefix;
 913         fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
 914         prefixlen = strlen(prefix);
 915         for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
 916                 if ((strcmp(ksp->ks_module, modname) == 0) &&
 917                     fptr_searchkstat(ksp)) {
 918                         idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
 919                 }
 920         }
 921         dladm_sort_index_list(idlist, *size);



 922 }
 923 
 924 static dladm_stat_chain_t *
 925 i_dlstat_query_stats(dladm_handle_t handle, const char *modname,
 926     const char *prefix, uint_t idlist[], uint_t idlist_size,
 927     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
 928 {

 929         kstat_t                 *ksp;
 930         char                    statname[MAXLINKNAMELEN];
 931         int                     i = 0;
 932         dladm_stat_chain_t      *head = NULL, *prev = NULL;
 933         dladm_stat_chain_t      *curr;
 934 
 935         if (dladm_dld_kcp(handle) == NULL) {
 936                 warn("kstat_open operation failed");
 937                 return (NULL);
 938         }
 939 
 940         for (i = 0; i < idlist_size; i++) {
 941                 uint_t  index = idlist[i];
 942 
 943                 (void) snprintf(statname, sizeof (statname), "%s%d", prefix,
 944                     index);
 945 
 946                 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0,
 947                     statname, NULL);
 948                 if (ksp == NULL)
 949                         continue;
 950 
 951                 curr = malloc(sizeof (dladm_stat_chain_t));
 952                 if (curr == NULL)
 953                         break;
 954 
 955                 curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index);
 956                 if (curr->dc_statentry == NULL) {
 957                         free(curr);
 958                         break;
 959                 }
 960 
 961                 (void) strlcpy(curr->dc_statheader, statname,
 962                     sizeof (curr->dc_statheader));
 963                 curr->dc_next = NULL;
 964 
 965                 if (head == NULL)       /* First node */
 966                         head = curr;
 967                 else
 968                         prev->dc_next = curr;
 969 
 970                 prev = curr;
 971         }
 972 done:

 973         return (head);
 974 }
 975 
 976 static misc_stat_entry_t *
 977 i_dlstat_misc_stats(dladm_handle_t handle, const char *linkname)
 978 {

 979         kstat_t                 *ksp;
 980         misc_stat_entry_t       *misc_stat_entry = NULL;
 981 
 982         if (dladm_dld_kcp(handle) == NULL)
 983                 return (NULL);
 984 
 985         ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), linkname, 0,
 986             DLSTAT_MAC_MISC_STAT, NULL);
 987         if (ksp == NULL)
 988                 goto done;
 989 
 990         misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
 991         if (misc_stat_entry == NULL)
 992                 goto done;
 993 
 994         i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
 995             &misc_stat_entry->mse_stats,
 996             misc_stats_list, MISC_STAT_SIZE);
 997 done:

 998         return (misc_stat_entry);
 999 }
1000 
1001 /* Rx lane statistic specific functions */
1002 static boolean_t
1003 i_dlstat_rx_lane_match(void *arg1, void *arg2)
1004 {
1005         rx_lane_stat_entry_t *s1 = arg1;
1006         rx_lane_stat_entry_t *s2 = arg2;
1007 
1008         return (s1->rle_index == s2->rle_index &&
1009             s1->rle_id == s2->rle_id);
1010 }
1011 
1012 static void *
1013 i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
1014 {
1015         rx_lane_stat_entry_t *s1 = arg1;
1016         rx_lane_stat_entry_t *s2 = arg2;
1017         rx_lane_stat_entry_t *diff_entry;


1088         if (local_stat_entry == NULL)
1089                 goto done;
1090 
1091         local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1092         local_stat_entry->rle_id = L_LOCAL;
1093 
1094         i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1095             rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1096 
1097         local_stat_entry->rle_stats.rl_ipackets =
1098             rx_lane_stat_entry->rle_stats.rl_lclpackets;
1099         local_stat_entry->rle_stats.rl_rbytes =
1100             rx_lane_stat_entry->rle_stats.rl_lclbytes;
1101 
1102 done:
1103         free(rx_lane_stat_entry);
1104         return (local_stat_entry);
1105 }
1106 
1107 static dladm_stat_chain_t *
1108 i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname)
1109 {
1110         dladm_stat_chain_t      *local_stats = NULL;
1111 
1112         local_stats = i_dlstat_query_stats(handle, linkname,
1113             DLSTAT_MAC_RX_SWLANE,
1114             default_idlist, default_idlist_size,
1115             i_dlstat_rx_local_retrieve_stat);
1116 
1117         if (local_stats != NULL) {
1118                 (void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
1119                     sizeof (local_stats->dc_statheader));
1120         }
1121         return (local_stats);
1122 }
1123 
1124 static dladm_stat_chain_t *
1125 i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname)
1126 {
1127         misc_stat_entry_t       *misc_stat_entry;
1128         dladm_stat_chain_t      *head = NULL;
1129         rx_lane_stat_entry_t    *rx_lane_stat_entry;
1130 
1131         misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1132         if (misc_stat_entry == NULL)
1133                 goto done;
1134 
1135         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1136         if (rx_lane_stat_entry == NULL)
1137                 goto done;
1138 
1139         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1140         rx_lane_stat_entry->rle_id = L_BCAST;
1141 
1142         rx_lane_stat_entry->rle_stats.rl_ipackets =
1143             misc_stat_entry->mse_stats.ms_brdcstrcv +
1144             misc_stat_entry->mse_stats.ms_multircv;
1145         rx_lane_stat_entry->rle_stats.rl_intrs =
1146             misc_stat_entry->mse_stats.ms_brdcstrcv +
1147             misc_stat_entry->mse_stats.ms_multircv;
1148         rx_lane_stat_entry->rle_stats.rl_rbytes =
1149             misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
1150             misc_stat_entry->mse_stats.ms_multircvbytes;
1151 
1152         head = malloc(sizeof (dladm_stat_chain_t));
1153         if (head == NULL) {
1154                 free(rx_lane_stat_entry);
1155                 goto done;
1156         }
1157 
1158         head->dc_statentry = rx_lane_stat_entry;
1159         head->dc_next = NULL;
1160 
1161         free(misc_stat_entry);
1162 done:
1163         return (head);
1164 }
1165 
1166 static dladm_stat_chain_t *
1167 i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
1168 {
1169         misc_stat_entry_t       *misc_stat_entry;
1170         dladm_stat_chain_t      *head = NULL;
1171         rx_lane_stat_entry_t    *rx_lane_stat_entry;
1172 
1173         misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1174         if (misc_stat_entry == NULL)
1175                 goto done;
1176 
1177         rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1178         if (rx_lane_stat_entry == NULL)
1179                 goto done;
1180 
1181         rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1182         rx_lane_stat_entry->rle_id = L_DFNCT;
1183 
1184         rx_lane_stat_entry->rle_stats.rl_ipackets =
1185             misc_stat_entry->mse_stats.ms_ipackets;
1186         rx_lane_stat_entry->rle_stats.rl_rbytes =
1187             misc_stat_entry->mse_stats.ms_rbytes;
1188         rx_lane_stat_entry->rle_stats.rl_intrs =
1189             misc_stat_entry->mse_stats.ms_intrs;
1190         rx_lane_stat_entry->rle_stats.rl_polls =
1191             misc_stat_entry->mse_stats.ms_polls;
1192         rx_lane_stat_entry->rle_stats.rl_sdrops =
1193             misc_stat_entry->mse_stats.ms_rxsdrops;


1195             misc_stat_entry->mse_stats.ms_chainunder10;
1196         rx_lane_stat_entry->rle_stats.rl_ch10_50 =
1197             misc_stat_entry->mse_stats.ms_chain10to50;
1198         rx_lane_stat_entry->rle_stats.rl_chg50 =
1199             misc_stat_entry->mse_stats.ms_chainover50;
1200 
1201         head = malloc(sizeof (dladm_stat_chain_t));
1202         if (head == NULL) {
1203                 free(rx_lane_stat_entry);
1204                 goto done;
1205         }
1206 
1207         head->dc_statentry = rx_lane_stat_entry;
1208         head->dc_next = NULL;
1209 
1210 done:
1211         return (head);
1212 }
1213 
1214 static dladm_stat_chain_t *
1215 i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1216 {
1217         uint_t  rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1218         uint_t  rx_hwlane_idlist_size;
1219 
1220         i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST,
1221             rx_hwlane_idlist, &rx_hwlane_idlist_size);
1222 
1223         return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE,
1224             rx_hwlane_idlist, rx_hwlane_idlist_size,
1225             i_dlstat_rx_hwlane_retrieve_stat));
1226 }
1227 
1228 /*ARGSUSED*/
1229 static dladm_stat_chain_t *
1230 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1231     const char *linkname)
1232 {
1233         return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE,
1234             default_idlist, default_idlist_size,
1235             i_dlstat_rx_swlane_retrieve_stat));
1236 }
1237 
1238 void *
1239 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1240 {
1241         dladm_stat_chain_t      *head = NULL;
1242         dladm_stat_chain_t      *local_stats = NULL;
1243         dladm_stat_chain_t      *bcast_stats = NULL;
1244         dladm_stat_chain_t      *defunctlane_stats = NULL;
1245         dladm_stat_chain_t      *lane_stats = NULL;
1246         char                    linkname[MAXLINKNAMELEN];
1247         boolean_t               is_legacy_driver;
1248 
1249         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1250             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1251                 goto done;
1252         }
1253 
1254         /* Check if it is legacy driver */
1255         if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1256             "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1257                 goto done;
1258         }
1259 
1260         if (is_legacy_driver) {
1261                 head = i_dlstat_legacy_rx_lane_stats(dh, linkname);
1262                 goto done;
1263         }
1264 
1265         local_stats = i_dlstat_rx_local_stats(dh, linkname);
1266         bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname);
1267         defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname);
1268         lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname);
1269         if (lane_stats == NULL)
1270                 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1271 
1272         head = i_dlstat_join_lists(local_stats, bcast_stats);
1273         head = i_dlstat_join_lists(head, defunctlane_stats);
1274         head = i_dlstat_join_lists(head, lane_stats);
1275 done:
1276         return (head);
1277 }
1278 
1279 /* Tx lane statistic specific functions */
1280 static boolean_t
1281 i_dlstat_tx_lane_match(void *arg1, void *arg2)
1282 {
1283         tx_lane_stat_entry_t *s1 = arg1;
1284         tx_lane_stat_entry_t *s2 = arg2;
1285 
1286         return (s1->tle_index == s2->tle_index &&
1287             s1->tle_id == s2->tle_id);
1288 }


1331 static void *
1332 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1333 {
1334         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1335 
1336         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1337         if (tx_lane_stat_entry == NULL)
1338                 goto done;
1339 
1340         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1341         tx_lane_stat_entry->tle_id = L_SWLANE;
1342 
1343         i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1344             tx_lane_stats_list, TX_LANE_STAT_SIZE);
1345 
1346 done:
1347         return (tx_lane_stat_entry);
1348 }
1349 
1350 static dladm_stat_chain_t *
1351 i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname)
1352 {
1353         misc_stat_entry_t       *misc_stat_entry;
1354         dladm_stat_chain_t      *head = NULL;
1355         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1356 
1357         misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1358         if (misc_stat_entry == NULL)
1359                 goto done;
1360 
1361         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1362         if (tx_lane_stat_entry == NULL)
1363                 goto done;
1364 
1365         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1366         tx_lane_stat_entry->tle_id = L_BCAST;
1367 
1368         tx_lane_stat_entry->tle_stats.tl_opackets =
1369             misc_stat_entry->mse_stats.ms_brdcstxmt +
1370             misc_stat_entry->mse_stats.ms_multixmt;
1371 
1372         tx_lane_stat_entry->tle_stats.tl_obytes =
1373             misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1374             misc_stat_entry->mse_stats.ms_multixmtbytes;
1375 
1376         head = malloc(sizeof (dladm_stat_chain_t));
1377         if (head == NULL) {
1378                 free(tx_lane_stat_entry);
1379                 goto done;
1380         }
1381 
1382         head->dc_statentry = tx_lane_stat_entry;
1383         head->dc_next = NULL;
1384 
1385         free(misc_stat_entry);
1386 done:
1387         return (head);
1388 }
1389 
1390 static dladm_stat_chain_t *
1391 i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
1392 {
1393         misc_stat_entry_t       *misc_stat_entry;
1394         dladm_stat_chain_t      *head = NULL;
1395         tx_lane_stat_entry_t    *tx_lane_stat_entry;
1396 
1397         misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1398         if (misc_stat_entry == NULL)
1399                 goto done;
1400 
1401         tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1402         if (tx_lane_stat_entry == NULL)
1403                 goto done;
1404 
1405         tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1406         tx_lane_stat_entry->tle_id = L_DFNCT;
1407 
1408         tx_lane_stat_entry->tle_stats.tl_opackets =
1409             misc_stat_entry->mse_stats.ms_opackets;
1410         tx_lane_stat_entry->tle_stats.tl_obytes =
1411             misc_stat_entry->mse_stats.ms_obytes;
1412         tx_lane_stat_entry->tle_stats.tl_sdrops =
1413             misc_stat_entry->mse_stats.ms_txsdrops;
1414 
1415         head = malloc(sizeof (dladm_stat_chain_t));
1416         if (head == NULL) {
1417                 free(tx_lane_stat_entry);
1418                 goto done;
1419         }
1420 
1421         head->dc_statentry = tx_lane_stat_entry;
1422         head->dc_next = NULL;
1423 
1424 done:
1425         return (head);
1426 }
1427 
1428 static dladm_stat_chain_t *
1429 i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1430 {
1431         uint_t  tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1432         uint_t  tx_hwlane_idlist_size;
1433 
1434         i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST,
1435             tx_hwlane_idlist, &tx_hwlane_idlist_size);
1436 
1437         return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE,
1438             tx_hwlane_idlist, tx_hwlane_idlist_size,
1439             i_dlstat_tx_hwlane_retrieve_stat));
1440 }
1441 
1442 /*ARGSUSED*/
1443 static dladm_stat_chain_t *
1444 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1445     const char *linkname)
1446 {
1447         return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE,
1448             default_idlist, default_idlist_size,
1449             i_dlstat_tx_swlane_retrieve_stat));
1450 }
1451 
1452 void *
1453 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1454 {
1455         dladm_stat_chain_t      *head = NULL;
1456         dladm_stat_chain_t      *bcast_stats = NULL;
1457         dladm_stat_chain_t      *defunctlane_stats = NULL;
1458         dladm_stat_chain_t      *lane_stats;
1459         char                    linkname[MAXLINKNAMELEN];
1460         boolean_t               is_legacy_driver;
1461 
1462         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1463             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1464                 goto done;
1465         }
1466 
1467         /* Check if it is legacy driver */
1468         if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1469             "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1470                 goto done;
1471         }
1472 
1473         if (is_legacy_driver) {
1474                 head = i_dlstat_legacy_tx_lane_stats(dh, linkname);
1475                 goto done;
1476         }
1477 
1478         bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname);
1479         defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname);
1480         lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname);
1481         if (lane_stats == NULL)
1482                 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1483 
1484         head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1485         head = i_dlstat_join_lists(head, lane_stats);
1486 
1487 done:
1488         return (head);
1489 }
1490 
1491 /* Rx lane total statistic specific functions */
1492 void *
1493 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1494 {
1495         dladm_stat_chain_t      *total_head = NULL;
1496         dladm_stat_chain_t      *rx_lane_head, *curr;
1497         rx_lane_stat_entry_t    *total_stats;
1498 
1499         /* Get per rx lane stats */
1500         rx_lane_head = dlstat_rx_lane_stats(dh, linkid);


1633 }
1634 
1635 static void *
1636 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
1637     uint_t idlist[], uint_t idlist_size,
1638     const char *modname, const char *prefix)
1639 {
1640         int                     i;
1641         char                    statprefix[MAXLINKNAMELEN];
1642         char                    linkname[MAXLINKNAMELEN];
1643         dladm_stat_chain_t      *curr, *curr_head;
1644         dladm_stat_chain_t      *head = NULL, *prev = NULL;
1645         uint_t                  fanout_idlist[MAX_RINGS_PER_GROUP];
1646         uint_t                  fanout_idlist_size;
1647 
1648         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1649             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1650                 return (NULL);
1651         }
1652 
1653         i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST,
1654             fanout_idlist, &fanout_idlist_size);
1655 
1656         for (i = 0; i < idlist_size; i++) {
1657                 uint_t  index = idlist[i];
1658 
1659                 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
1660                     prefix, index);
1661 
1662                 curr_head = i_dlstat_query_stats(dh, modname, statprefix,
1663                     fanout_idlist, fanout_idlist_size,
1664                     i_dlstat_fanout_retrieve_stat);
1665 
1666                 if (curr_head == NULL)  /* Last lane */
1667                         break;
1668 
1669                 if (head == NULL)       /* First lane */
1670                         head = curr_head;
1671                 else    /* Link new lane list to end of previous lane list */
1672                         prev->dc_next = curr_head;
1673 
1674                 /* Walk new lane list and set ids */
1675                 for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
1676                         fanout_stat_entry_t *curr_stats = curr->dc_statentry;
1677 
1678                         curr_stats->fe_index = index;
1679                         curr_stats->fe_id = L_HWLANE;
1680                         /*
1681                          * Save last pointer of previous linked list.
1682                          * This pointer is used to chain linked lists


1688 
1689         return (head);
1690 }
1691 
1692 void *
1693 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
1694     const char *linkname)
1695 {
1696         return (i_dlstat_query_fanout_stats(dh, linkid,
1697             default_idlist, default_idlist_size, linkname,
1698             DLSTAT_MAC_RX_SWLANE));
1699 }
1700 
1701 void *
1702 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1703     const char *linkname)
1704 {
1705         uint_t  rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1706         uint_t  rx_hwlane_idlist_size;
1707 
1708         i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST,
1709             rx_hwlane_idlist, &rx_hwlane_idlist_size);
1710 
1711         return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
1712             rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
1713 }
1714 
1715 void *
1716 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
1717 {
1718         dladm_stat_chain_t      *head = NULL;
1719         dladm_stat_chain_t      *fout_hwlane_stats;
1720         dladm_stat_chain_t      *fout_swlane_and_local_stats;
1721         fanout_stat_entry_t     *fout_stats;
1722         char                    linkname[MAXLINKNAMELEN];
1723 
1724         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1725             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1726                 goto done;
1727         }
1728 


1814          * kstats corresponding to physical device rings continue to use
1815          * device names even if the link is renamed using dladm rename-link.
1816          * Thus, given a linkid, we lookup the physical device name.
1817          * However, if an aggr is renamed, kstats corresponding to its
1818          * pseudo rings are renamed as well.
1819          */
1820         if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1821             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1822                 return (NULL);
1823         }
1824 
1825         if (class != DATALINK_CLASS_AGGR) {
1826                 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1827                     DLADM_STATUS_OK) {
1828                         return (NULL);
1829                 }
1830                 modname = dpa.dp_dev;
1831         } else
1832                 modname = linkname;
1833 
1834         i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST,
1835             rx_ring_idlist, &rx_ring_idlist_size);
1836 
1837         return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING,
1838             rx_ring_idlist, rx_ring_idlist_size,
1839             i_dlstat_rx_ring_retrieve_stat));
1840 }
1841 
1842 /* Tx ring statistic specific functions */
1843 static boolean_t
1844 i_dlstat_tx_ring_match(void *arg1, void *arg2)
1845 {
1846         tx_lane_stat_entry_t    *s1 = arg1;
1847         tx_lane_stat_entry_t    *s2 = arg2;
1848 
1849         return (s1->tle_index == s2->tle_index);
1850 }
1851 
1852 static void *
1853 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
1854 {
1855         ring_stat_entry_t       *s1 = arg1;
1856         ring_stat_entry_t       *s2 = arg2;
1857         ring_stat_entry_t       *diff_entry;


1901          * kstats corresponding to physical device rings continue to use
1902          * device names even if the link is renamed using dladm rename-link.
1903          * Thus, given a linkid, we lookup the physical device name.
1904          * However, if an aggr is renamed, kstats corresponding to its
1905          * pseudo rings are renamed as well.
1906          */
1907         if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1908             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1909                 return (NULL);
1910         }
1911 
1912         if (class != DATALINK_CLASS_AGGR) {
1913                 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1914                     DLADM_STATUS_OK) {
1915                         return (NULL);
1916                 }
1917                 modname = dpa.dp_dev;
1918         } else
1919                 modname = linkname;
1920 
1921         i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST,
1922             tx_ring_idlist, &tx_ring_idlist_size);
1923 
1924         return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING,
1925             tx_ring_idlist, tx_ring_idlist_size,
1926             i_dlstat_tx_ring_retrieve_stat));
1927 }
1928 
1929 /* Rx ring total statistic specific functions */
1930 void *
1931 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1932 {
1933         dladm_stat_chain_t      *total_head = NULL;
1934         dladm_stat_chain_t      *rx_ring_head, *curr;
1935         ring_stat_entry_t       *total_stats;
1936 
1937         /* Get per rx ring stats */
1938         rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
1939         if (rx_ring_head == NULL)
1940                 goto done;
1941 
1942         total_stats = calloc(1, sizeof (ring_stat_entry_t));
1943         if (total_stats == NULL)
1944                 goto done;


2151         aggr_port_stat_entry_t  *diff_entry;
2152 
2153         diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2154         if (diff_entry == NULL)
2155                 goto done;
2156 
2157         diff_entry->ape_portlinkid = s1->ape_portlinkid;
2158 
2159         DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2160             AGGR_PORT_STAT_SIZE);
2161 
2162 done:
2163         return (diff_entry);
2164 }
2165 
2166 /*
2167  * Query dls stats for the aggr port. This results in query for stats into
2168  * the corresponding device driver.
2169  */
2170 static aggr_port_stat_entry_t *
2171 i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname,
2172     datalink_id_t linkid)
2173 {

2174         kstat_t                 *ksp;
2175         char                    module[DLPI_LINKNAME_MAX];
2176         uint_t                  instance;
2177         aggr_port_stat_entry_t  *aggr_port_stat_entry = NULL;
2178 
2179         if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2180                 goto done;
2181 
2182         if (dladm_dld_kcp(handle) == NULL) {
2183                 warn("kstat open operation failed");
2184                 return (NULL);
2185         }
2186 
2187         ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance,
2188         "mac", NULL);
2189         if (ksp == NULL)
2190                 goto done;
2191 
2192         aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2193         if (aggr_port_stat_entry == NULL)
2194                 goto done;
2195 
2196         /* Save port's linkid */
2197         aggr_port_stat_entry->ape_portlinkid = linkid;
2198 
2199         i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
2200             &aggr_port_stat_entry->ape_stats,
2201             aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2202 done:

2203         return (aggr_port_stat_entry);
2204 }
2205 
2206 void *
2207 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2208 {
2209         dladm_aggr_grp_attr_t   ginfo;
2210         int                     i;
2211         dladm_aggr_port_attr_t   *portp;
2212         dladm_phys_attr_t       dpa;
2213         aggr_port_stat_entry_t  *aggr_port_stat_entry;
2214         dladm_stat_chain_t      *head = NULL, *prev = NULL, *curr;
2215         dladm_stat_chain_t      *total_stats;
2216 
2217         /* Get aggr info */
2218         bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2219         if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2220             != DLADM_STATUS_OK)
2221                 goto done;
2222         /* For every port that is member of this aggr do */
2223         for (i = 0; i < ginfo.lg_nports; i++) {
2224                 portp = &(ginfo.lg_ports[i]);
2225                 if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2226                     DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2227                         goto done;
2228                 }
2229 
2230                 aggr_port_stat_entry = i_dlstat_single_port_stats(dh,
2231                     dpa.dp_dev, portp->lp_linkid);
2232 
2233                 /* Create dladm_stat_chain_t object for this stat */
2234                 curr = malloc(sizeof (dladm_stat_chain_t));
2235                 if (curr == NULL) {
2236                         free(aggr_port_stat_entry);
2237                         goto done;
2238                 }
2239                 (void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2240                     sizeof (curr->dc_statheader));
2241                 curr->dc_statentry = aggr_port_stat_entry;
2242                 curr->dc_next = NULL;
2243 
2244                 /* Chain this aggr port stat entry */
2245                 /* head of the stat list */
2246                 if (prev == NULL)
2247                         head = curr;
2248                 else
2249                         prev->dc_next = curr;
2250                 prev = curr;
2251         }


2261         }
2262 
2263 done:
2264         free(ginfo.lg_ports);
2265         return (head);
2266 }
2267 
2268 /* Misc stat specific functions */
2269 void *
2270 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2271 {
2272         misc_stat_entry_t       *misc_stat_entry;
2273         dladm_stat_chain_t      *head = NULL;
2274         char                    linkname[MAXLINKNAMELEN];
2275 
2276         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2277             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2278                 goto done;
2279         }
2280 
2281         misc_stat_entry = i_dlstat_misc_stats(dh, linkname);
2282         if (misc_stat_entry == NULL)
2283                 goto done;
2284 
2285         head = malloc(sizeof (dladm_stat_chain_t));
2286         if (head == NULL) {
2287                 free(misc_stat_entry);
2288                 goto done;
2289         }
2290 
2291         head->dc_statentry = misc_stat_entry;
2292         (void) strlcpy(head->dc_statheader, "mac_misc_stat",
2293             sizeof (head->dc_statheader));
2294         head->dc_next = NULL;
2295 
2296 done:
2297         return (head);
2298 }
2299 
2300 /* Exported functions */
2301 dladm_stat_chain_t *


2495         while (curr != NULL) {
2496                 dladm_stat_chain_t      *tofree = curr;
2497                 name_value_stat_entry_t *nv_entry = curr->dc_statentry;
2498                 name_value_stat_t       *nv_curr = nv_entry->nve_stats;
2499 
2500                 while (nv_curr != NULL) {
2501                         name_value_stat_t       *nv_tofree = nv_curr;
2502 
2503                         nv_curr = nv_curr->nv_nextstat;
2504                         free(nv_tofree);
2505                 }
2506 
2507                 curr = curr->dc_next;
2508                 free(nv_entry);
2509                 free(tofree);
2510         }
2511 }
2512 
2513 /* flow stats specific routines */
2514 flow_stat_t *
2515 dladm_flow_stat_query(dladm_handle_t handle, const char *flowname)
2516 {

2517         kstat_t         *ksp;
2518         flow_stat_t     *flow_stat = NULL;
2519 
2520         if (dladm_dld_kcp(handle) == NULL)
2521                 return (NULL);
2522 
2523         flow_stat = calloc(1, sizeof (flow_stat_t));
2524         if (flow_stat == NULL)
2525                 goto done;
2526 
2527         ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname,
2528         "flow");
2529 
2530         if (ksp != NULL) {
2531                 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat,
2532                     flow_stats_list, FLOW_STAT_SIZE);
2533         }
2534 
2535 done:

2536         return (flow_stat);
2537 }
2538 
2539 flow_stat_t *
2540 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
2541 {
2542         flow_stat_t     *diff_stat;
2543 
2544         diff_stat = calloc(1, sizeof (flow_stat_t));
2545         if (diff_stat == NULL)
2546                 goto done;
2547 
2548         if (op2 == NULL) {
2549                 bcopy(op1, diff_stat, sizeof (flow_stat_t));
2550         } else {
2551                 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
2552                     FLOW_STAT_SIZE);
2553         }
2554 done:
2555         return (diff_stat);
2556 }
2557 
2558 void
2559 dladm_flow_stat_free(flow_stat_t *curr)
2560 {
2561         free(curr);
2562 }
2563 
2564 /* Query all flow stats */
2565 name_value_stat_entry_t *
2566 dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname)
2567 {
2568         flow_stat_t             *flow_stat;
2569         name_value_stat_entry_t *name_value_stat_entry = NULL;
2570 
2571         /* Query flow stats */
2572         flow_stat =  dladm_flow_stat_query(handle, flowname);
2573         if (flow_stat == NULL)
2574                 goto done;
2575 
2576         /* Allocate memory for query all stat entry */
2577         name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2578         if (name_value_stat_entry == NULL) {
2579                 dladm_flow_stat_free(flow_stat);
2580                 goto done;
2581         }
2582 
2583         /* Header for these stat fields */
2584         (void) strncpy(name_value_stat_entry->nve_header, flowname,
2585             MAXFLOWNAMELEN);
2586 
2587         /* Convert every statfield in flow_stat to <statname, statval> pair */
2588         name_value_stat_entry->nve_stats =
2589             i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
2590 
2591         /* Free flow_stat */
2592         dladm_flow_stat_free(flow_stat);