[BACK]Return to if.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

Annotation of src/usr.bin/systat/if.c, Revision 1.27

1.27    ! deraadt     1: /*     $OpenBSD: if.c,v 1.26 2021/01/18 00:49:09 mortimer Exp $ */
1.1       markus      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:  */
1.15      jasper     17:
1.27    ! deraadt    18: #include <sys/types.h>
1.23      deraadt    19: #include <sys/signal.h>
1.1       markus     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>
1.13      deraadt    25: #include <sys/sockio.h>
1.15      jasper     26: #include <sys/ioctl.h>
1.1       markus     27:
                     28: #include <stdlib.h>
1.5       deraadt    29: #include <string.h>
1.15      jasper     30: #include <unistd.h>
1.27    ! deraadt    31:
        !            32: #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
1.1       markus     33:
                     34: #include "systat.h"
                     35:
                     36: static  enum state { BOOT, TIME, RUN } state = TIME;
                     37:
                     38: struct ifstat {
                     39:        char            ifs_name[IFNAMSIZ];     /* interface name */
1.13      deraadt    40:        char            ifs_description[IFDESCRSIZE];
1.1       markus     41:        struct ifcount  ifs_cur;
                     42:        struct ifcount  ifs_old;
                     43:        struct ifcount  ifs_now;
1.17      canacar    44:        char            ifs_flag;
1.1       markus     45: } *ifstats;
1.26      mortimer   46:
                     47: struct ifcount sum;
1.1       markus     48:
                     49: static int nifs = 0;
1.12      canacar    50: static int num_ifs = 0;
1.20      mpf        51: static int show_bits = 0;
1.1       markus     52:
1.12      canacar    53: void print_if(void);
                     54: int read_if(void);
                     55: int select_if(void);
                     56: int if_keyboard_callback(int);
                     57:
1.16      deraadt    58: void fetchifstat(void);
1.12      canacar    59: static void showifstat(struct ifstat *);
                     60: static void showtotal(void);
1.18      lum        61: static void rt_getaddrinfo(struct sockaddr *, int, struct sockaddr **);
1.12      canacar    62:
1.24      dlg        63: const char ifails[] = "IFAILS";
                     64: const char ofails[] = "OFAILS";
                     65:
                     66: #define IF_ERR_SUM     0
                     67: #define IF_ERR_ERRORS  1
                     68: #define IF_ERR_QDROPS  2
                     69:
                     70: struct if_err_view {
                     71:        const char *iname;
                     72:        const char *oname;
                     73:        uint64_t (*icount)(const struct ifcount *);
                     74:        uint64_t (*ocount)(const struct ifcount *);
                     75: };
                     76:
                     77: static uint64_t if_err_ifails(const struct ifcount *);
                     78: static uint64_t if_err_ofails(const struct ifcount *);
                     79: static uint64_t if_err_ierrors(const struct ifcount *);
                     80: static uint64_t if_err_oerrors(const struct ifcount *);
                     81: static uint64_t if_err_iqdrops(const struct ifcount *);
                     82: static uint64_t if_err_oqdrops(const struct ifcount *);
                     83:
                     84: static const struct if_err_view if_err_views[] = {
                     85:        [IF_ERR_SUM] =    {
                     86:                .iname = ifails,
                     87:                .oname = ofails,
                     88:                .icount = if_err_ifails,
                     89:                .ocount = if_err_ofails,
                     90:        },
                     91:        [IF_ERR_ERRORS] = {
                     92:                .iname = "IERRS",
                     93:                .oname = "OERRS",
                     94:                .icount = if_err_ierrors,
                     95:                .ocount = if_err_oerrors,
                     96:        },
                     97:        [IF_ERR_QDROPS] = {
                     98:                .iname = "IQDROPS",
                     99:                .oname = "OQDROPS",
                    100:                .icount = if_err_iqdrops,
                    101:                .ocount = if_err_oqdrops,
                    102:        },
                    103: };
                    104:
                    105: static const struct if_err_view *if_err_view = &if_err_views[IF_ERR_SUM];
1.12      canacar   106:
                    107: /* Define fields */
                    108: field_def fields_if[] = {
                    109:        {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.13      deraadt   110:        {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12      canacar   111:        {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    112:        {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.24      dlg       113:        {ifails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.12      canacar   114:        {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    115:        {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.24      dlg       116:        {ofails, 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.12      canacar   117:        {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.13      deraadt   118:        {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12      canacar   119: };
                    120:
                    121:
1.19      jasper    122: #define FLD_IF_IFACE   FIELD_ADDR(fields_if,0)
                    123: #define FLD_IF_STATE   FIELD_ADDR(fields_if,1)
                    124: #define FLD_IF_IPKTS   FIELD_ADDR(fields_if,2)
                    125: #define FLD_IF_IBYTES  FIELD_ADDR(fields_if,3)
                    126: #define FLD_IF_IERRS   FIELD_ADDR(fields_if,4)
                    127: #define FLD_IF_OPKTS   FIELD_ADDR(fields_if,5)
                    128: #define FLD_IF_OBYTES  FIELD_ADDR(fields_if,6)
                    129: #define FLD_IF_OERRS   FIELD_ADDR(fields_if,7)
                    130: #define FLD_IF_COLLS   FIELD_ADDR(fields_if,8)
                    131: #define FLD_IF_DESC    FIELD_ADDR(fields_if,9)
1.12      canacar   132:
                    133:
                    134: /* Define views */
                    135: field_def *view_if_0[] = {
1.13      deraadt   136:        FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS,
                    137:        FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES,
                    138:        FLD_IF_OERRS, FLD_IF_COLLS, NULL
1.12      canacar   139: };
                    140:
                    141: /* Define view managers */
                    142:
                    143: struct view_manager ifstat_mgr = {
                    144:        "Ifstat", select_if, read_if, NULL, print_header,
                    145:        print_if, if_keyboard_callback, NULL, NULL
                    146: };
                    147:
                    148: field_view views_if[] = {
                    149:        {view_if_0, "ifstat", '1', &ifstat_mgr},
                    150:        {NULL, NULL, 0, NULL}
                    151: };
1.7       claudio   152:
1.1       markus    153:
                    154: int
                    155: initifstat(void)
                    156: {
1.12      canacar   157:        field_view *v;
                    158:        read_if();
                    159:        for (v = views_if; v->name != NULL; v++)
                    160:                add_view(v);
1.1       markus    161:
                    162:        return(1);
                    163: }
                    164:
                    165: #define UPDATE(x, y) do { \
1.2       deraadt   166:                ifs->ifs_now.x = ifm.y; \
1.1       markus    167:                ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
1.4       dlg       168:                if (state == TIME) {\
                    169:                        ifs->ifs_old.x = ifs->ifs_now.x; \
                    170:                        ifs->ifs_cur.x /= naptime; \
                    171:                } \
1.1       markus    172:                sum.x += ifs->ifs_cur.x; \
                    173:        } while(0)
                    174:
                    175:
                    176: void
                    177: rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
                    178: {
                    179:        int i;
                    180:
                    181:        for (i = 0; i < RTAX_MAX; i++) {
                    182:                if (addrs & (1 << i)) {
                    183:                        info[i] = sa;
                    184:                        sa = (struct sockaddr *) ((char *)(sa) +
                    185:                            roundup(sa->sa_len, sizeof(long)));
                    186:                } else
                    187:                        info[i] = NULL;
                    188:        }
                    189: }
                    190:
1.12      canacar   191:
                    192:
                    193: int
                    194: select_if(void)
                    195: {
                    196:        num_disp = num_ifs + 1;
                    197:        return (0);
                    198: }
                    199:
                    200: int
                    201: read_if(void)
                    202: {
                    203:        fetchifstat();
                    204:        num_disp = num_ifs + 1;
                    205:
                    206:        return 0;
                    207: }
                    208:
1.1       markus    209: void
1.12      canacar   210: print_if(void)
                    211: {
                    212:        int n, i, count = 0;
                    213:
                    214:        for (n = 0, i = 0; n < nifs; n++) {
                    215:                if (ifstats[n].ifs_name[0] == '\0')
                    216:                        continue;
                    217:                if (i++ < dispstart)
                    218:                        continue;
                    219:                if (i == num_disp)
                    220:                        break;
                    221:                showifstat(ifstats + n);
                    222:                if (maxprint > 0 && ++count >= maxprint)
                    223:                        return;
                    224:        }
                    225:        showtotal();
                    226: }
                    227:
                    228:
1.16      deraadt   229: void
1.1       markus    230: fetchifstat(void)
                    231: {
                    232:        struct ifstat *newstats, *ifs;
1.2       deraadt   233:        struct if_msghdr ifm;
1.1       markus    234:        struct sockaddr *info[RTAX_MAX];
                    235:        struct sockaddr_dl *sdl;
                    236:        char *buf, *next, *lim;
1.17      canacar   237:        int mib[6], i;
1.1       markus    238:        size_t need;
                    239:
                    240:        mib[0] = CTL_NET;
1.21      guenther  241:        mib[1] = PF_ROUTE;
1.1       markus    242:        mib[2] = 0;
                    243:        mib[3] = 0;
                    244:        mib[4] = NET_RT_IFLIST;
                    245:        mib[5] = 0;
                    246:
                    247:        if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
                    248:                return;
                    249:        if ((buf = malloc(need)) == NULL)
                    250:                return;
                    251:        if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
                    252:                free(buf);
                    253:                return;
                    254:        }
                    255:
                    256:        bzero(&sum, sizeof(sum));
1.12      canacar   257:        num_ifs = 0;
1.1       markus    258:
                    259:        lim = buf + need;
1.2       deraadt   260:        for (next = buf; next < lim; next += ifm.ifm_msglen) {
                    261:                bcopy(next, &ifm, sizeof ifm);
1.14      claudio   262:                if (ifm.ifm_version != RTM_VERSION ||
                    263:                    ifm.ifm_type != RTM_IFINFO ||
                    264:                    !(ifm.ifm_addrs & RTA_IFP))
1.1       markus    265:                        continue;
1.2       deraadt   266:                if (ifm.ifm_index >= nifs) {
1.22      doug      267:                        if ((newstats = reallocarray(ifstats, ifm.ifm_index + 4,
                    268:                            sizeof(struct ifstat))) == NULL)
1.1       markus    269:                                continue;
                    270:                        ifstats = newstats;
1.2       deraadt   271:                        for (; nifs < ifm.ifm_index + 4; nifs++)
1.12      canacar   272:                                bzero(&ifstats[nifs], sizeof(*ifstats));
1.1       markus    273:                }
1.2       deraadt   274:                ifs = &ifstats[ifm.ifm_index];
1.1       markus    275:                if (ifs->ifs_name[0] == '\0') {
                    276:                        bzero(&info, sizeof(info));
1.2       deraadt   277:                        rt_getaddrinfo(
                    278:                            (struct sockaddr *)((struct if_msghdr *)next + 1),
                    279:                            ifm.ifm_addrs, info);
1.13      deraadt   280:                        sdl = (struct sockaddr_dl *)info[RTAX_IFP];
                    281:
                    282:                        if (sdl && sdl->sdl_family == AF_LINK &&
                    283:                            sdl->sdl_nlen > 0) {
                    284:                                struct ifreq ifrdesc;
                    285:                                char ifdescr[IFDESCRSIZE];
                    286:                                int s;
                    287:
                    288:                                bcopy(sdl->sdl_data, ifs->ifs_name,
                    289:                                      sdl->sdl_nlen);
                    290:                                ifs->ifs_name[sdl->sdl_nlen] = '\0';
                    291:
                    292:                                /* Get the interface description */
                    293:                                memset(&ifrdesc, 0, sizeof(ifrdesc));
                    294:                                strlcpy(ifrdesc.ifr_name, ifs->ifs_name,
                    295:                                        sizeof(ifrdesc.ifr_name));
                    296:                                ifrdesc.ifr_data = (caddr_t)&ifdescr;
                    297:
                    298:                                s = socket(AF_INET, SOCK_DGRAM, 0);
                    299:                                if (s != -1) {
                    300:                                        if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0)
                    301:                                                strlcpy(ifs->ifs_description,
                    302:                                                    ifrdesc.ifr_data,
                    303:                                                    sizeof(ifs->ifs_description));
                    304:                                        close(s);
1.3       dlg       305:                                }
1.1       markus    306:                        }
                    307:                        if (ifs->ifs_name[0] == '\0')
                    308:                                continue;
                    309:                }
1.12      canacar   310:                num_ifs++;
1.1       markus    311:                UPDATE(ifc_ip, ifm_data.ifi_ipackets);
                    312:                UPDATE(ifc_ib, ifm_data.ifi_ibytes);
                    313:                UPDATE(ifc_ie, ifm_data.ifi_ierrors);
1.24      dlg       314:                UPDATE(ifc_iq, ifm_data.ifi_iqdrops);
1.1       markus    315:                UPDATE(ifc_op, ifm_data.ifi_opackets);
                    316:                UPDATE(ifc_ob, ifm_data.ifi_obytes);
                    317:                UPDATE(ifc_oe, ifm_data.ifi_oerrors);
1.24      dlg       318:                UPDATE(ifc_oq, ifm_data.ifi_oqdrops);
1.1       markus    319:                UPDATE(ifc_co, ifm_data.ifi_collisions);
1.7       claudio   320:                ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
                    321:                ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
1.17      canacar   322:                ifs->ifs_flag++;
1.1       markus    323:        }
1.17      canacar   324:
                    325:        /* remove unreferenced interfaces */
                    326:        for (i = 0; i < nifs; i++) {
                    327:                ifs = &ifstats[i];
                    328:                if (ifs->ifs_flag)
                    329:                        ifs->ifs_flag = 0;
                    330:                else
                    331:                        ifs->ifs_name[0] = '\0';
                    332:        }
                    333:
1.1       markus    334:        free(buf);
                    335: }
                    336:
                    337:
1.12      canacar   338: static void
                    339: showifstat(struct ifstat *ifs)
1.1       markus    340: {
1.20      mpf       341:        int conv = show_bits ? 8 : 1;
                    342:        int div = show_bits ? 1000 : 1024;
                    343:
1.12      canacar   344:        print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
1.1       markus    345:
1.12      canacar   346:        tb_start();
                    347:        tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
                    348:                 "up" : "dn");
1.7       claudio   349:
1.12      canacar   350:        switch (ifs->ifs_cur.ifc_state) {
1.7       claudio   351:        case LINK_STATE_UP:
1.8       reyk      352:        case LINK_STATE_HALF_DUPLEX:
                    353:        case LINK_STATE_FULL_DUPLEX:
1.12      canacar   354:                tbprintf(":U");
                    355:                break;
1.7       claudio   356:        case LINK_STATE_DOWN:
1.12      canacar   357:                tbprintf (":D");
                    358:                break;
1.7       claudio   359:        }
1.12      canacar   360:
                    361:        print_fld_tb(FLD_IF_STATE);
1.13      deraadt   362:
                    363:        print_fld_str(FLD_IF_DESC, ifs->ifs_description);
1.12      canacar   364:
1.20      mpf       365:        print_fld_sdiv(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib * conv, div);
1.12      canacar   366:        print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
1.24      dlg       367:        print_fld_size(FLD_IF_IERRS, if_err_view->icount(&ifs->ifs_cur));
1.12      canacar   368:
1.20      mpf       369:        print_fld_sdiv(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob * conv, div);
1.12      canacar   370:        print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
1.24      dlg       371:        print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&ifs->ifs_cur));
1.12      canacar   372:
                    373:        print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
                    374:
                    375:        end_line();
1.7       claudio   376: }
1.6       deraadt   377:
1.12      canacar   378: static void
                    379: showtotal(void)
1.1       markus    380: {
1.20      mpf       381:        int conv = show_bits ? 8 : 1;
                    382:        int div = show_bits ? 1000 : 1024;
                    383:
1.12      canacar   384:        print_fld_str(FLD_IF_IFACE, "Totals");
                    385:
1.20      mpf       386:        print_fld_sdiv(FLD_IF_IBYTES, sum.ifc_ib * conv, div);
1.12      canacar   387:        print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
1.24      dlg       388:        print_fld_size(FLD_IF_IERRS, if_err_view->icount(&sum));
1.12      canacar   389:
1.20      mpf       390:        print_fld_sdiv(FLD_IF_OBYTES, sum.ifc_ob * conv, div);
1.12      canacar   391:        print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
1.24      dlg       392:        print_fld_size(FLD_IF_OERRS, if_err_view->ocount(&sum));
1.12      canacar   393:
                    394:        print_fld_size(FLD_IF_COLLS, sum.ifc_co);
                    395:
                    396:        end_line();
1.1       markus    397:
                    398: }
                    399:
1.24      dlg       400: static uint64_t
                    401: if_err_ifails(const struct ifcount *ifc)
                    402: {
                    403:        return (ifc->ifc_ie + ifc->ifc_iq);
                    404: }
                    405:
                    406: static uint64_t
                    407: if_err_ofails(const struct ifcount *ifc)
                    408: {
                    409:        return (ifc->ifc_oe + ifc->ifc_oq);
                    410: }
                    411:
                    412: static uint64_t
                    413: if_err_ierrors(const struct ifcount *ifc)
                    414: {
                    415:        return (ifc->ifc_ie);
                    416: }
                    417:
                    418: static uint64_t
                    419: if_err_oerrors(const struct ifcount *ifc)
                    420: {
                    421:        return (ifc->ifc_oe);
                    422: }
                    423:
                    424: static uint64_t
                    425: if_err_iqdrops(const struct ifcount *ifc)
                    426: {
                    427:        return (ifc->ifc_iq);
                    428: }
                    429:
                    430: static uint64_t
                    431: if_err_oqdrops(const struct ifcount *ifc)
                    432: {
                    433:        return (ifc->ifc_oq);
                    434: }
                    435:
                    436: static void
                    437: if_set_errs(unsigned int v)
                    438: {
                    439:        if_err_view = &if_err_views[v];
                    440:        FLD_IF_IERRS->title = if_err_view->iname;
1.25      dlg       441:        FLD_IF_OERRS->title = if_err_view->oname;
1.24      dlg       442:        gotsig_alarm = 1;
                    443: }
                    444:
1.1       markus    445: int
1.12      canacar   446: if_keyboard_callback(int ch)
1.1       markus    447: {
                    448:        struct ifstat *ifs;
                    449:
1.12      canacar   450:        switch (ch) {
1.24      dlg       451:        case 'd':
                    452:                if_set_errs(IF_ERR_QDROPS);
                    453:                break;
                    454:        case 'e':
                    455:                if_set_errs(IF_ERR_ERRORS);
                    456:                break;
                    457:        case 'f':
                    458:                if_set_errs(IF_ERR_SUM);
                    459:                break;
                    460:
1.12      canacar   461:        case 'r':
                    462:                for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
                    463:                        ifs->ifs_old = ifs->ifs_now;
1.1       markus    464:                state = RUN;
1.12      canacar   465:                gotsig_alarm = 1;
                    466:
                    467:                break;
                    468:        case 'b':
1.1       markus    469:                state = BOOT;
                    470:                for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
                    471:                        bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
1.20      mpf       472:                gotsig_alarm = 1;
                    473:                break;
                    474:        case 'B':
                    475:                show_bits = !show_bits;
                    476:                if (show_bits) {
                    477:                        FLD_IF_IBYTES->title = "IBITS";
                    478:                        FLD_IF_OBYTES->title = "OBITS";
                    479:                } else {
                    480:                        FLD_IF_IBYTES->title = "IBYTES";
                    481:                        FLD_IF_OBYTES->title = "OBYTES";
                    482:                }
1.12      canacar   483:                gotsig_alarm = 1;
                    484:                break;
                    485:        case 't':
1.1       markus    486:                state = TIME;
1.12      canacar   487:                gotsig_alarm = 1;
                    488:                break;
                    489:        default:
                    490:                return keyboard_callback(ch);
                    491:        };
                    492:
                    493:        return 1;
1.1       markus    494: }
1.12      canacar   495: