1 /*- 2 * Copyright (c) 2009 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 /* 31 * npe statistics class. 32 */ 33 #include <sys/param.h> 34 #include <sys/sysctl.h> 35 36 #include <err.h> 37 #include <signal.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "npestats.h" 44 45 #define AFTER(prev) ((prev)+1) 46 47 static const struct fmt npestats[] = { 48 #define S_ALIGN 0 49 { 7, "align", "align", "alignment errors" }, 50 #define S_FCS AFTER(S_ALIGN) 51 { 7, "fcs", "fcs", "FCS errors" }, 52 #define S_MACRX AFTER(S_FCS) 53 { 7, "macrx", "macrx", "internal MAC rx errors" }, 54 #define S_RXORN AFTER(S_MACRX) 55 { 6, "overrun", "overrun", "rx overrun discards" }, 56 #define S_LEARN AFTER(S_RXORN) 57 { 5, "learn", "learn", "rx learned entry discards" }, 58 #define S_LARGE AFTER(S_LEARN) 59 { 5, "large", "large", "rx large frame discards" }, 60 #define S_STP AFTER(S_LARGE) 61 { 5, "stp", "stp", "rx STP blocked discards" }, 62 #define S_RX_VLAN_TYPE AFTER(S_STP) 63 { 5, "rx_vlan_type", "rx_vlant", "rx VLAN type filter discards" }, 64 #define S_RX_VLAN_ID AFTER(S_RX_VLAN_TYPE) 65 { 5, "rx_vlan_id", "rx_vlani", "rx VLAN Id filter discards" }, 66 #define S_BADSRC AFTER(S_RX_VLAN_ID) 67 { 5, "badsrc", "badsrc", "rx invalid source discards" }, 68 #define S_BLACKLIST AFTER(S_BADSRC) 69 { 5, "blacklist", "blacklist", "rx black list discards" }, 70 #define S_WHITELIST AFTER(S_BLACKLIST) 71 { 5, "whitelist", "whitelist", "rx white list discards" }, 72 #define S_UNDERFLOW AFTER(S_WHITELIST) 73 { 5, "underflow", "underflow", "rx underflow entry discards" }, 74 #define S_COLL_SINGLE AFTER(S_UNDERFLOW) 75 { 5, "collision1", "collision1", "single collision frames" }, 76 #define S_COLL_MULTI AFTER(S_COLL_SINGLE) 77 { 5, "collisionM", "collisionM", "multiple collision frames" }, 78 #define S_DEFERRED AFTER(S_COLL_MULTI) 79 { 5, "deferred", "deferred", "deferred transmissions" }, 80 #define S_LATE AFTER(S_DEFERRED) 81 { 5, "late", "late", "late collisions" }, 82 #define S_EXCESSIVE AFTER(S_LATE) 83 { 5, "excessive", "excessive", "excessive collisions" }, 84 #define S_MACTX AFTER(S_EXCESSIVE) 85 { 7, "mactx", "mactx", "internal MAC tx errors" }, 86 #define S_CARRIER AFTER(S_MACTX) 87 { 7, "carrier", "carrier", "carrier sense errors" }, 88 #define S_TOOBIG AFTER(S_CARRIER) 89 { 7, "toobig", "toobig", "tx large frame discards" }, 90 #define S_TX_VLAN_ID AFTER(S_TOOBIG) 91 { 7, "tx_vlan_id", "tx_vlani", "tx VLAN Id filter discards" }, 92 }; 93 #define S_LAST S_TX_VLAN_ID 94 95 /* 96 * Stat block returned by NPE with NPE_GETSTATS msg. 97 */ 98 struct npestats { 99 uint32_t dot3StatsAlignmentErrors; 100 uint32_t dot3StatsFCSErrors; 101 uint32_t dot3StatsInternalMacReceiveErrors; 102 uint32_t RxOverrunDiscards; 103 uint32_t RxLearnedEntryDiscards; 104 uint32_t RxLargeFramesDiscards; 105 uint32_t RxSTPBlockedDiscards; 106 uint32_t RxVLANTypeFilterDiscards; 107 uint32_t RxVLANIdFilterDiscards; 108 uint32_t RxInvalidSourceDiscards; 109 uint32_t RxBlackListDiscards; 110 uint32_t RxWhiteListDiscards; 111 uint32_t RxUnderflowEntryDiscards; 112 uint32_t dot3StatsSingleCollisionFrames; 113 uint32_t dot3StatsMultipleCollisionFrames; 114 uint32_t dot3StatsDeferredTransmissions; 115 uint32_t dot3StatsLateCollisions; 116 uint32_t dot3StatsExcessiveCollisions; 117 uint32_t dot3StatsInternalMacTransmitErrors; 118 uint32_t dot3StatsCarrierSenseErrors; 119 uint32_t TxLargeFrameDiscards; 120 uint32_t TxVLANIdFilterDiscards; 121 }; 122 123 struct npestatfoo_p { 124 struct npestatfoo base; 125 char oid[80]; 126 int mib[4]; 127 struct npestats cur; 128 struct npestats total; 129 }; 130 131 static void 132 npe_setifname(struct npestatfoo *wf0, const char *ifname) 133 { 134 struct npestatfoo_p *wf = (struct npestatfoo_p *) wf0; 135 size_t len; 136 137 snprintf(wf->oid, sizeof(wf->oid), "dev.npe.%s.stats", ifname+3); 138 len = 4; 139 if (sysctlnametomib(wf->oid, wf->mib, &len) < 0) 140 err(1, "sysctlnametomib: %s", wf->oid); 141 } 142 143 static void 144 npe_collect(struct npestatfoo_p *wf, struct npestats *stats) 145 { 146 size_t len = sizeof(struct npestats); 147 if (sysctl(wf->mib, 4, stats, &len, NULL, 0) < 0) 148 err(1, "sysctl: %s", wf->oid); 149 } 150 151 static void 152 npe_collect_cur(struct bsdstat *sf) 153 { 154 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 155 156 npe_collect(wf, &wf->cur); 157 } 158 159 static void 160 npe_collect_tot(struct bsdstat *sf) 161 { 162 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 163 164 npe_collect(wf, &wf->total); 165 } 166 167 static void 168 npe_update_tot(struct bsdstat *sf) 169 { 170 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 171 172 wf->total = wf->cur; 173 } 174 175 static int 176 npe_get_curstat(struct bsdstat *sf, int s, char b[], size_t bs) 177 { 178 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 179 #define STAT(x) \ 180 snprintf(b, bs, "%u", wf->cur.x - wf->total.x); return 1 181 182 switch (s) { 183 case S_ALIGN: STAT(dot3StatsAlignmentErrors); 184 case S_FCS: STAT(dot3StatsFCSErrors); 185 case S_MACRX: STAT(dot3StatsInternalMacReceiveErrors); 186 case S_RXORN: STAT(RxOverrunDiscards); 187 case S_LEARN: STAT(RxLearnedEntryDiscards); 188 case S_LARGE: STAT(RxLargeFramesDiscards); 189 case S_STP: STAT(RxSTPBlockedDiscards); 190 case S_RX_VLAN_TYPE: STAT(RxVLANTypeFilterDiscards); 191 case S_RX_VLAN_ID: STAT(RxVLANIdFilterDiscards); 192 case S_BADSRC: STAT(RxInvalidSourceDiscards); 193 case S_BLACKLIST: STAT(RxBlackListDiscards); 194 case S_WHITELIST: STAT(RxWhiteListDiscards); 195 case S_UNDERFLOW: STAT(RxUnderflowEntryDiscards); 196 case S_COLL_SINGLE: STAT(dot3StatsSingleCollisionFrames); 197 case S_COLL_MULTI: STAT(dot3StatsMultipleCollisionFrames); 198 case S_DEFERRED: STAT(dot3StatsDeferredTransmissions); 199 case S_LATE: STAT(dot3StatsLateCollisions); 200 case S_EXCESSIVE: STAT(dot3StatsExcessiveCollisions); 201 case S_MACTX: STAT(dot3StatsInternalMacTransmitErrors); 202 case S_CARRIER: STAT(dot3StatsCarrierSenseErrors); 203 case S_TOOBIG: STAT(TxLargeFrameDiscards); 204 case S_TX_VLAN_ID: STAT(TxVLANIdFilterDiscards); 205 } 206 b[0] = '\0'; 207 return 0; 208 #undef STAT 209 } 210 211 static int 212 npe_get_totstat(struct bsdstat *sf, int s, char b[], size_t bs) 213 { 214 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 215 #define STAT(x) \ 216 snprintf(b, bs, "%u", wf->total.x); return 1 217 218 switch (s) { 219 case S_ALIGN: STAT(dot3StatsAlignmentErrors); 220 case S_FCS: STAT(dot3StatsFCSErrors); 221 case S_MACRX: STAT(dot3StatsInternalMacReceiveErrors); 222 case S_RXORN: STAT(RxOverrunDiscards); 223 case S_LEARN: STAT(RxLearnedEntryDiscards); 224 case S_LARGE: STAT(RxLargeFramesDiscards); 225 case S_STP: STAT(RxSTPBlockedDiscards); 226 case S_RX_VLAN_TYPE: STAT(RxVLANTypeFilterDiscards); 227 case S_RX_VLAN_ID: STAT(RxVLANIdFilterDiscards); 228 case S_BADSRC: STAT(RxInvalidSourceDiscards); 229 case S_BLACKLIST: STAT(RxBlackListDiscards); 230 case S_WHITELIST: STAT(RxWhiteListDiscards); 231 case S_UNDERFLOW: STAT(RxUnderflowEntryDiscards); 232 case S_COLL_SINGLE: STAT(dot3StatsSingleCollisionFrames); 233 case S_COLL_MULTI: STAT(dot3StatsMultipleCollisionFrames); 234 case S_DEFERRED: STAT(dot3StatsDeferredTransmissions); 235 case S_LATE: STAT(dot3StatsLateCollisions); 236 case S_EXCESSIVE: STAT(dot3StatsExcessiveCollisions); 237 case S_MACTX: STAT(dot3StatsInternalMacTransmitErrors); 238 case S_CARRIER: STAT(dot3StatsCarrierSenseErrors); 239 case S_TOOBIG: STAT(TxLargeFrameDiscards); 240 case S_TX_VLAN_ID: STAT(TxVLANIdFilterDiscards); 241 } 242 b[0] = '\0'; 243 return 0; 244 #undef STAT 245 } 246 247 BSDSTAT_DEFINE_BOUNCE(npestatfoo) 248 249 struct npestatfoo * 250 npestats_new(const char *ifname, const char *fmtstring) 251 { 252 struct npestatfoo_p *wf; 253 254 wf = calloc(1, sizeof(struct npestatfoo_p)); 255 if (wf != NULL) { 256 bsdstat_init(&wf->base.base, "npestats", npestats, 257 nitems(npestats)); 258 /* override base methods */ 259 wf->base.base.collect_cur = npe_collect_cur; 260 wf->base.base.collect_tot = npe_collect_tot; 261 wf->base.base.get_curstat = npe_get_curstat; 262 wf->base.base.get_totstat = npe_get_totstat; 263 wf->base.base.update_tot = npe_update_tot; 264 265 /* setup bounce functions for public methods */ 266 BSDSTAT_BOUNCE(wf, npestatfoo); 267 268 /* setup our public methods */ 269 wf->base.setifname = npe_setifname; 270 271 npe_setifname(&wf->base, ifname); 272 wf->base.setfmt(&wf->base, fmtstring); 273 } 274 return &wf->base; 275 } 276