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);
|