1 /* $OpenBSD: if.c,v 1.12 2008/06/12 22:26:01 canacar Exp $ */ 2 /* 3 * Copyright (c) 2004 Markus Friedl <markus@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/param.h> 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/sysctl.h> 21 #include <net/if.h> 22 #include <net/if_dl.h> 23 #include <net/route.h> 24 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "systat.h" 29 30 static enum state { BOOT, TIME, RUN } state = TIME; 31 32 struct ifcount { 33 u_int64_t ifc_ib; /* input bytes */ 34 u_int64_t ifc_ip; /* input packets */ 35 u_int64_t ifc_ie; /* input errors */ 36 u_int64_t ifc_ob; /* output bytes */ 37 u_int64_t ifc_op; /* output packets */ 38 u_int64_t ifc_oe; /* output errors */ 39 u_int64_t ifc_co; /* collisions */ 40 int ifc_flags; /* up / down */ 41 int ifc_state; /* link state */ 42 } sum; 43 44 struct ifstat { 45 char ifs_name[IFNAMSIZ]; /* interface name */ 46 struct ifcount ifs_cur; 47 struct ifcount ifs_old; 48 struct ifcount ifs_now; 49 } *ifstats; 50 51 static int nifs = 0; 52 static int num_ifs = 0; 53 54 void print_if(void); 55 int read_if(void); 56 int select_if(void); 57 int if_keyboard_callback(int); 58 59 static void fetchifstat(void); 60 static void showifstat(struct ifstat *); 61 static void showtotal(void); 62 63 64 /* Define fields */ 65 field_def fields_if[] = { 66 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 67 {"STATE", 10, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 68 {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 69 {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 70 {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 71 {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 72 {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 73 {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 74 {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 75 }; 76 77 78 #define FIELD_ADDR(x) (&fields_if[x]) 79 80 #define FLD_IF_IFACE FIELD_ADDR(0) 81 #define FLD_IF_STATE FIELD_ADDR(1) 82 #define FLD_IF_IPKTS FIELD_ADDR(2) 83 #define FLD_IF_IBYTES FIELD_ADDR(3) 84 #define FLD_IF_IERRS FIELD_ADDR(4) 85 #define FLD_IF_OPKTS FIELD_ADDR(5) 86 #define FLD_IF_OBYTES FIELD_ADDR(6) 87 #define FLD_IF_OERRS FIELD_ADDR(7) 88 #define FLD_IF_COLLS FIELD_ADDR(8) 89 90 91 /* Define views */ 92 field_def *view_if_0[] = { 93 FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_IPKTS, FLD_IF_IBYTES, 94 FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, FLD_IF_OERRS, 95 FLD_IF_COLLS, NULL 96 }; 97 98 /* Define view managers */ 99 100 struct view_manager ifstat_mgr = { 101 "Ifstat", select_if, read_if, NULL, print_header, 102 print_if, if_keyboard_callback, NULL, NULL 103 }; 104 105 field_view views_if[] = { 106 {view_if_0, "ifstat", '1', &ifstat_mgr}, 107 {NULL, NULL, 0, NULL} 108 }; 109 110 111 int 112 initifstat(void) 113 { 114 field_view *v; 115 read_if(); 116 for (v = views_if; v->name != NULL; v++) 117 add_view(v); 118 119 return(1); 120 } 121 122 #define UPDATE(x, y) do { \ 123 ifs->ifs_now.x = ifm.y; \ 124 ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \ 125 if (state == TIME) {\ 126 ifs->ifs_old.x = ifs->ifs_now.x; \ 127 ifs->ifs_cur.x /= naptime; \ 128 } \ 129 sum.x += ifs->ifs_cur.x; \ 130 } while(0) 131 132 133 void 134 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info) 135 { 136 int i; 137 138 for (i = 0; i < RTAX_MAX; i++) { 139 if (addrs & (1 << i)) { 140 info[i] = sa; 141 sa = (struct sockaddr *) ((char *)(sa) + 142 roundup(sa->sa_len, sizeof(long))); 143 } else 144 info[i] = NULL; 145 } 146 } 147 148 149 150 int 151 select_if(void) 152 { 153 num_disp = num_ifs + 1; 154 return (0); 155 } 156 157 int 158 read_if(void) 159 { 160 fetchifstat(); 161 num_disp = num_ifs + 1; 162 163 return 0; 164 } 165 166 void 167 print_if(void) 168 { 169 int n, i, count = 0; 170 171 for (n = 0, i = 0; n < nifs; n++) { 172 if (ifstats[n].ifs_name[0] == '\0') 173 continue; 174 if (i++ < dispstart) 175 continue; 176 if (i == num_disp) 177 break; 178 showifstat(ifstats + n); 179 if (maxprint > 0 && ++count >= maxprint) 180 return; 181 } 182 showtotal(); 183 } 184 185 186 static void 187 fetchifstat(void) 188 { 189 struct ifstat *newstats, *ifs; 190 struct if_msghdr ifm; 191 struct sockaddr *info[RTAX_MAX]; 192 struct sockaddr_dl *sdl; 193 char *buf, *next, *lim; 194 int mib[6]; 195 size_t need; 196 197 mib[0] = CTL_NET; 198 mib[1] = AF_ROUTE; 199 mib[2] = 0; 200 mib[3] = 0; 201 mib[4] = NET_RT_IFLIST; 202 mib[5] = 0; 203 204 if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1) 205 return; 206 if ((buf = malloc(need)) == NULL) 207 return; 208 if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) { 209 free(buf); 210 return; 211 } 212 213 bzero(&sum, sizeof(sum)); 214 num_ifs = 0; 215 216 lim = buf + need; 217 for (next = buf; next < lim; next += ifm.ifm_msglen) { 218 bcopy(next, &ifm, sizeof ifm); 219 if (ifm.ifm_type != RTM_IFINFO || 220 !(ifm.ifm_addrs & RTA_IFP)) 221 continue; 222 if (ifm.ifm_index >= nifs) { 223 if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) 224 * sizeof(struct ifstat))) == NULL) 225 continue; 226 ifstats = newstats; 227 for (; nifs < ifm.ifm_index + 4; nifs++) 228 bzero(&ifstats[nifs], sizeof(*ifstats)); 229 } 230 ifs = &ifstats[ifm.ifm_index]; 231 if (ifs->ifs_name[0] == '\0') { 232 bzero(&info, sizeof(info)); 233 rt_getaddrinfo( 234 (struct sockaddr *)((struct if_msghdr *)next + 1), 235 ifm.ifm_addrs, info); 236 if ((sdl = (struct sockaddr_dl *)info[RTAX_IFP])) { 237 if (sdl->sdl_family == AF_LINK && 238 sdl->sdl_nlen > 0) { 239 bcopy(sdl->sdl_data, ifs->ifs_name, 240 sdl->sdl_nlen); 241 ifs->ifs_name[sdl->sdl_nlen] = '\0'; 242 } 243 } 244 if (ifs->ifs_name[0] == '\0') 245 continue; 246 } 247 num_ifs++; 248 UPDATE(ifc_ip, ifm_data.ifi_ipackets); 249 UPDATE(ifc_ib, ifm_data.ifi_ibytes); 250 UPDATE(ifc_ie, ifm_data.ifi_ierrors); 251 UPDATE(ifc_op, ifm_data.ifi_opackets); 252 UPDATE(ifc_ob, ifm_data.ifi_obytes); 253 UPDATE(ifc_oe, ifm_data.ifi_oerrors); 254 UPDATE(ifc_co, ifm_data.ifi_collisions); 255 ifs->ifs_cur.ifc_flags = ifm.ifm_flags; 256 ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state; 257 } 258 free(buf); 259 } 260 261 262 static void 263 showifstat(struct ifstat *ifs) 264 { 265 print_fld_str(FLD_IF_IFACE, ifs->ifs_name); 266 267 tb_start(); 268 tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ? 269 "up" : "dn"); 270 271 switch (ifs->ifs_cur.ifc_state) { 272 case LINK_STATE_UP: 273 case LINK_STATE_HALF_DUPLEX: 274 case LINK_STATE_FULL_DUPLEX: 275 tbprintf(":U"); 276 break; 277 case LINK_STATE_DOWN: 278 tbprintf (":D"); 279 break; 280 } 281 282 print_fld_tb(FLD_IF_STATE); 283 284 print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib); 285 print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip); 286 print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie); 287 288 print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob); 289 print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op); 290 print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe); 291 292 print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co); 293 294 end_line(); 295 } 296 297 static void 298 showtotal(void) 299 { 300 print_fld_str(FLD_IF_IFACE, "Totals"); 301 302 print_fld_size(FLD_IF_IBYTES, sum.ifc_ib); 303 print_fld_size(FLD_IF_IPKTS, sum.ifc_ip); 304 print_fld_size(FLD_IF_IERRS, sum.ifc_ie); 305 306 print_fld_size(FLD_IF_OBYTES, sum.ifc_ob); 307 print_fld_size(FLD_IF_OPKTS, sum.ifc_op); 308 print_fld_size(FLD_IF_OERRS, sum.ifc_oe); 309 310 print_fld_size(FLD_IF_COLLS, sum.ifc_co); 311 312 end_line(); 313 314 } 315 316 int 317 if_keyboard_callback(int ch) 318 { 319 struct ifstat *ifs; 320 321 switch (ch) { 322 case 'r': 323 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 324 ifs->ifs_old = ifs->ifs_now; 325 state = RUN; 326 gotsig_alarm = 1; 327 328 break; 329 case 'b': 330 state = BOOT; 331 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 332 bzero(&ifs->ifs_old, sizeof(ifs->ifs_old)); 333 gotsig_alarm = 1; 334 break; 335 case 't': 336 state = TIME; 337 gotsig_alarm = 1; 338 break; 339 default: 340 return keyboard_callback(ch); 341 }; 342 343 return 1; 344 } 345 346