1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Data-Link Services Module 30 */ 31 32 #include <sys/types.h> 33 #include <sys/sysmacros.h> 34 #include <sys/atomic.h> 35 #include <sys/kstat.h> 36 #include <sys/vlan.h> 37 #include <sys/mac.h> 38 #include <sys/mac_ether.h> 39 #include <sys/ctype.h> 40 #include <sys/dls.h> 41 #include <sys/dls_impl.h> 42 43 static mac_stat_info_t i_dls_si[] = { 44 { MAC_STAT_IFSPEED, "ifspeed", KSTAT_DATA_UINT64, 0 }, 45 { MAC_STAT_MULTIRCV, "multircv", KSTAT_DATA_UINT32, 0 }, 46 { MAC_STAT_BRDCSTRCV, "brdcstrcv", KSTAT_DATA_UINT32, 0 }, 47 { MAC_STAT_MULTIXMT, "multixmt", KSTAT_DATA_UINT32, 0 }, 48 { MAC_STAT_BRDCSTXMT, "brdcstxmt", KSTAT_DATA_UINT32, 0 }, 49 { MAC_STAT_NORCVBUF, "norcvbuf", KSTAT_DATA_UINT32, 0 }, 50 { MAC_STAT_IERRORS, "ierrors", KSTAT_DATA_UINT32, 0 }, 51 { MAC_STAT_NOXMTBUF, "noxmtbuf", KSTAT_DATA_UINT32, 0 }, 52 { MAC_STAT_OERRORS, "oerrors", KSTAT_DATA_UINT32, 0 }, 53 { MAC_STAT_COLLISIONS, "collisions", KSTAT_DATA_UINT32, 0 }, 54 { MAC_STAT_RBYTES, "rbytes", KSTAT_DATA_UINT32, 0 }, 55 { MAC_STAT_IPACKETS, "ipackets", KSTAT_DATA_UINT32, 0 }, 56 { MAC_STAT_OBYTES, "obytes", KSTAT_DATA_UINT32, 0 }, 57 { MAC_STAT_OPACKETS, "opackets", KSTAT_DATA_UINT32, 0 }, 58 { MAC_STAT_RBYTES, "rbytes64", KSTAT_DATA_UINT64, 0 }, 59 { MAC_STAT_IPACKETS, "ipackets64", KSTAT_DATA_UINT64, 0 }, 60 { MAC_STAT_OBYTES, "obytes64", KSTAT_DATA_UINT64, 0 }, 61 { MAC_STAT_OPACKETS, "opackets64", KSTAT_DATA_UINT64, 0 }, 62 { MAC_STAT_LINK_STATE, "link_state", KSTAT_DATA_UINT32, 63 (uint64_t)LINK_STATE_UNKNOWN} 64 }; 65 66 #define STAT_INFO_COUNT (sizeof (i_dls_si) / sizeof (i_dls_si[0])) 67 68 /* 69 * Private functions. 70 */ 71 72 static int 73 i_dls_mac_stat_update(kstat_t *ksp, int rw) 74 { 75 dls_vlan_t *dvp = ksp->ks_private; 76 77 return (dls_stat_update(ksp, dvp, rw)); 78 } 79 80 /* 81 * Exported functions. 82 */ 83 int 84 dls_stat_update(kstat_t *ksp, dls_vlan_t *dvp, int rw) 85 { 86 dls_link_t *dlp = dvp->dv_dlp; 87 kstat_named_t *knp; 88 uint_t i; 89 uint64_t val; 90 int err; 91 92 if (rw != KSTAT_READ) 93 return (EACCES); 94 95 if ((err = dls_mac_hold(dlp)) != 0) 96 return (err); 97 98 knp = (kstat_named_t *)ksp->ks_data; 99 for (i = 0; i < STAT_INFO_COUNT; i++) { 100 val = mac_stat_get(dlp->dl_mh, i_dls_si[i].msi_stat); 101 102 switch (i_dls_si[i].msi_type) { 103 case KSTAT_DATA_UINT64: 104 knp->value.ui64 = val; 105 break; 106 case KSTAT_DATA_UINT32: 107 knp->value.ui32 = (uint32_t)val; 108 break; 109 default: 110 ASSERT(B_FALSE); 111 } 112 113 knp++; 114 } 115 116 /* 117 * Ethernet specific kstat "link_duplex" 118 */ 119 if (dlp->dl_mip->mi_nativemedia != DL_ETHER) { 120 knp->value.ui32 = LINK_DUPLEX_UNKNOWN; 121 } else { 122 val = mac_stat_get(dlp->dl_mh, ETHER_STAT_LINK_DUPLEX); 123 knp->value.ui32 = (uint32_t)val; 124 } 125 knp++; 126 knp->value.ui32 = dlp->dl_unknowns; 127 dls_mac_rele(dlp); 128 129 return (0); 130 } 131 132 int 133 dls_stat_create(const char *module, int instance, const char *name, 134 int (*update)(struct kstat *, int), void *private, kstat_t **kspp) 135 { 136 kstat_t *ksp; 137 kstat_named_t *knp; 138 uint_t i; 139 140 if ((ksp = kstat_create(module, instance, name, "net", 141 KSTAT_TYPE_NAMED, STAT_INFO_COUNT + 2, 0)) == NULL) { 142 return (EINVAL); 143 } 144 145 ksp->ks_update = update; 146 ksp->ks_private = private; 147 148 knp = (kstat_named_t *)ksp->ks_data; 149 for (i = 0; i < STAT_INFO_COUNT; i++) { 150 kstat_named_init(knp, i_dls_si[i].msi_name, 151 i_dls_si[i].msi_type); 152 knp++; 153 } 154 155 kstat_named_init(knp++, "link_duplex", KSTAT_DATA_UINT32); 156 kstat_named_init(knp, "unknowns", KSTAT_DATA_UINT32); 157 kstat_install(ksp); 158 *kspp = ksp; 159 return (0); 160 } 161 162 void 163 dls_mac_stat_create(dls_vlan_t *dvp) 164 { 165 kstat_t *ksp = NULL; 166 major_t major; 167 168 /* 169 * Create the legacy kstats to provide backward compatibility. 170 * These kstats need to be created even when this link does not 171 * have a link name, i.e., when the VLAN is accessed using its 172 * /dev node. 173 * 174 * Note that we only need to create the legacy kstats for GLDv3 175 * physical links, aggregation links which are created using 176 * the 'key' option, and any VLAN links created over them. 177 * This can be determined by checking its dv_ppa. 178 */ 179 ASSERT(dvp->dv_ksp == NULL); 180 if (dvp->dv_ppa >= MAC_MAX_MINOR) 181 return; 182 183 major = getmajor(dvp->dv_dev); 184 ASSERT(GLDV3_DRV(major) && (dvp->dv_ksp == NULL)); 185 186 if (dls_stat_create(ddi_major_to_name(major), 187 dvp->dv_id * 1000 + dvp->dv_ppa, NULL, 188 i_dls_mac_stat_update, dvp, &ksp) != 0) { 189 return; 190 } 191 ASSERT(ksp != NULL); 192 dvp->dv_ksp = ksp; 193 } 194 195 void 196 dls_mac_stat_destroy(dls_vlan_t *dvp) 197 { 198 if (dvp->dv_ksp != NULL) { 199 kstat_delete(dvp->dv_ksp); 200 dvp->dv_ksp = NULL; 201 } 202 } 203