Annotation of embedaddon/bmon/src/in_netlink.c, revision 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>