1 /* $OpenBSD: if.c,v 1.20 2011/04/05 07:35:32 mpf 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 18 #include <sys/param.h> 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/sysctl.h> 22 #include <net/if.h> 23 #include <net/if_dl.h> 24 #include <net/route.h> 25 #include <sys/sockio.h> 26 #include <sys/ioctl.h> 27 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "systat.h" 33 34 static enum state { BOOT, TIME, RUN } state = TIME; 35 36 struct ifstat { 37 char ifs_name[IFNAMSIZ]; /* interface name */ 38 char ifs_description[IFDESCRSIZE]; 39 struct ifcount ifs_cur; 40 struct ifcount ifs_old; 41 struct ifcount ifs_now; 42 char ifs_flag; 43 } *ifstats; 44 45 static int nifs = 0; 46 static int num_ifs = 0; 47 static int show_bits = 0; 48 49 void print_if(void); 50 int read_if(void); 51 int select_if(void); 52 int if_keyboard_callback(int); 53 54 void fetchifstat(void); 55 static void showifstat(struct ifstat *); 56 static void showtotal(void); 57 static void rt_getaddrinfo(struct sockaddr *, int, struct sockaddr **); 58 59 60 /* Define fields */ 61 field_def fields_if[] = { 62 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 63 {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 64 {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 68 {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 69 {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 70 {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 71 {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 72 }; 73 74 75 #define FLD_IF_IFACE FIELD_ADDR(fields_if,0) 76 #define FLD_IF_STATE FIELD_ADDR(fields_if,1) 77 #define FLD_IF_IPKTS FIELD_ADDR(fields_if,2) 78 #define FLD_IF_IBYTES FIELD_ADDR(fields_if,3) 79 #define FLD_IF_IERRS FIELD_ADDR(fields_if,4) 80 #define FLD_IF_OPKTS FIELD_ADDR(fields_if,5) 81 #define FLD_IF_OBYTES FIELD_ADDR(fields_if,6) 82 #define FLD_IF_OERRS FIELD_ADDR(fields_if,7) 83 #define FLD_IF_COLLS FIELD_ADDR(fields_if,8) 84 #define FLD_IF_DESC FIELD_ADDR(fields_if,9) 85 86 87 /* Define views */ 88 field_def *view_if_0[] = { 89 FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS, 90 FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, 91 FLD_IF_OERRS, FLD_IF_COLLS, NULL 92 }; 93 94 /* Define view managers */ 95 96 struct view_manager ifstat_mgr = { 97 "Ifstat", select_if, read_if, NULL, print_header, 98 print_if, if_keyboard_callback, NULL, NULL 99 }; 100 101 field_view views_if[] = { 102 {view_if_0, "ifstat", '1', &ifstat_mgr}, 103 {NULL, NULL, 0, NULL} 104 }; 105 106 107 int 108 initifstat(void) 109 { 110 field_view *v; 111 read_if(); 112 for (v = views_if; v->name != NULL; v++) 113 add_view(v); 114 115 return(1); 116 } 117 118 #define UPDATE(x, y) do { \ 119 ifs->ifs_now.x = ifm.y; \ 120 ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \ 121 if (state == TIME) {\ 122 ifs->ifs_old.x = ifs->ifs_now.x; \ 123 ifs->ifs_cur.x /= naptime; \ 124 } \ 125 sum.x += ifs->ifs_cur.x; \ 126 } while(0) 127 128 129 void 130 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info) 131 { 132 int i; 133 134 for (i = 0; i < RTAX_MAX; i++) { 135 if (addrs & (1 << i)) { 136 info[i] = sa; 137 sa = (struct sockaddr *) ((char *)(sa) + 138 roundup(sa->sa_len, sizeof(long))); 139 } else 140 info[i] = NULL; 141 } 142 } 143 144 145 146 int 147 select_if(void) 148 { 149 num_disp = num_ifs + 1; 150 return (0); 151 } 152 153 int 154 read_if(void) 155 { 156 fetchifstat(); 157 num_disp = num_ifs + 1; 158 159 return 0; 160 } 161 162 void 163 print_if(void) 164 { 165 int n, i, count = 0; 166 167 for (n = 0, i = 0; n < nifs; n++) { 168 if (ifstats[n].ifs_name[0] == '\0') 169 continue; 170 if (i++ < dispstart) 171 continue; 172 if (i == num_disp) 173 break; 174 showifstat(ifstats + n); 175 if (maxprint > 0 && ++count >= maxprint) 176 return; 177 } 178 showtotal(); 179 } 180 181 182 void 183 fetchifstat(void) 184 { 185 struct ifstat *newstats, *ifs; 186 struct if_msghdr ifm; 187 struct sockaddr *info[RTAX_MAX]; 188 struct sockaddr_dl *sdl; 189 char *buf, *next, *lim; 190 int mib[6], i; 191 size_t need; 192 193 mib[0] = CTL_NET; 194 mib[1] = AF_ROUTE; 195 mib[2] = 0; 196 mib[3] = 0; 197 mib[4] = NET_RT_IFLIST; 198 mib[5] = 0; 199 200 if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1) 201 return; 202 if ((buf = malloc(need)) == NULL) 203 return; 204 if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) { 205 free(buf); 206 return; 207 } 208 209 bzero(&sum, sizeof(sum)); 210 num_ifs = 0; 211 212 lim = buf + need; 213 for (next = buf; next < lim; next += ifm.ifm_msglen) { 214 bcopy(next, &ifm, sizeof ifm); 215 if (ifm.ifm_version != RTM_VERSION || 216 ifm.ifm_type != RTM_IFINFO || 217 !(ifm.ifm_addrs & RTA_IFP)) 218 continue; 219 if (ifm.ifm_index >= nifs) { 220 if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) 221 * sizeof(struct ifstat))) == NULL) 222 continue; 223 ifstats = newstats; 224 for (; nifs < ifm.ifm_index + 4; nifs++) 225 bzero(&ifstats[nifs], sizeof(*ifstats)); 226 } 227 ifs = &ifstats[ifm.ifm_index]; 228 if (ifs->ifs_name[0] == '\0') { 229 bzero(&info, sizeof(info)); 230 rt_getaddrinfo( 231 (struct sockaddr *)((struct if_msghdr *)next + 1), 232 ifm.ifm_addrs, info); 233 sdl = (struct sockaddr_dl *)info[RTAX_IFP]; 234 235 if (sdl && sdl->sdl_family == AF_LINK && 236 sdl->sdl_nlen > 0) { 237 struct ifreq ifrdesc; 238 char ifdescr[IFDESCRSIZE]; 239 int s; 240 241 bcopy(sdl->sdl_data, ifs->ifs_name, 242 sdl->sdl_nlen); 243 ifs->ifs_name[sdl->sdl_nlen] = '\0'; 244 245 /* Get the interface description */ 246 memset(&ifrdesc, 0, sizeof(ifrdesc)); 247 strlcpy(ifrdesc.ifr_name, ifs->ifs_name, 248 sizeof(ifrdesc.ifr_name)); 249 ifrdesc.ifr_data = (caddr_t)&ifdescr; 250 251 s = socket(AF_INET, SOCK_DGRAM, 0); 252 if (s != -1) { 253 if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) 254 strlcpy(ifs->ifs_description, 255 ifrdesc.ifr_data, 256 sizeof(ifs->ifs_description)); 257 close(s); 258 } 259 } 260 if (ifs->ifs_name[0] == '\0') 261 continue; 262 } 263 num_ifs++; 264 UPDATE(ifc_ip, ifm_data.ifi_ipackets); 265 UPDATE(ifc_ib, ifm_data.ifi_ibytes); 266 UPDATE(ifc_ie, ifm_data.ifi_ierrors); 267 UPDATE(ifc_op, ifm_data.ifi_opackets); 268 UPDATE(ifc_ob, ifm_data.ifi_obytes); 269 UPDATE(ifc_oe, ifm_data.ifi_oerrors); 270 UPDATE(ifc_co, ifm_data.ifi_collisions); 271 ifs->ifs_cur.ifc_flags = ifm.ifm_flags; 272 ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state; 273 ifs->ifs_flag++; 274 } 275 276 /* remove unreferenced interfaces */ 277 for (i = 0; i < nifs; i++) { 278 ifs = &ifstats[i]; 279 if (ifs->ifs_flag) 280 ifs->ifs_flag = 0; 281 else 282 ifs->ifs_name[0] = '\0'; 283 } 284 285 free(buf); 286 } 287 288 289 static void 290 showifstat(struct ifstat *ifs) 291 { 292 int conv = show_bits ? 8 : 1; 293 int div = show_bits ? 1000 : 1024; 294 295 print_fld_str(FLD_IF_IFACE, ifs->ifs_name); 296 297 tb_start(); 298 tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ? 299 "up" : "dn"); 300 301 switch (ifs->ifs_cur.ifc_state) { 302 case LINK_STATE_UP: 303 case LINK_STATE_HALF_DUPLEX: 304 case LINK_STATE_FULL_DUPLEX: 305 tbprintf(":U"); 306 break; 307 case LINK_STATE_DOWN: 308 tbprintf (":D"); 309 break; 310 } 311 312 print_fld_tb(FLD_IF_STATE); 313 314 print_fld_str(FLD_IF_DESC, ifs->ifs_description); 315 316 print_fld_sdiv(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib * conv, div); 317 print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip); 318 print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie); 319 320 print_fld_sdiv(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob * conv, div); 321 print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op); 322 print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe); 323 324 print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co); 325 326 end_line(); 327 } 328 329 static void 330 showtotal(void) 331 { 332 int conv = show_bits ? 8 : 1; 333 int div = show_bits ? 1000 : 1024; 334 335 print_fld_str(FLD_IF_IFACE, "Totals"); 336 337 print_fld_sdiv(FLD_IF_IBYTES, sum.ifc_ib * conv, div); 338 print_fld_size(FLD_IF_IPKTS, sum.ifc_ip); 339 print_fld_size(FLD_IF_IERRS, sum.ifc_ie); 340 341 print_fld_sdiv(FLD_IF_OBYTES, sum.ifc_ob * conv, div); 342 print_fld_size(FLD_IF_OPKTS, sum.ifc_op); 343 print_fld_size(FLD_IF_OERRS, sum.ifc_oe); 344 345 print_fld_size(FLD_IF_COLLS, sum.ifc_co); 346 347 end_line(); 348 349 } 350 351 int 352 if_keyboard_callback(int ch) 353 { 354 struct ifstat *ifs; 355 356 switch (ch) { 357 case 'r': 358 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 359 ifs->ifs_old = ifs->ifs_now; 360 state = RUN; 361 gotsig_alarm = 1; 362 363 break; 364 case 'b': 365 state = BOOT; 366 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 367 bzero(&ifs->ifs_old, sizeof(ifs->ifs_old)); 368 gotsig_alarm = 1; 369 break; 370 case 'B': 371 show_bits = !show_bits; 372 if (show_bits) { 373 FLD_IF_IBYTES->title = "IBITS"; 374 FLD_IF_OBYTES->title = "OBITS"; 375 } else { 376 FLD_IF_IBYTES->title = "IBYTES"; 377 FLD_IF_OBYTES->title = "OBYTES"; 378 } 379 gotsig_alarm = 1; 380 break; 381 case 't': 382 state = TIME; 383 gotsig_alarm = 1; 384 break; 385 default: 386 return keyboard_callback(ch); 387 }; 388 389 return 1; 390 } 391 392