Annotation of embedaddon/bmon/src/in_netlink.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * in_netlink.c            rtnetlink input (Linux)
                      3:  *
                      4:  * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch>
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a
                      7:  * copy of this software and associated documentation files (the "Software"),
                      8:  * to deal in the Software without restriction, including without limitation
                      9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
                     10:  * and/or sell copies of the Software, and to permit persons to whom the
                     11:  * Software is furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included
                     14:  * in all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                     17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
                     21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
                     22:  * DEALINGS IN THE SOFTWARE.
                     23:  */
                     24: 
                     25: #include <bmon/bmon.h>
                     26: #include <bmon/input.h>
                     27: #include <bmon/node.h>
                     28: #include <bmon/item.h>
                     29: #include <bmon/conf.h>
                     30: #include <bmon/utils.h>
                     31: 
                     32: #if defined HAVE_NL && defined SYS_LINUX
                     33: 
                     34: static int c_notc = 0;
                     35: static const char *c_mapfile;
                     36: 
                     37: struct hmap {
                     38:        char *id;
                     39:        char *name;
                     40:        struct hmap *next;
                     41: };
                     42: 
                     43: static struct hmap *map;
                     44: 
                     45: #include <netlink/netlink.h>
                     46: #include <netlink/cache.h>
                     47: #include <netlink/helpers.h>
                     48: #include <netlink/route/link.h>
                     49: #include <netlink/route/qdisc.h>
                     50: #include <netlink/route/class.h>
                     51: #include <netlink/route/filter.h>
                     52: 
                     53: #include <net/if.h>
                     54: 
                     55: static struct nl_handle nl_h = NL_INIT_HANDLE();
                     56: static struct nl_cache link_cache = RTNL_INIT_LINK_CACHE();
                     57: static struct nl_cache *qdisc_cache;
                     58: static struct nl_cache *class_cache;
                     59: 
                     60: struct xdata {
                     61:        item_t *intf;
                     62:        struct rtnl_link *link;
                     63:        int level;
                     64:        item_t *parent;
                     65: };
                     66: 
                     67: static void read_map(const char *file)
                     68: {
                     69:        FILE *f;
                     70:        char buf[1024];
                     71:        int line = 0;
                     72: 
                     73:        f = fopen(file, "r");
                     74:        if (f == NULL)
                     75:                quit("Could not open mapfile %s: %s\n", file, strerror(errno));
                     76: 
                     77:        while (fgets(buf, sizeof(buf), f)) {
                     78:                struct hmap *m;
                     79:                char *p, *id, *name;
                     80:                line++;
                     81:                if (*buf == '#' || *buf == '\r' || *buf == '\n')
                     82:                        continue;
                     83: 
                     84:                for (p = buf; *p == ' ' || *p == '\t'; p++);
                     85:                if (*p == '\0')
                     86:                        quit("%s: Parse error at line %d: Missing handle\n",
                     87:                            file, line);
                     88:                id = p;
                     89: 
                     90:                for (; *p != ' ' && *p != '\t' && *p != '\0'; p++);
                     91:                if (*p == '\0')
                     92:                        quit("%s: Parse error at line %d: Missing name\n",
                     93:                            file, line);
                     94:                *p = '\0';
                     95: 
                     96:                for (++p; *p == ' ' || *p == '\t'; p++);
                     97:                name = p;
                     98:                for (; *p != ' ' && *p != '\t' && *p != '\0' &&
                     99:                       *p != '\r' && *p != '\n'; p++);
                    100:                *p = '\0';
                    101: 
                    102:                if (strlen(id) <= 0 || strlen(name) <= 0)
                    103:                        quit("%s: Parse error at line %d: Invalid id or handle\n",
                    104:                            file, line);
                    105: 
                    106:                m = xcalloc(1, sizeof(*m));
                    107:                m->id = strdup(id);
                    108:                m->name = strdup(name);
                    109:                m->next = map;
                    110:                map = m;
                    111:        }
                    112: 
                    113:        fclose(f);
                    114: }
                    115: 
                    116: static const char *lookup_map(const char *handle)
                    117: {
                    118:        struct hmap *m;
                    119: 
                    120:        for (m = map; m; m = m->next)
                    121:                if (!strcmp(handle, m->id))
                    122:                        return m->name;
                    123: 
                    124:        return handle;
                    125: }
                    126: 
                    127: static void handle_qdisc(struct nl_common *, void *);
                    128: 
                    129: #if 0
                    130: static void handle_filter(struct nl_common *c, void *arg)
                    131: {
                    132:        struct rtnl_filter *filter = (struct rtnl_filter *) c;
                    133:        struct xdata *x = arg;
                    134:        item_t *intf;
                    135:        char name[IFNAME_MAX];
                    136: 
                    137:        printf("HAHAH!\n");
                    138: 
                    139:        if (filter->f_handle) {
                    140:                const char *h = lookup_map(nl_handle2str(filter->f_handle));
                    141:                snprintf(name, sizeof(name), "f:%s %s", filter->f_kind, h);
                    142:        } else
                    143:                snprintf(name, sizeof(name), "f:%s", filter->f_kind);
                    144: 
                    145:        intf = lookup_item(get_local_node(), name, filter->f_handle, x->parent);
                    146: 
                    147:        if (intf == NULL)
                    148:                return;
                    149: 
                    150:        intf->i_link = x->intf->i_index;
                    151:        intf->i_flags |= ITEM_FLAG_IS_CHILD;
                    152:        intf->i_level = x->level;
                    153: 
                    154:        update_attr(intf, PACKETS, 0, 0, 0);
                    155:        update_attr(intf, BYTES, 0, 0, 0);
                    156: 
                    157:        notify_update(intf, NULL);
                    158:        increase_lifetime(intf, 1);
                    159: }
                    160: #endif
                    161: 
                    162: static void handle_class(struct nl_common *c, void *arg)
                    163: {
                    164:        struct rtnl_class *class = (struct rtnl_class *) c;
                    165:        struct rtnl_qdisc *leaf;
                    166:        struct xdata *x = arg;
                    167:        item_t *intf;
                    168:        char name[IFNAME_MAX];
                    169:        struct xdata xn = {
                    170:                .intf = x->intf,
                    171:                .link = x->link,
                    172:                .level = x->level + 1,
                    173:        };
                    174: 
                    175:        if (class->c_handle) {
                    176:                const char *h = lookup_map(nl_handle2str(class->c_handle));
                    177:                snprintf(name, sizeof(name), "c:%s(%s)", class->c_kind, h);
                    178:        } else
                    179:                snprintf(name, sizeof(name), "c:%s", class->c_kind);
                    180: 
                    181:        intf = lookup_item(get_local_node(), name, class->c_handle, x->parent);
                    182: 
                    183:        if (intf == NULL)
                    184:                return;
                    185: 
                    186:        xn.parent = intf;
                    187: 
                    188:        intf->i_link = x->intf->i_index;
                    189:        intf->i_flags |= ITEM_FLAG_IS_CHILD;
                    190:        intf->i_level = x->level;
                    191:        intf->i_major_attr = BYTES;
                    192:        intf->i_minor_attr = PACKETS;
                    193: 
                    194:        update_attr(intf, PACKETS, 0, class->c_stats.tcs_basic.packets, TX_PROVIDED);
                    195:        update_attr(intf, BYTES, 0, class->c_stats.tcs_basic.bytes, TX_PROVIDED);
                    196:        update_attr(intf, DROP, 0, class->c_stats.tcs_queue.drops, TX_PROVIDED);
                    197:        update_attr(intf, OVERLIMITS, 0, class->c_stats.tcs_queue.overlimits, TX_PROVIDED);
                    198:        update_attr(intf, BPS, 0, class->c_stats.tcs_rate_est.bps, TX_PROVIDED);
                    199:        update_attr(intf, PPS, 0, class->c_stats.tcs_rate_est.pps, TX_PROVIDED);
                    200:        update_attr(intf, QLEN, 0, class->c_stats.tcs_queue.qlen, TX_PROVIDED);
                    201:        update_attr(intf, BACKLOG, 0, class->c_stats.tcs_queue.backlog, TX_PROVIDED);
                    202:        update_attr(intf, REQUEUES, 0, class->c_stats.tcs_queue.requeues, TX_PROVIDED);
                    203: 
                    204:        notify_update(intf, NULL);
                    205:        increase_lifetime(intf, 1);
                    206: 
                    207:        if ((leaf = rtnl_class_leaf_qdisc(class, qdisc_cache)))
                    208:                handle_qdisc((struct nl_common *) leaf, &xn);
                    209:        rtnl_class_foreach_child(class, class_cache, &handle_class, &xn);
                    210: #if 0
                    211:        rtnl_class_foreach_filter_nocache(&nl_h, class, &handle_filter, &xn);
                    212: #endif
                    213: }
                    214: 
                    215: static void handle_qdisc(struct nl_common *c, void *arg)
                    216: {
                    217:        struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) c;
                    218:        struct xdata *x = arg;
                    219:        item_t *intf;
                    220:        char name[IFNAME_MAX];
                    221:        struct xdata xn = {
                    222:                .intf = x->intf,
                    223:                .link = x->link,
                    224:                .level = x->level + 1,
                    225:        };
                    226: 
                    227:        if (qdisc->q_handle) {
                    228:                const char *h = lookup_map(nl_handle2str(qdisc->q_handle));
                    229:                snprintf(name, sizeof(name), "q:%s(%s)", qdisc->q_kind, h);
                    230:        } else
                    231:                snprintf(name, sizeof(name), "q:%s", qdisc->q_kind);
                    232: 
                    233:        intf = lookup_item(get_local_node(), name, qdisc->q_handle, x->parent);
                    234:        if (intf == NULL)
                    235:                return;
                    236: 
                    237:        xn.parent = intf;
                    238: 
                    239:        intf->i_link = x->intf->i_index;
                    240:        intf->i_flags |= ITEM_FLAG_IS_CHILD;
                    241:        intf->i_level = x->level;
                    242:        intf->i_major_attr = BYTES;
                    243:        intf->i_minor_attr = PACKETS;
                    244: 
                    245:        if (qdisc->q_handle == 0xffff00) {
                    246:                update_attr(intf, BYTES, qdisc->q_stats.tcs_basic.bytes, 0, RX_PROVIDED);
                    247:                update_attr(intf, PACKETS, qdisc->q_stats.tcs_basic.packets, 0, RX_PROVIDED);
                    248:                update_attr(intf, DROP, qdisc->q_stats.tcs_queue.drops, 0, RX_PROVIDED);
                    249:                update_attr(intf, OVERLIMITS, qdisc->q_stats.tcs_queue.overlimits, 0, RX_PROVIDED);
                    250:                update_attr(intf, BPS, qdisc->q_stats.tcs_rate_est.bps, 0, RX_PROVIDED);
                    251:                update_attr(intf, PPS, qdisc->q_stats.tcs_rate_est.pps, 0, RX_PROVIDED);
                    252:                update_attr(intf, QLEN, qdisc->q_stats.tcs_queue.qlen, 0, RX_PROVIDED);
                    253:                update_attr(intf, BACKLOG, qdisc->q_stats.tcs_queue.backlog, 0, RX_PROVIDED);
                    254:                update_attr(intf, REQUEUES, qdisc->q_stats.tcs_queue.requeues, 0, RX_PROVIDED);
                    255:        } else {
                    256:                update_attr(intf, BYTES, 0, qdisc->q_stats.tcs_basic.bytes, TX_PROVIDED);
                    257:                update_attr(intf, PACKETS, 0, qdisc->q_stats.tcs_basic.packets, TX_PROVIDED);
                    258:                update_attr(intf, DROP, 0, qdisc->q_stats.tcs_queue.drops, TX_PROVIDED);
                    259:                update_attr(intf, OVERLIMITS, 0, qdisc->q_stats.tcs_queue.overlimits, TX_PROVIDED);
                    260:                update_attr(intf, BPS, 0, qdisc->q_stats.tcs_rate_est.bps, TX_PROVIDED);
                    261:                update_attr(intf, PPS, 0, qdisc->q_stats.tcs_rate_est.pps, TX_PROVIDED);
                    262:                update_attr(intf, QLEN, 0, qdisc->q_stats.tcs_queue.qlen, TX_PROVIDED);
                    263:                update_attr(intf, BACKLOG, 0, qdisc->q_stats.tcs_queue.backlog, TX_PROVIDED);
                    264:                update_attr(intf, REQUEUES, 0, qdisc->q_stats.tcs_queue.requeues, TX_PROVIDED);
                    265:        }
                    266: 
                    267:        notify_update(intf, NULL);
                    268:        increase_lifetime(intf, 1);
                    269: 
                    270:        rtnl_qdisc_foreach_child(qdisc, class_cache, &handle_class, &xn);
                    271: #if 0
                    272:        rtnl_qdisc_foreach_filter_nocache(&nl_h, qdisc, &handle_filter, &xn);
                    273: #endif
                    274: }
                    275: 
                    276: static void handle_tc(item_t *intf, struct rtnl_link *link)
                    277: {
                    278:        struct rtnl_qdisc *qdisc;
                    279:        struct xdata x = {
                    280:                .intf = intf,
                    281:                .link = link,
                    282:                .level = 1,
                    283:                .parent = intf,
                    284:        };
                    285: 
                    286:        class_cache = rtnl_class_build_cache(&nl_h, link->l_index);
                    287:        if (class_cache == NULL)
                    288:                return;
                    289: 
                    290:        if ((qdisc = rtnl_qdisc_get_root(qdisc_cache, link->l_index)))
                    291:                handle_qdisc((struct nl_common *) qdisc, &x);
                    292:        else if ((qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, link->l_index, 0)))
                    293:                handle_qdisc((struct nl_common *) qdisc, &x);
                    294: 
                    295:        if ((qdisc = rtnl_qdisc_get_ingress(qdisc_cache, link->l_index)))
                    296:                handle_qdisc((struct nl_common *) qdisc, &x);
                    297: 
                    298:        nl_cache_destroy_and_free(class_cache);
                    299: }
                    300: 
                    301: static void do_link(struct nl_common *item, void *arg)
                    302: {
                    303:        struct rtnl_link *link = (struct rtnl_link *) item;
                    304:        struct rtnl_lstats *st;
                    305:        item_t *intf;
                    306: 
                    307:        if (!link->l_name[0])
                    308:                return;
                    309: 
                    310:        if (get_show_only_running() && !(link->l_flags & IFF_UP))
                    311:                return;
                    312: 
                    313:        intf = lookup_item(get_local_node(), link->l_name, 0, 0);
                    314: 
                    315:        if (NULL == intf)
                    316:                return;
                    317: 
                    318:        intf->i_major_attr = BYTES;
                    319:        intf->i_minor_attr = PACKETS;
                    320: 
                    321:        st = &link->l_stats;
                    322: 
                    323:        update_attr(intf, BYTES, st->ls_rx.bytes, st->ls_tx.bytes,
                    324:                    RX_PROVIDED | TX_PROVIDED);
                    325:        update_attr(intf, PACKETS, st->ls_rx.packets, st->ls_tx.packets,
                    326:                    RX_PROVIDED | TX_PROVIDED);
                    327: 
                    328:        update_attr(intf, ERRORS, st->ls_rx.errors, st->ls_tx.errors,
                    329:                RX_PROVIDED | TX_PROVIDED);
                    330: 
                    331:        update_attr(intf, DROP, st->ls_rx.dropped, st->ls_tx.dropped,
                    332:                RX_PROVIDED | TX_PROVIDED);
                    333: 
                    334:        update_attr(intf, FIFO, st->ls_rx_fifo_errors,
                    335:                st->ls_tx_fifo_errors, RX_PROVIDED | TX_PROVIDED);
                    336: 
                    337:        update_attr(intf, COMPRESSED, st->ls_rx.compressed,
                    338:                st->ls_tx.compressed, RX_PROVIDED | TX_PROVIDED);
                    339: 
                    340:        update_attr(intf, MULTICAST, st->ls_rx.multicast, 0, RX_PROVIDED);
                    341:        update_attr(intf, COLLISIONS, 0, st->ls_tx_collisions, TX_PROVIDED);
                    342:        update_attr(intf, LENGTH_ERRORS, st->ls_rx_length_errors, 0, RX_PROVIDED);
                    343:        update_attr(intf, OVER_ERRORS, st->ls_rx_over_errors, 0, RX_PROVIDED);
                    344:        update_attr(intf, CRC_ERRORS, st->ls_rx_crc_errors, 0, RX_PROVIDED);
                    345:        update_attr(intf, FRAME, st->ls_rx_frame_errors, 0, RX_PROVIDED);
                    346:        update_attr(intf, MISSED_ERRORS, st->ls_rx_missed_errors, 0, RX_PROVIDED);
                    347:        update_attr(intf, ABORTED_ERRORS, 0, st->ls_tx_aborted_errors, TX_PROVIDED);
                    348:        update_attr(intf, HEARTBEAT_ERRORS, 0, st->ls_tx_heartbeat_errors,
                    349:                TX_PROVIDED);
                    350:        update_attr(intf, WINDOW_ERRORS, 0, st->ls_tx_window_errors, TX_PROVIDED);
                    351:        update_attr(intf, CARRIER_ERRORS, 0, st->ls_tx_carrier_errors, TX_PROVIDED);
                    352: 
                    353:        if (!c_notc)
                    354:                handle_tc(intf, link);
                    355:        
                    356:        notify_update(intf, NULL);
                    357:        increase_lifetime(intf, 1);
                    358: }
                    359: 
                    360: static void netlink_read(void)
                    361: {
                    362:        if (nl_cache_update(&nl_h, &link_cache) < 0)
                    363:                quit("%s\n", nl_geterror());
                    364: 
                    365:        if (!c_notc) {
                    366:                if (qdisc_cache == NULL) {
                    367:                        qdisc_cache = rtnl_qdisc_build_cache(&nl_h);
                    368:                        if (qdisc_cache == NULL)
                    369:                                c_notc = 1;
                    370:                } else {
                    371:                        if (nl_cache_update(&nl_h, qdisc_cache) < 0)
                    372:                                c_notc = 1;
                    373:                }
                    374:        }
                    375: 
                    376:        nl_cache_foreach(&link_cache, do_link, NULL);
                    377: }
                    378: 
                    379: static void netlink_shutdown(void)
                    380: {
                    381:        nl_close(&nl_h);
                    382: }
                    383: 
                    384: static void netlink_do_init(void)
                    385: {
                    386:        if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)
                    387:                quit("%s\n", nl_geterror());
                    388: 
                    389:        nl_use_default_handlers(&nl_h);
                    390: }
                    391: 
                    392: static int netlink_probe(void)
                    393: {
                    394:        if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)
                    395:                return 0;
                    396:        
                    397:        if (nl_cache_update(&nl_h, &link_cache) < 0) {
                    398:                nl_close(&nl_h);
                    399:                return 0;
                    400:        }
                    401: 
                    402:        nl_cache_destroy(&link_cache);
                    403:        nl_close(&nl_h);
                    404: 
                    405:        if (c_mapfile)
                    406:                read_map(c_mapfile);
                    407:        
                    408:        return 1;
                    409: }
                    410: 
                    411: static void print_help(void)
                    412: {
                    413:        printf(
                    414:        "netlink - Netlink statistic collector for Linux\n" \
                    415:        "\n" \
                    416:        "  Powerful statistic collector for Linux using netlink sockets\n" \
                    417:        "  to collect link and traffic control statistics.\n" \
                    418:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
                    419:        "\n" \
                    420:        "  Options:\n" \
                    421:        "    notc           Do not collect traffic control statistics\n" \
                    422:        "    map=FILE       Translate handles to map using a mapfile\n" \
                    423:        "\n" \
                    424:        "  Map File format:\n" \
                    425:        "    # comment\n" \
                    426:        "    <handle> <name> # midline comment\n");
                    427: }
                    428: 
                    429: static void netlink_set_opts(tv_t *attrs)
                    430: {
                    431:        while (attrs) {
                    432:                if (!strcasecmp(attrs->type, "notc"))
                    433:                        c_notc = 1;
                    434:                else if (!strcasecmp(attrs->type, "map"))
                    435:                        c_mapfile = attrs->value;
                    436:                else if (!strcasecmp(attrs->type, "help")) {
                    437:                        print_help();
                    438:                        exit(0);
                    439:                }
                    440:                attrs = attrs->next;
                    441:        }
                    442: }
                    443: 
                    444: static struct input_module netlink_ops = {
                    445:        .im_name     = "netlink",
                    446:        .im_read     = netlink_read,
                    447:        .im_shutdown = netlink_shutdown,
                    448:        .im_set_opts = netlink_set_opts,
                    449:        .im_probe = netlink_probe,
                    450:        .im_init = netlink_do_init,
                    451: };
                    452: 
                    453: static void __init netlink_init(void)
                    454: {
                    455:        register_input_module(&netlink_ops);
                    456: }
                    457: 
                    458: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>