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 * $FreeBSD$ 30 */ 31 32 /* 33 * npe statistics class. 34 */ 35 #include <sys/types.h> 36 #include <sys/sysctl.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <signal.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <err.h> 44 45 #include "npestats.h" 46 47 #define AFTER(prev) ((prev)+1) 48 49 static const struct fmt npestats[] = { 50 #define S_ALIGN 0 51 { 7, "align", "align", "alignment errors" }, 52 #define S_FCS AFTER(S_ALIGN) 53 { 7, "fcs", "fcs", "FCS errors" }, 54 #define S_MACRX AFTER(S_FCS) 55 { 7, "macrx", "macrx", "internal MAC rx errors" }, 56 #define S_RXORN AFTER(S_MACRX) 57 { 6, "overrun", "overrun", "rx overrun discards" }, 58 #define S_LEARN AFTER(S_RXORN) 59 { 5, "learn", "learn", "rx learned entry discards" }, 60 #define S_LARGE AFTER(S_LEARN) 61 { 5, "large", "large", "rx large frame discards" }, 62 #define S_STP AFTER(S_LARGE) 63 { 5, "stp", "stp", "rx STP blocked discards" }, 64 #define S_RX_VLAN_TYPE AFTER(S_STP) 65 { 5, "rx_vlan_type", "rx_vlant", "rx VLAN type filter discards" }, 66 #define S_RX_VLAN_ID AFTER(S_RX_VLAN_TYPE) 67 { 5, "rx_vlan_id", "rx_vlani", "rx VLAN Id filter discards" }, 68 #define S_BADSRC AFTER(S_RX_VLAN_ID) 69 { 5, "badsrc", "badsrc", "rx invalid source discards" }, 70 #define S_BLACKLIST AFTER(S_BADSRC) 71 { 5, "blacklist", "blacklist", "rx black list discards" }, 72 #define S_WHITELIST AFTER(S_BLACKLIST) 73 { 5, "whitelist", "whitelist", "rx white list discards" }, 74 #define S_UNDERFLOW AFTER(S_WHITELIST) 75 { 5, "underflow", "underflow", "rx underflow entry discards" }, 76 #define S_COLL_SINGLE AFTER(S_UNDERFLOW) 77 { 5, "collision1", "collision1", "single collision frames" }, 78 #define S_COLL_MULTI AFTER(S_COLL_SINGLE) 79 { 5, "collisionM", "collisionM", "multiple collision frames" }, 80 #define S_DEFERRED AFTER(S_COLL_MULTI) 81 { 5, "deferred", "deferred", "deferred transmissions" }, 82 #define S_LATE AFTER(S_DEFERRED) 83 { 5, "late", "late", "late collisions" }, 84 #define S_EXCESSIVE AFTER(S_LATE) 85 { 5, "excessive", "excessive", "excessive collisions" }, 86 #define S_MACTX AFTER(S_EXCESSIVE) 87 { 7, "mactx", "mactx", "internal MAC tx errors" }, 88 #define S_CARRIER AFTER(S_MACTX) 89 { 7, "carrier", "carrier", "carrier sense errors" }, 90 #define S_TOOBIG AFTER(S_CARRIER) 91 { 7, "toobig", "toobig", "tx large frame discards" }, 92 #define S_TX_VLAN_ID AFTER(S_TOOBIG) 93 { 7, "tx_vlan_id", "tx_vlani", "tx VLAN Id filter discards" }, 94 }; 95 #define S_LAST S_TX_VLAN_ID 96 97 /* 98 * Stat block returned by NPE with NPE_GETSTATS msg. 99 */ 100 struct npestats { 101 uint32_t dot3StatsAlignmentErrors; 102 uint32_t dot3StatsFCSErrors; 103 uint32_t dot3StatsInternalMacReceiveErrors; 104 uint32_t RxOverrunDiscards; 105 uint32_t RxLearnedEntryDiscards; 106 uint32_t RxLargeFramesDiscards; 107 uint32_t RxSTPBlockedDiscards; 108 uint32_t RxVLANTypeFilterDiscards; 109 uint32_t RxVLANIdFilterDiscards; 110 uint32_t RxInvalidSourceDiscards; 111 uint32_t RxBlackListDiscards; 112 uint32_t RxWhiteListDiscards; 113 uint32_t RxUnderflowEntryDiscards; 114 uint32_t dot3StatsSingleCollisionFrames; 115 uint32_t dot3StatsMultipleCollisionFrames; 116 uint32_t dot3StatsDeferredTransmissions; 117 uint32_t dot3StatsLateCollisions; 118 uint32_t dot3StatsExcessiveCollisions; 119 uint32_t dot3StatsInternalMacTransmitErrors; 120 uint32_t dot3StatsCarrierSenseErrors; 121 uint32_t TxLargeFrameDiscards; 122 uint32_t TxVLANIdFilterDiscards; 123 }; 124 125 struct npestatfoo_p { 126 struct npestatfoo base; 127 char oid[80]; 128 int mib[4]; 129 struct npestats cur; 130 struct npestats total; 131 }; 132 133 static void 134 npe_setifname(struct npestatfoo *wf0, const char *ifname) 135 { 136 struct npestatfoo_p *wf = (struct npestatfoo_p *) wf0; 137 size_t len; 138 139 snprintf(wf->oid, sizeof(wf->oid), "dev.npe.%s.stats", ifname+3); 140 len = 4; 141 if (sysctlnametomib(wf->oid, wf->mib, &len) < 0) 142 err(1, "sysctlnametomib: %s", wf->oid); 143 } 144 145 static void 146 npe_collect(struct npestatfoo_p *wf, struct npestats *stats) 147 { 148 size_t len = sizeof(struct npestats); 149 if (sysctl(wf->mib, 4, stats, &len, NULL, 0) < 0) 150 err(1, "sysctl: %s", wf->oid); 151 } 152 153 static void 154 npe_collect_cur(struct statfoo *sf) 155 { 156 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 157 158 npe_collect(wf, &wf->cur); 159 } 160 161 static void 162 npe_collect_tot(struct statfoo *sf) 163 { 164 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 165 166 npe_collect(wf, &wf->total); 167 } 168 169 static void 170 npe_update_tot(struct statfoo *sf) 171 { 172 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 173 174 wf->total = wf->cur; 175 } 176 177 static int 178 npe_get_curstat(struct statfoo *sf, int s, char b[], size_t bs) 179 { 180 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 181 #define STAT(x) \ 182 snprintf(b, bs, "%u", wf->cur.x - wf->total.x); return 1 183 184 switch (s) { 185 case S_ALIGN: STAT(dot3StatsAlignmentErrors); 186 case S_FCS: STAT(dot3StatsFCSErrors); 187 case S_MACRX: STAT(dot3StatsInternalMacReceiveErrors); 188 case S_RXORN: STAT(RxOverrunDiscards); 189 case S_LEARN: STAT(RxLearnedEntryDiscards); 190 case S_LARGE: STAT(RxLargeFramesDiscards); 191 case S_STP: STAT(RxSTPBlockedDiscards); 192 case S_RX_VLAN_TYPE: STAT(RxVLANTypeFilterDiscards); 193 case S_RX_VLAN_ID: STAT(RxVLANIdFilterDiscards); 194 case S_BADSRC: STAT(RxInvalidSourceDiscards); 195 case S_BLACKLIST: STAT(RxBlackListDiscards); 196 case S_WHITELIST: STAT(RxWhiteListDiscards); 197 case S_UNDERFLOW: STAT(RxUnderflowEntryDiscards); 198 case S_COLL_SINGLE: STAT(dot3StatsSingleCollisionFrames); 199 case S_COLL_MULTI: STAT(dot3StatsMultipleCollisionFrames); 200 case S_DEFERRED: STAT(dot3StatsDeferredTransmissions); 201 case S_LATE: STAT(dot3StatsLateCollisions); 202 case S_EXCESSIVE: STAT(dot3StatsExcessiveCollisions); 203 case S_MACTX: STAT(dot3StatsInternalMacTransmitErrors); 204 case S_CARRIER: STAT(dot3StatsCarrierSenseErrors); 205 case S_TOOBIG: STAT(TxLargeFrameDiscards); 206 case S_TX_VLAN_ID: STAT(TxVLANIdFilterDiscards); 207 } 208 b[0] = '\0'; 209 return 0; 210 #undef STAT 211 } 212 213 static int 214 npe_get_totstat(struct statfoo *sf, int s, char b[], size_t bs) 215 { 216 struct npestatfoo_p *wf = (struct npestatfoo_p *) sf; 217 #define STAT(x) \ 218 snprintf(b, bs, "%u", wf->total.x); return 1 219 220 switch (s) { 221 case S_ALIGN: STAT(dot3StatsAlignmentErrors); 222 case S_FCS: STAT(dot3StatsFCSErrors); 223 case S_MACRX: STAT(dot3StatsInternalMacReceiveErrors); 224 case S_RXORN: STAT(RxOverrunDiscards); 225 case S_LEARN: STAT(RxLearnedEntryDiscards); 226 case S_LARGE: STAT(RxLargeFramesDiscards); 227 case S_STP: STAT(RxSTPBlockedDiscards); 228 case S_RX_VLAN_TYPE: STAT(RxVLANTypeFilterDiscards); 229 case S_RX_VLAN_ID: STAT(RxVLANIdFilterDiscards); 230 case S_BADSRC: STAT(RxInvalidSourceDiscards); 231 case S_BLACKLIST: STAT(RxBlackListDiscards); 232 case S_WHITELIST: STAT(RxWhiteListDiscards); 233 case S_UNDERFLOW: STAT(RxUnderflowEntryDiscards); 234 case S_COLL_SINGLE: STAT(dot3StatsSingleCollisionFrames); 235 case S_COLL_MULTI: STAT(dot3StatsMultipleCollisionFrames); 236 case S_DEFERRED: STAT(dot3StatsDeferredTransmissions); 237 case S_LATE: STAT(dot3StatsLateCollisions); 238 case S_EXCESSIVE: STAT(dot3StatsExcessiveCollisions); 239 case S_MACTX: STAT(dot3StatsInternalMacTransmitErrors); 240 case S_CARRIER: STAT(dot3StatsCarrierSenseErrors); 241 case S_TOOBIG: STAT(TxLargeFrameDiscards); 242 case S_TX_VLAN_ID: STAT(TxVLANIdFilterDiscards); 243 } 244 b[0] = '\0'; 245 return 0; 246 #undef STAT 247 } 248 249 STATFOO_DEFINE_BOUNCE(npestatfoo) 250 251 struct npestatfoo * 252 npestats_new(const char *ifname, const char *fmtstring) 253 { 254 #define N(a) (sizeof(a) / sizeof(a[0])) 255 struct npestatfoo_p *wf; 256 257 wf = calloc(1, sizeof(struct npestatfoo_p)); 258 if (wf != NULL) { 259 statfoo_init(&wf->base.base, "npestats", npestats, N(npestats)); 260 /* override base methods */ 261 wf->base.base.collect_cur = npe_collect_cur; 262 wf->base.base.collect_tot = npe_collect_tot; 263 wf->base.base.get_curstat = npe_get_curstat; 264 wf->base.base.get_totstat = npe_get_totstat; 265 wf->base.base.update_tot = npe_update_tot; 266 267 /* setup bounce functions for public methods */ 268 STATFOO_BOUNCE(wf, npestatfoo); 269 270 /* setup our public methods */ 271 wf->base.setifname = npe_setifname; 272 273 npe_setifname(&wf->base, ifname); 274 wf->base.setfmt(&wf->base, fmtstring); 275 } 276 return &wf->base; 277 #undef N 278 } 279