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

1.1       misho       1: /*
1.1.1.2 ! misho       2:  * in_netlink.c            Netlink input
1.1       misho       3:  *
1.1.1.2 ! misho       4:  * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
        !             5:  * Copyright (c) 2013 Red Hat, Inc.
1.1       misho       6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a
                      8:  * copy of this software and associated documentation files (the "Software"),
                      9:  * to deal in the Software without restriction, including without limitation
                     10:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
                     11:  * and/or sell copies of the Software, and to permit persons to whom the
                     12:  * Software is furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included
                     15:  * in all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
                     22:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
                     23:  * DEALINGS IN THE SOFTWARE.
                     24:  */
                     25: 
                     26: #include <bmon/bmon.h>
                     27: #include <bmon/input.h>
1.1.1.2 ! misho      28: #include <bmon/element.h>
        !            29: #include <bmon/attr.h>
1.1       misho      30: #include <bmon/conf.h>
1.1.1.2 ! misho      31: #include <bmon/input.h>
1.1       misho      32: #include <bmon/utils.h>
                     33: 
1.1.1.2 ! misho      34: #ifndef SYS_BSD
1.1       misho      35: 
                     36: static int c_notc = 0;
1.1.1.2 ! misho      37: static struct element_group *grp;
        !            38: static struct bmon_module netlink_ops;
1.1       misho      39: 
                     40: #include <netlink/netlink.h>
                     41: #include <netlink/cache.h>
1.1.1.2 ! misho      42: #include <netlink/utils.h>
1.1       misho      43: #include <netlink/route/link.h>
1.1.1.2 ! misho      44: #include <netlink/route/tc.h>
1.1       misho      45: #include <netlink/route/qdisc.h>
                     46: #include <netlink/route/class.h>
1.1.1.2 ! misho      47: #include <netlink/route/classifier.h>
        !            48: #include <netlink/route/qdisc/htb.h>
1.1       misho      49: 
1.1.1.2 ! misho      50: static struct attr_map link_attrs[] = {
        !            51: {
        !            52:        .name           = "bytes",
        !            53:        .type           = ATTR_TYPE_COUNTER,
        !            54:        .unit           = UNIT_BYTE,
        !            55:        .description    = "Bytes",
        !            56:        .rxid           = RTNL_LINK_RX_BYTES,
        !            57:        .txid           = RTNL_LINK_TX_BYTES,
        !            58: },
        !            59: {
        !            60:        .name           = "packets",
        !            61:        .type           = ATTR_TYPE_COUNTER,
        !            62:        .unit           = UNIT_NUMBER,
        !            63:        .description    = "Packets",
        !            64:        .rxid           = RTNL_LINK_RX_PACKETS,
        !            65:        .txid           = RTNL_LINK_TX_PACKETS,
        !            66: },
        !            67: {
        !            68:        .name           = "errors",
        !            69:        .type           = ATTR_TYPE_COUNTER,
        !            70:        .unit           = UNIT_NUMBER,
        !            71:        .description    = "Errors",
        !            72:        .rxid           = RTNL_LINK_RX_ERRORS,
        !            73:        .txid           = RTNL_LINK_TX_ERRORS,
        !            74: },
        !            75: {
        !            76:        .name           = "drop",
        !            77:        .type           = ATTR_TYPE_COUNTER,
        !            78:        .unit           = UNIT_NUMBER,
        !            79:        .description    = "Dropped",
        !            80:        .rxid           = RTNL_LINK_RX_DROPPED,
        !            81:        .txid           = RTNL_LINK_TX_DROPPED,
        !            82: },
        !            83: {
        !            84:        .name           = "compressed",
        !            85:        .type           = ATTR_TYPE_COUNTER,
        !            86:        .unit           = UNIT_NUMBER,
        !            87:        .description    = "Compressed",
        !            88:        .rxid           = RTNL_LINK_RX_COMPRESSED,
        !            89:        .txid           = RTNL_LINK_TX_COMPRESSED,
        !            90: },
        !            91: {
        !            92:        .name           = "fifoerr",
        !            93:        .type           = ATTR_TYPE_COUNTER,
        !            94:        .unit           = UNIT_NUMBER,
        !            95:        .description    = "FIFO Error",
        !            96:        .rxid           = RTNL_LINK_RX_FIFO_ERR,
        !            97:        .txid           = RTNL_LINK_TX_FIFO_ERR,
        !            98: },
        !            99: {
        !           100:        .name           = "lenerr",
        !           101:        .type           = ATTR_TYPE_COUNTER,
        !           102:        .unit           = UNIT_NUMBER,
        !           103:        .description    = "Length Error",
        !           104:        .rxid           = RTNL_LINK_RX_LEN_ERR,
        !           105:        .txid           = -1,
        !           106: },
        !           107: {
        !           108:        .name           = "overerr",
        !           109:        .type           = ATTR_TYPE_COUNTER,
        !           110:        .unit           = UNIT_NUMBER,
        !           111:        .description    = "Over Error",
        !           112:        .rxid           = RTNL_LINK_RX_OVER_ERR,
        !           113:        .txid           = -1,
        !           114: },
        !           115: {
        !           116:        .name           = "crcerr",
        !           117:        .type           = ATTR_TYPE_COUNTER,
        !           118:        .unit           = UNIT_NUMBER,
        !           119:        .description    = "CRC Error",
        !           120:        .rxid           = RTNL_LINK_RX_CRC_ERR,
        !           121:        .txid           = -1,
        !           122: },
        !           123: {
        !           124:        .name           = "frameerr",
        !           125:        .type           = ATTR_TYPE_COUNTER,
        !           126:        .unit           = UNIT_NUMBER,
        !           127:        .description    = "Frame Error",
        !           128:        .rxid           = RTNL_LINK_RX_FRAME_ERR,
        !           129:        .txid           = -1,
        !           130: },
        !           131: {
        !           132:        .name           = "misserr",
        !           133:        .type           = ATTR_TYPE_COUNTER,
        !           134:        .unit           = UNIT_NUMBER,
        !           135:        .description    = "Missed Error",
        !           136:        .rxid           = RTNL_LINK_RX_MISSED_ERR,
        !           137:        .txid           = -1,
        !           138: },
        !           139: {
        !           140:        .name           = "aborterr",
        !           141:        .type           = ATTR_TYPE_COUNTER,
        !           142:        .unit           = UNIT_NUMBER,
        !           143:        .description    = "Abort Error",
        !           144:        .rxid           = -1,
        !           145:        .txid           = RTNL_LINK_TX_ABORT_ERR,
        !           146: },
        !           147: {
        !           148:        .name           = "carrerr",
        !           149:        .type           = ATTR_TYPE_COUNTER,
        !           150:        .unit           = UNIT_NUMBER,
        !           151:        .description    = "Carrier Error",
        !           152:        .rxid           = -1,
        !           153:        .txid           = RTNL_LINK_TX_CARRIER_ERR,
        !           154: },
        !           155: {
        !           156:        .name           = "hbeaterr",
        !           157:        .type           = ATTR_TYPE_COUNTER,
        !           158:        .unit           = UNIT_NUMBER,
        !           159:        .description    = "Heartbeat Error",
        !           160:        .rxid           = -1,
        !           161:        .txid           = RTNL_LINK_TX_HBEAT_ERR,
        !           162: },
        !           163: {
        !           164:        .name           = "winerr",
        !           165:        .type           = ATTR_TYPE_COUNTER,
        !           166:        .unit           = UNIT_NUMBER,
        !           167:        .description    = "Window Error",
        !           168:        .rxid           = -1,
        !           169:        .txid           = RTNL_LINK_TX_WIN_ERR,
        !           170: },
        !           171: {
        !           172:        .name           = "coll",
        !           173:        .type           = ATTR_TYPE_COUNTER,
        !           174:        .unit           = UNIT_NUMBER,
        !           175:        .description    = "Collisions",
        !           176:        .rxid           = -1,
        !           177:        .txid           = RTNL_LINK_COLLISIONS,
        !           178: },
        !           179: {
        !           180:        .name           = "mcast",
        !           181:        .type           = ATTR_TYPE_COUNTER,
        !           182:        .unit           = UNIT_NUMBER,
        !           183:        .description    = "Multicast",
        !           184:        .rxid           = -1,
        !           185:        .txid           = RTNL_LINK_MULTICAST,
        !           186: },
        !           187: {
        !           188:        .name           = "ip6pkts",
        !           189:        .type           = ATTR_TYPE_COUNTER,
        !           190:        .unit           = UNIT_NUMBER,
        !           191:        .description    = "Ip6Pkts",
        !           192:        .rxid           = RTNL_LINK_IP6_INPKTS,
        !           193:        .txid           = RTNL_LINK_IP6_OUTPKTS,
        !           194: },
        !           195: {
        !           196:        .name           = "ip6discards",
        !           197:        .type           = ATTR_TYPE_COUNTER,
        !           198:        .unit           = UNIT_NUMBER,
        !           199:        .description    = "Ip6Discards",
        !           200:        .rxid           = RTNL_LINK_IP6_INDISCARDS,
        !           201:        .txid           = RTNL_LINK_IP6_OUTDISCARDS,
        !           202: },
        !           203: {
        !           204:        .name           = "ip6octets",
        !           205:        .type           = ATTR_TYPE_COUNTER,
        !           206:        .unit           = UNIT_BYTE,
        !           207:        .description    = "Ip6Octets",
        !           208:        .rxid           = RTNL_LINK_IP6_INOCTETS,
        !           209:        .txid           = RTNL_LINK_IP6_OUTOCTETS,
        !           210: },
        !           211: {
        !           212:        .name           = "ip6bcastp",
        !           213:        .type           = ATTR_TYPE_COUNTER,
        !           214:        .unit           = UNIT_NUMBER,
        !           215:        .description    = "Ip6 Broadcast Packets",
        !           216:        .rxid           = RTNL_LINK_IP6_INBCASTPKTS,
        !           217:        .txid           = RTNL_LINK_IP6_OUTBCASTPKTS,
        !           218: },
        !           219: {
        !           220:        .name           = "ip6bcast",
        !           221:        .type           = ATTR_TYPE_COUNTER,
        !           222:        .unit           = UNIT_BYTE,
        !           223:        .description    = "Ip6 Broadcast",
        !           224:        .rxid           = RTNL_LINK_IP6_INBCASTOCTETS,
        !           225:        .txid           = RTNL_LINK_IP6_OUTBCASTOCTETS,
        !           226: },
        !           227: {
        !           228:        .name           = "ip6mcastp",
        !           229:        .type           = ATTR_TYPE_COUNTER,
        !           230:        .unit           = UNIT_NUMBER,
        !           231:        .description    = "Ip6 Multicast Packets",
        !           232:        .rxid           = RTNL_LINK_IP6_INMCASTPKTS,
        !           233:        .txid           = RTNL_LINK_IP6_OUTMCASTPKTS,
        !           234: },
        !           235: {
        !           236:        .name           = "ip6mcast",
        !           237:        .type           = ATTR_TYPE_COUNTER,
        !           238:        .unit           = UNIT_BYTE,
        !           239:        .description    = "Ip6 Multicast",
        !           240:        .rxid           = RTNL_LINK_IP6_INMCASTOCTETS,
        !           241:        .txid           = RTNL_LINK_IP6_OUTMCASTOCTETS,
        !           242: },
        !           243: {
        !           244:        .name           = "ip6noroute",
        !           245:        .type           = ATTR_TYPE_COUNTER,
        !           246:        .unit           = UNIT_NUMBER,
        !           247:        .description    = "Ip6 No Route",
        !           248:        .rxid           = RTNL_LINK_IP6_INNOROUTES,
        !           249:        .txid           = RTNL_LINK_IP6_OUTNOROUTES,
        !           250: },
        !           251: {
        !           252:        .name           = "ip6forward",
        !           253:        .type           = ATTR_TYPE_COUNTER,
        !           254:        .unit           = UNIT_NUMBER,
        !           255:        .description    = "Ip6 Forwarded",
        !           256:        .rxid           = -1,
        !           257:        .txid           = RTNL_LINK_IP6_OUTFORWDATAGRAMS,
        !           258: },
        !           259: {
        !           260:        .name           = "ip6delivers",
        !           261:        .type           = ATTR_TYPE_COUNTER,
        !           262:        .unit           = UNIT_NUMBER,
        !           263:        .description    = "Ip6 Delivers",
        !           264:        .rxid           = RTNL_LINK_IP6_INDELIVERS,
        !           265:        .txid           = -1,
        !           266: },
        !           267: {
        !           268:        .name           = "icmp6",
        !           269:        .type           = ATTR_TYPE_COUNTER,
        !           270:        .unit           = UNIT_NUMBER,
        !           271:        .description    = "ICMPv6",
        !           272:        .rxid           = RTNL_LINK_ICMP6_INMSGS,
        !           273:        .txid           = RTNL_LINK_ICMP6_OUTMSGS,
        !           274: },
        !           275: {
        !           276:        .name           = "icmp6err",
        !           277:        .type           = ATTR_TYPE_COUNTER,
        !           278:        .unit           = UNIT_NUMBER,
        !           279:        .description    = "ICMPv6 Errors",
        !           280:        .rxid           = RTNL_LINK_ICMP6_INERRORS,
        !           281:        .txid           = RTNL_LINK_ICMP6_OUTERRORS,
        !           282: },
        !           283: {
        !           284:        .name           = "ip6inhdrerr",
        !           285:        .type           = ATTR_TYPE_COUNTER,
        !           286:        .unit           = UNIT_NUMBER,
        !           287:        .description    = "Ip6 Header Error",
        !           288:        .rxid           = RTNL_LINK_IP6_INHDRERRORS,
        !           289:        .txid           = -1,
        !           290: },
        !           291: {
        !           292:        .name           = "ip6toobigerr",
        !           293:        .type           = ATTR_TYPE_COUNTER,
        !           294:        .unit           = UNIT_NUMBER,
        !           295:        .description    = "Ip6 Too Big Error",
        !           296:        .rxid           = RTNL_LINK_IP6_INTOOBIGERRORS,
        !           297:        .txid           = -1,
        !           298: },
        !           299: {
        !           300:        .name           = "ip6trunc",
        !           301:        .type           = ATTR_TYPE_COUNTER,
        !           302:        .unit           = UNIT_NUMBER,
        !           303:        .description    = "Ip6 Truncated Packets",
        !           304:        .rxid           = RTNL_LINK_IP6_INTRUNCATEDPKTS,
        !           305:        .txid           = -1,
        !           306: },
        !           307: {
        !           308:        .name           = "ip6unkproto",
        !           309:        .type           = ATTR_TYPE_COUNTER,
        !           310:        .unit           = UNIT_NUMBER,
        !           311:        .description    = "Ip6 Unknown Protocol Error",
        !           312:        .rxid           = RTNL_LINK_IP6_INUNKNOWNPROTOS,
        !           313:        .txid           = -1,
        !           314: },
        !           315: {
        !           316:        .name           = "ip6addrerr",
        !           317:        .type           = ATTR_TYPE_COUNTER,
        !           318:        .unit           = UNIT_NUMBER,
        !           319:        .description    = "Ip6 Address Error",
        !           320:        .rxid           = RTNL_LINK_IP6_INADDRERRORS,
        !           321:        .txid           = -1,
        !           322: },
        !           323: {
        !           324:        .name           = "ip6reasmtimeo",
        !           325:        .type           = ATTR_TYPE_COUNTER,
        !           326:        .unit           = UNIT_NUMBER,
        !           327:        .description    = "Ip6 Reassembly Timeouts",
        !           328:        .rxid           = RTNL_LINK_IP6_REASMTIMEOUT,
        !           329:        .txid           = -1,
        !           330: },
        !           331: {
        !           332:        .name           = "ip6fragok",
        !           333:        .type           = ATTR_TYPE_COUNTER,
        !           334:        .unit           = UNIT_NUMBER,
        !           335:        .description    = "Ip6 Reasm/Frag OK",
        !           336:        .rxid           = RTNL_LINK_IP6_REASMOKS,
        !           337:        .txid           = RTNL_LINK_IP6_FRAGOKS,
        !           338: },
        !           339: {
        !           340:        .name           = "ip6fragfail",
        !           341:        .type           = ATTR_TYPE_COUNTER,
        !           342:        .unit           = UNIT_NUMBER,
        !           343:        .description    = "Ip6 Reasm/Frag Failures",
        !           344:        .rxid           = RTNL_LINK_IP6_REASMFAILS,
        !           345:        .txid           = RTNL_LINK_IP6_FRAGFAILS,
        !           346: },
        !           347: {
        !           348:        .name           = "ip6fragcreate",
        !           349:        .type           = ATTR_TYPE_COUNTER,
        !           350:        .unit           = UNIT_NUMBER,
        !           351:        .description    = "Ip6 Reasm/Frag Requests",
        !           352:        .rxid           = RTNL_LINK_IP6_REASMREQDS,
        !           353:        .txid           = RTNL_LINK_IP6_FRAGCREATES,
        !           354: }
        !           355: };
1.1       misho     356: 
1.1.1.2 ! misho     357: static struct attr_map tc_attrs[] = {
        !           358: {
        !           359:        .name           = "tc_bytes",
        !           360:        .type           = ATTR_TYPE_COUNTER,
        !           361:        .unit           = UNIT_BYTE,
        !           362:        .description    = "Bytes",
        !           363:        .rxid           = -1,
        !           364:        .txid           = RTNL_TC_BYTES,
        !           365: },
        !           366: {
        !           367:        .name           = "tc_packets",
        !           368:        .type           = ATTR_TYPE_COUNTER,
        !           369:        .unit           = UNIT_NUMBER,
        !           370:        .description    = "Packets",
        !           371:        .rxid           = -1,
        !           372:        .txid           = RTNL_TC_PACKETS,
        !           373: },
        !           374: {
        !           375:        .name           = "tc_overlimits",
        !           376:        .type           = ATTR_TYPE_COUNTER,
        !           377:        .unit           = UNIT_NUMBER,
        !           378:        .description    = "Overlimits",
        !           379:        .rxid           = -1,
        !           380:        .txid           = RTNL_TC_OVERLIMITS,
        !           381: },
        !           382: {
        !           383:        .name           = "tc_drop",
        !           384:        .type           = ATTR_TYPE_COUNTER,
        !           385:        .unit           = UNIT_NUMBER,
        !           386:        .description    = "Dropped",
        !           387:        .rxid           = -1,
        !           388:        .txid           = RTNL_TC_DROPS,
        !           389: },
        !           390: {
        !           391:        .name           = "tc_bps",
        !           392:        .type           = ATTR_TYPE_RATE,
        !           393:        .unit           = UNIT_BYTE,
        !           394:        .description    = "Byte Rate/s",
        !           395:        .rxid           = -1,
        !           396:        .txid           = RTNL_TC_RATE_BPS,
        !           397: },
        !           398: {
        !           399:        .name           = "tc_pps",
        !           400:        .type           = ATTR_TYPE_RATE,
        !           401:        .unit           = UNIT_NUMBER,
        !           402:        .description    = "Packet Rate/s",
        !           403:        .rxid           = -1,
        !           404:        .txid           = RTNL_TC_RATE_PPS,
        !           405: },
        !           406: {
        !           407:        .name           = "tc_qlen",
        !           408:        .type           = ATTR_TYPE_RATE,
        !           409:        .unit           = UNIT_NUMBER,
        !           410:        .description    = "Queue Length",
        !           411:        .rxid           = -1,
        !           412:        .txid           = RTNL_TC_QLEN,
        !           413: },
        !           414: {
        !           415:        .name           = "tc_backlog",
        !           416:        .type           = ATTR_TYPE_RATE,
        !           417:        .unit           = UNIT_NUMBER,
        !           418:        .description    = "Backlog",
        !           419:        .rxid           = -1,
        !           420:        .txid           = RTNL_TC_BACKLOG,
        !           421: },
        !           422: {
        !           423:        .name           = "tc_requeues",
        !           424:        .type           = ATTR_TYPE_COUNTER,
        !           425:        .unit           = UNIT_NUMBER,
        !           426:        .description    = "Requeues",
        !           427:        .rxid           = -1,
        !           428:        .txid           = RTNL_TC_REQUEUES,
        !           429: }
        !           430: };
        !           431: 
        !           432: struct rdata {
        !           433:        struct element *        parent;
        !           434:        int                     level;
1.1       misho     435: };
                    436: 
1.1.1.2 ! misho     437: static struct nl_sock *sock;
        !           438: static struct nl_cache *link_cache, *qdisc_cache, *class_cache;
        !           439: 
        !           440: static void update_tc_attrs(struct element *e, struct rtnl_tc *tc)
1.1       misho     441: {
1.1.1.2 ! misho     442:        int i;
1.1       misho     443: 
1.1.1.2 ! misho     444:        for (i = 0; i < ARRAY_SIZE(tc_attrs); i++) {
        !           445:                uint64_t c_tx = rtnl_tc_get_stat(tc, tc_attrs[i].txid);
        !           446:                attr_update(e, tc_attrs[i].attrid, 0, c_tx, UPDATE_FLAG_TX);
        !           447:        }
        !           448: }
1.1       misho     449: 
1.1.1.2 ! misho     450: static void update_tc_infos(struct element *e, struct rtnl_tc *tc)
        !           451: {
        !           452:        char buf[64];
1.1       misho     453: 
1.1.1.2 ! misho     454:        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mtu(tc));
        !           455:        element_update_info(e, "MTU", buf);
1.1       misho     456: 
1.1.1.2 ! misho     457:        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mpu(tc));
        !           458:        element_update_info(e, "MPU", buf);
1.1       misho     459: 
1.1.1.2 ! misho     460:        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_overhead(tc));
        !           461:        element_update_info(e, "Overhead", buf);
1.1       misho     462: 
1.1.1.2 ! misho     463:        snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_handle(tc));
        !           464:        element_update_info(e, "Id", buf);
1.1       misho     465: 
1.1.1.2 ! misho     466:        snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_parent(tc));
        !           467:        element_update_info(e, "Parent", buf);
1.1       misho     468: 
                    469: }
                    470: 
1.1.1.2 ! misho     471: static void handle_qdisc(struct nl_object *obj, void *);
        !           472: static void find_classes(uint32_t, struct rdata *);
        !           473: static void find_qdiscs(uint32_t, struct rdata *);
        !           474: 
        !           475: static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
        !           476:                                     struct rdata *rdata)
1.1       misho     477: {
1.1.1.2 ! misho     478:        char buf[IFNAME_MAX], name[IFNAME_MAX];
        !           479:        uint32_t id = rtnl_tc_get_handle(tc);
        !           480:        struct element *e;
        !           481: 
        !           482:        rtnl_tc_handle2str(id, buf, sizeof(buf));
        !           483:        snprintf(name, sizeof(name), "%s %s (%s)",
        !           484:                 prefix, buf, rtnl_tc_get_kind(tc));
        !           485: 
        !           486:        if (!(e = element_lookup(grp, name, id, rdata ? rdata->parent : NULL, ELEMENT_CREAT)))
        !           487:                return NULL;
        !           488: 
        !           489:        if (e->e_flags & ELEMENT_FLAG_CREATED) {
        !           490:                e->e_level = rdata ? rdata->level : 0;
1.1       misho     491: 
1.1.1.2 ! misho     492:                if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
        !           493:                    element_set_usage_attr(e, "tc_bytes"))
        !           494:                        BUG();
1.1       misho     495: 
1.1.1.2 ! misho     496:                update_tc_infos(e, tc);
        !           497: 
        !           498:                e->e_flags &= ~ELEMENT_FLAG_CREATED;
        !           499:        }
        !           500: 
        !           501:        update_tc_attrs(e, tc);
        !           502: 
        !           503:        element_notify_update(e, NULL);
        !           504:        element_lifesign(e, 1);
        !           505: 
        !           506:        return e;
1.1       misho     507: }
                    508: 
1.1.1.2 ! misho     509: static void handle_cls(struct nl_object *obj, void *arg)
        !           510: {
        !           511:        struct rtnl_cls *cls = (struct rtnl_cls *) obj;
        !           512:        struct rdata *rdata = arg;
        !           513: 
        !           514:        handle_tc_obj((struct rtnl_tc *) cls, "cls", rdata);
        !           515: }
1.1       misho     516: 
1.1.1.2 ! misho     517: static void handle_class(struct nl_object *obj, void *arg)
1.1       misho     518: {
1.1.1.2 ! misho     519:        struct rtnl_tc *tc = (struct rtnl_tc *) obj;
        !           520:        struct element *e;
        !           521:        struct rdata *rdata = arg;
        !           522:        struct rdata ndata = {
        !           523:                .level = rdata->level + 1,
        !           524:        };
1.1       misho     525: 
1.1.1.2 ! misho     526:        if (!(e = handle_tc_obj(tc, "class", rdata)))
        !           527:                return;
1.1       misho     528: 
1.1.1.2 ! misho     529:        ndata.parent = e;
1.1       misho     530: 
1.1.1.2 ! misho     531:        if (!strcmp(rtnl_tc_get_kind(tc), "htb"))
        !           532:                element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc));
1.1       misho     533: 
1.1.1.2 ! misho     534:        find_classes(rtnl_tc_get_handle(tc), &ndata);
        !           535:        find_qdiscs(rtnl_tc_get_handle(tc), &ndata);
        !           536: }
        !           537: 
        !           538: static void find_qdiscs(uint32_t parent, struct rdata *rdata)
        !           539: {
        !           540:        struct rtnl_qdisc *filter;
        !           541: 
        !           542:        if (!(filter = rtnl_qdisc_alloc()))
1.1       misho     543:                return;
                    544: 
1.1.1.2 ! misho     545:        rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
1.1       misho     546: 
1.1.1.2 ! misho     547:        nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
        !           548:                                handle_qdisc, rdata);
1.1       misho     549: 
1.1.1.2 ! misho     550:        rtnl_qdisc_put(filter);
1.1       misho     551: }
                    552: 
1.1.1.2 ! misho     553: static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata)
1.1       misho     554: {
1.1.1.2 ! misho     555:        struct nl_cache *cls_cache;
        !           556: 
        !           557:        if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
        !           558:                return;
        !           559: 
        !           560:        nl_cache_foreach(cls_cache, handle_cls, rdata);
1.1       misho     561: 
1.1.1.2 ! misho     562:        nl_cache_free(cls_cache);
        !           563: }
1.1       misho     564: 
1.1.1.2 ! misho     565: static void find_classes(uint32_t parent, struct rdata *rdata)
        !           566: {
        !           567:        struct rtnl_class *filter;
1.1       misho     568: 
1.1.1.2 ! misho     569:        if (!(filter = rtnl_class_alloc()))
1.1       misho     570:                return;
                    571: 
1.1.1.2 ! misho     572:        rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
1.1       misho     573: 
1.1.1.2 ! misho     574:        nl_cache_foreach_filter(class_cache, OBJ_CAST(filter),
        !           575:                                handle_class, rdata);
        !           576: 
        !           577:        rtnl_class_put(filter);
1.1       misho     578: }
                    579: 
1.1.1.2 ! misho     580: static void handle_qdisc(struct nl_object *obj, void *arg)
1.1       misho     581: {
1.1.1.2 ! misho     582:        struct rtnl_tc *tc = (struct rtnl_tc *) obj;
        !           583:        struct element *e;
        !           584:        struct rdata *rdata = arg;
        !           585:        struct rdata ndata = {
        !           586:                .level = rdata->level + 1,
1.1       misho     587:        };
                    588: 
1.1.1.2 ! misho     589:        if (!(e = handle_tc_obj(tc, "qdisc", rdata)))
1.1       misho     590:                return;
                    591: 
1.1.1.2 ! misho     592:        ndata.parent = e;
1.1       misho     593: 
1.1.1.2 ! misho     594:        find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);
        !           595: 
        !           596:        if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
        !           597:                find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata);
        !           598:                find_classes(TC_H_ROOT, &ndata);
        !           599:        }
        !           600: 
        !           601:        find_classes(rtnl_tc_get_handle(tc), &ndata);
1.1       misho     602: }
                    603: 
1.1.1.2 ! misho     604: static void handle_tc(struct element *e, struct rtnl_link *link)
1.1       misho     605: {
                    606:        struct rtnl_qdisc *qdisc;
1.1.1.2 ! misho     607:        int ifindex = rtnl_link_get_ifindex(link);
        !           608:        struct rdata rdata = {
1.1       misho     609:                .level = 1,
1.1.1.2 ! misho     610:                .parent = e,
1.1       misho     611:        };
                    612: 
1.1.1.2 ! misho     613:        if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
1.1       misho     614:                return;
                    615: 
1.1.1.2 ! misho     616:        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
        !           617:        if (qdisc) {
        !           618:                handle_qdisc(OBJ_CAST(qdisc), &rdata);
        !           619:                rtnl_qdisc_put(qdisc);
        !           620:        }
        !           621: 
        !           622:        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
        !           623:        if (qdisc) {
        !           624:                handle_qdisc(OBJ_CAST(qdisc), &rdata);
        !           625:                rtnl_qdisc_put(qdisc);
        !           626:        }
        !           627: 
        !           628:        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
        !           629:        if (qdisc) {
        !           630:                handle_qdisc(OBJ_CAST(qdisc), &rdata);
        !           631:                rtnl_qdisc_put(qdisc);
        !           632:        }
        !           633: 
        !           634:        nl_cache_free(class_cache);
        !           635: }
        !           636: 
        !           637: static void update_link_infos(struct element *e, struct rtnl_link *link)
        !           638: {
        !           639:        char buf[64];
        !           640: 
        !           641:        snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link));
        !           642:        element_update_info(e, "MTU", buf);
        !           643: 
        !           644:        rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf));
        !           645:        element_update_info(e, "Flags", buf);
        !           646: 
        !           647:        rtnl_link_operstate2str(rtnl_link_get_operstate(link),
        !           648:                                buf, sizeof(buf));
        !           649:        element_update_info(e, "Operstate", buf);
        !           650: 
        !           651:        snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link));
        !           652:        element_update_info(e, "IfIndex", buf);
        !           653: 
        !           654:        nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf));
        !           655:        element_update_info(e, "Address", buf);
        !           656: 
        !           657:        nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf));
        !           658:        element_update_info(e, "Broadcast", buf);
        !           659: 
        !           660:        rtnl_link_mode2str(rtnl_link_get_linkmode(link),
        !           661:                           buf, sizeof(buf));
        !           662:        element_update_info(e, "Mode", buf);
        !           663: 
        !           664:        snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link));
        !           665:        element_update_info(e, "TXQlen", buf);
1.1       misho     666: 
1.1.1.2 ! misho     667:        nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf));
        !           668:        element_update_info(e, "Family", buf);
1.1       misho     669: 
1.1.1.2 ! misho     670:        element_update_info(e, "Alias",
        !           671:                rtnl_link_get_ifalias(link) ? : "");
        !           672: 
        !           673:        element_update_info(e, "Qdisc",
        !           674:                rtnl_link_get_qdisc(link) ? : "");
        !           675: 
        !           676:        if (rtnl_link_get_link(link)) {
        !           677:                snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link));
        !           678:                element_update_info(e, "SlaveOfIndex", buf);
        !           679:        }
1.1       misho     680: }
                    681: 
1.1.1.2 ! misho     682: static void do_link(struct nl_object *obj, void *arg)
1.1       misho     683: {
1.1.1.2 ! misho     684:        struct rtnl_link *link = (struct rtnl_link *) obj;
        !           685:        struct element *e, *e_parent = NULL;
        !           686:        int i, master_ifindex;
1.1       misho     687: 
1.1.1.2 ! misho     688:        if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) {
        !           689:                /* FIXME: delete element */
1.1       misho     690:                return;
1.1.1.2 ! misho     691:        }
1.1       misho     692: 
1.1.1.2 ! misho     693:        /* Check if the interface is a slave of another interface */
        !           694:        if ((master_ifindex = rtnl_link_get_link(link))) {
        !           695:                char parent[IFNAMSIZ+1];
        !           696: 
        !           697:                rtnl_link_i2name(link_cache, master_ifindex,
        !           698:                                 parent, sizeof(parent));
1.1       misho     699: 
1.1.1.2 ! misho     700:                e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0);
        !           701:        }
1.1       misho     702: 
1.1.1.2 ! misho     703:        if (!(e = element_lookup(grp, rtnl_link_get_name(link),
        !           704:                                 rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT)))
1.1       misho     705:                return;
                    706: 
1.1.1.2 ! misho     707:        if (e->e_flags & ELEMENT_FLAG_CREATED) {
        !           708:                if (e->e_parent)
        !           709:                        e->e_level = e->e_parent->e_level + 1;
        !           710: 
        !           711:                if (element_set_key_attr(e, "bytes", "packets") ||
        !           712:                    element_set_usage_attr(e, "bytes"))
        !           713:                        BUG();
1.1       misho     714: 
1.1.1.2 ! misho     715:                /* FIXME: Update link infos every 1s or so */
        !           716:                update_link_infos(e, link);
        !           717: 
        !           718:                e->e_flags &= ~ELEMENT_FLAG_CREATED;
        !           719:        }
        !           720: 
        !           721:        for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
        !           722:                struct attr_map *m = &link_attrs[i];
        !           723:                uint64_t c_rx = 0, c_tx = 0;
        !           724:                int flags = 0;
        !           725: 
        !           726:                if (m->rxid >= 0) {
        !           727:                        c_rx = rtnl_link_get_stat(link, m->rxid);
        !           728:                        flags |= UPDATE_FLAG_RX;
        !           729:                }
        !           730: 
        !           731:                if (m->txid >= 0) {
        !           732:                        c_tx = rtnl_link_get_stat(link, m->txid);
        !           733:                        flags |= UPDATE_FLAG_TX;
        !           734:                }
1.1       misho     735: 
1.1.1.2 ! misho     736:                attr_update(e, m->attrid, c_rx, c_tx, flags);
        !           737:        }
1.1       misho     738: 
                    739:        if (!c_notc)
1.1.1.2 ! misho     740:                handle_tc(e, link);
        !           741: 
        !           742:        element_notify_update(e, NULL);
        !           743:        element_lifesign(e, 1);
1.1       misho     744: }
                    745: 
                    746: static void netlink_read(void)
                    747: {
1.1.1.2 ! misho     748:        int err;
1.1       misho     749: 
1.1.1.2 ! misho     750:        if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) {
        !           751:                fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err));
        !           752:                goto disable;
1.1       misho     753:        }
                    754: 
1.1.1.2 ! misho     755:        if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
        !           756:                fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err));
        !           757:                goto disable;
        !           758:        }
        !           759: 
        !           760:        nl_cache_foreach(link_cache, do_link, NULL);
        !           761: 
        !           762:        return;
        !           763: 
        !           764: disable:
        !           765:        netlink_ops.m_flags &= ~BMON_MODULE_ENABLED;
1.1       misho     766: }
                    767: 
                    768: static void netlink_shutdown(void)
                    769: {
1.1.1.2 ! misho     770:        nl_cache_free(link_cache);
        !           771:        nl_cache_free(qdisc_cache);
        !           772:        nl_socket_free(sock);
1.1       misho     773: }
                    774: 
1.1.1.2 ! misho     775: static int netlink_do_init(void)
1.1       misho     776: {
1.1.1.2 ! misho     777:        int err, i;
        !           778: 
        !           779:        if (!(sock = nl_socket_alloc())) {
        !           780:                fprintf(stderr, "Unable to allocate netlink socket\n");
        !           781:                goto disable;
        !           782:        }
        !           783: 
        !           784:        if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0) {
        !           785:                fprintf(stderr, "Unable to connect netlink socket: %s\n", nl_geterror(err));
        !           786:                goto disable;
        !           787:        }
        !           788: 
        !           789:        if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
        !           790:                fprintf(stderr, "Unable to allocate link cache: %s\n", nl_geterror(err));
        !           791:                goto disable;
        !           792:        }
        !           793: 
        !           794:        if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) {
        !           795:                fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err));
        !           796:                goto disable;
        !           797:        }
        !           798: 
        !           799:        if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) ||
        !           800:            attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs)))
        !           801:                BUG();
1.1       misho     802: 
1.1.1.2 ! misho     803:        if (!(grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE)))
        !           804:                BUG();
        !           805: 
        !           806:        return 0;
        !           807: 
        !           808: disable:
        !           809:        return -EOPNOTSUPP;
1.1       misho     810: }
                    811: 
                    812: static int netlink_probe(void)
                    813: {
1.1.1.2 ! misho     814:        struct nl_sock *sock;
        !           815:        struct nl_cache *lc;
        !           816:        int ret = 0;
        !           817: 
        !           818:        if (!(sock = nl_socket_alloc()))
1.1       misho     819:                return 0;
                    820:        
1.1.1.2 ! misho     821:        if (nl_connect(sock, NETLINK_ROUTE) < 0)
1.1       misho     822:                return 0;
1.1.1.2 ! misho     823:        
        !           824:        if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &lc) == 0) {
        !           825:                nl_cache_free(lc);
        !           826:                ret = 1;
1.1       misho     827:        }
                    828: 
1.1.1.2 ! misho     829:        nl_socket_free(sock);
1.1       misho     830:        
1.1.1.2 ! misho     831:        return ret;
1.1       misho     832: }
                    833: 
                    834: static void print_help(void)
                    835: {
                    836:        printf(
                    837:        "netlink - Netlink statistic collector for Linux\n" \
                    838:        "\n" \
                    839:        "  Powerful statistic collector for Linux using netlink sockets\n" \
                    840:        "  to collect link and traffic control statistics.\n" \
                    841:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
                    842:        "\n" \
                    843:        "  Options:\n" \
1.1.1.2 ! misho     844:        "    notc           Do not collect traffic control statistics\n");
1.1       misho     845: }
                    846: 
1.1.1.2 ! misho     847: static void netlink_parse_opt(const char *type, const char *value)
        !           848: {
        !           849:        if (!strcasecmp(type, "notc"))
        !           850:                c_notc = 1;
        !           851:        else if (!strcasecmp(type, "help")) {
        !           852:                print_help();
        !           853:                exit(0);
1.1       misho     854:        }
                    855: }
                    856: 
1.1.1.2 ! misho     857: static struct bmon_module netlink_ops = {
        !           858:        .m_name         = "netlink",
        !           859:        .m_flags        = BMON_MODULE_DEFAULT,
        !           860:        .m_do           = netlink_read,
        !           861:        .m_shutdown     = netlink_shutdown,
        !           862:        .m_parse_opt    = netlink_parse_opt,
        !           863:        .m_probe        = netlink_probe,
        !           864:        .m_init         = netlink_do_init,
1.1       misho     865: };
                    866: 
                    867: static void __init netlink_init(void)
                    868: {
1.1.1.2 ! misho     869:        input_register(&netlink_ops);
1.1       misho     870: }
                    871: #endif

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