Diff for /embedaddon/bmon/src/in_netlink.c between versions 1.1 and 1.1.1.2

version 1.1, 2012/02/21 22:19:56 version 1.1.1.2, 2014/07/30 07:55:27
Line 1 Line 1
 /*  /*
 * in_netlink.c            rtnetlink input (Linux) * in_netlink.c            Netlink input
  *   *
 * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2013 Red Hat, Inc.
  *   *
  * Permission is hereby granted, free of charge, to any person obtaining a   * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),   * copy of this software and associated documentation files (the "Software"),
Line 24 Line 25
   
 #include <bmon/bmon.h>  #include <bmon/bmon.h>
 #include <bmon/input.h>  #include <bmon/input.h>
#include <bmon/node.h>#include <bmon/element.h>
#include <bmon/item.h>#include <bmon/attr.h>
 #include <bmon/conf.h>  #include <bmon/conf.h>
   #include <bmon/input.h>
 #include <bmon/utils.h>  #include <bmon/utils.h>
   
#if defined HAVE_NL && defined SYS_LINUX#ifndef SYS_BSD
   
 static int c_notc = 0;  static int c_notc = 0;
static const char *c_mapfile;static struct element_group *grp;
 static struct bmon_module netlink_ops;
   
 struct hmap {  
         char *id;  
         char *name;  
         struct hmap *next;  
 };  
   
 static struct hmap *map;  
   
 #include <netlink/netlink.h>  #include <netlink/netlink.h>
 #include <netlink/cache.h>  #include <netlink/cache.h>
#include <netlink/helpers.h>#include <netlink/utils.h>
 #include <netlink/route/link.h>  #include <netlink/route/link.h>
   #include <netlink/route/tc.h>
 #include <netlink/route/qdisc.h>  #include <netlink/route/qdisc.h>
 #include <netlink/route/class.h>  #include <netlink/route/class.h>
#include <netlink/route/filter.h>#include <netlink/route/classifier.h>
 #include <netlink/route/qdisc/htb.h>
   
#include <net/if.h>static struct attr_map link_attrs[] = {
 {
         .name           = "bytes",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_BYTE,
         .description    = "Bytes",
         .rxid           = RTNL_LINK_RX_BYTES,
         .txid           = RTNL_LINK_TX_BYTES,
 },
 {
         .name           = "packets",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Packets",
         .rxid           = RTNL_LINK_RX_PACKETS,
         .txid           = RTNL_LINK_TX_PACKETS,
 },
 {
         .name           = "errors",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Errors",
         .rxid           = RTNL_LINK_RX_ERRORS,
         .txid           = RTNL_LINK_TX_ERRORS,
 },
 {
         .name           = "drop",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Dropped",
         .rxid           = RTNL_LINK_RX_DROPPED,
         .txid           = RTNL_LINK_TX_DROPPED,
 },
 {
         .name           = "compressed",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Compressed",
         .rxid           = RTNL_LINK_RX_COMPRESSED,
         .txid           = RTNL_LINK_TX_COMPRESSED,
 },
 {
         .name           = "fifoerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "FIFO Error",
         .rxid           = RTNL_LINK_RX_FIFO_ERR,
         .txid           = RTNL_LINK_TX_FIFO_ERR,
 },
 {
         .name           = "lenerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Length Error",
         .rxid           = RTNL_LINK_RX_LEN_ERR,
         .txid           = -1,
 },
 {
         .name           = "overerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Over Error",
         .rxid           = RTNL_LINK_RX_OVER_ERR,
         .txid           = -1,
 },
 {
         .name           = "crcerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "CRC Error",
         .rxid           = RTNL_LINK_RX_CRC_ERR,
         .txid           = -1,
 },
 {
         .name           = "frameerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Frame Error",
         .rxid           = RTNL_LINK_RX_FRAME_ERR,
         .txid           = -1,
 },
 {
         .name           = "misserr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Missed Error",
         .rxid           = RTNL_LINK_RX_MISSED_ERR,
         .txid           = -1,
 },
 {
         .name           = "aborterr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Abort Error",
         .rxid           = -1,
         .txid           = RTNL_LINK_TX_ABORT_ERR,
 },
 {
         .name           = "carrerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Carrier Error",
         .rxid           = -1,
         .txid           = RTNL_LINK_TX_CARRIER_ERR,
 },
 {
         .name           = "hbeaterr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Heartbeat Error",
         .rxid           = -1,
         .txid           = RTNL_LINK_TX_HBEAT_ERR,
 },
 {
         .name           = "winerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Window Error",
         .rxid           = -1,
         .txid           = RTNL_LINK_TX_WIN_ERR,
 },
 {
         .name           = "coll",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Collisions",
         .rxid           = -1,
         .txid           = RTNL_LINK_COLLISIONS,
 },
 {
         .name           = "mcast",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Multicast",
         .rxid           = -1,
         .txid           = RTNL_LINK_MULTICAST,
 },
 {
         .name           = "ip6pkts",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6Pkts",
         .rxid           = RTNL_LINK_IP6_INPKTS,
         .txid           = RTNL_LINK_IP6_OUTPKTS,
 },
 {
         .name           = "ip6discards",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6Discards",
         .rxid           = RTNL_LINK_IP6_INDISCARDS,
         .txid           = RTNL_LINK_IP6_OUTDISCARDS,
 },
 {
         .name           = "ip6octets",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_BYTE,
         .description    = "Ip6Octets",
         .rxid           = RTNL_LINK_IP6_INOCTETS,
         .txid           = RTNL_LINK_IP6_OUTOCTETS,
 },
 {
         .name           = "ip6bcastp",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Broadcast Packets",
         .rxid           = RTNL_LINK_IP6_INBCASTPKTS,
         .txid           = RTNL_LINK_IP6_OUTBCASTPKTS,
 },
 {
         .name           = "ip6bcast",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_BYTE,
         .description    = "Ip6 Broadcast",
         .rxid           = RTNL_LINK_IP6_INBCASTOCTETS,
         .txid           = RTNL_LINK_IP6_OUTBCASTOCTETS,
 },
 {
         .name           = "ip6mcastp",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Multicast Packets",
         .rxid           = RTNL_LINK_IP6_INMCASTPKTS,
         .txid           = RTNL_LINK_IP6_OUTMCASTPKTS,
 },
 {
         .name           = "ip6mcast",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_BYTE,
         .description    = "Ip6 Multicast",
         .rxid           = RTNL_LINK_IP6_INMCASTOCTETS,
         .txid           = RTNL_LINK_IP6_OUTMCASTOCTETS,
 },
 {
         .name           = "ip6noroute",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 No Route",
         .rxid           = RTNL_LINK_IP6_INNOROUTES,
         .txid           = RTNL_LINK_IP6_OUTNOROUTES,
 },
 {
         .name           = "ip6forward",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Forwarded",
         .rxid           = -1,
         .txid           = RTNL_LINK_IP6_OUTFORWDATAGRAMS,
 },
 {
         .name           = "ip6delivers",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Delivers",
         .rxid           = RTNL_LINK_IP6_INDELIVERS,
         .txid           = -1,
 },
 {
         .name           = "icmp6",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "ICMPv6",
         .rxid           = RTNL_LINK_ICMP6_INMSGS,
         .txid           = RTNL_LINK_ICMP6_OUTMSGS,
 },
 {
         .name           = "icmp6err",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "ICMPv6 Errors",
         .rxid           = RTNL_LINK_ICMP6_INERRORS,
         .txid           = RTNL_LINK_ICMP6_OUTERRORS,
 },
 {
         .name           = "ip6inhdrerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Header Error",
         .rxid           = RTNL_LINK_IP6_INHDRERRORS,
         .txid           = -1,
 },
 {
         .name           = "ip6toobigerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Too Big Error",
         .rxid           = RTNL_LINK_IP6_INTOOBIGERRORS,
         .txid           = -1,
 },
 {
         .name           = "ip6trunc",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Truncated Packets",
         .rxid           = RTNL_LINK_IP6_INTRUNCATEDPKTS,
         .txid           = -1,
 },
 {
         .name           = "ip6unkproto",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Unknown Protocol Error",
         .rxid           = RTNL_LINK_IP6_INUNKNOWNPROTOS,
         .txid           = -1,
 },
 {
         .name           = "ip6addrerr",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Address Error",
         .rxid           = RTNL_LINK_IP6_INADDRERRORS,
         .txid           = -1,
 },
 {
         .name           = "ip6reasmtimeo",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Reassembly Timeouts",
         .rxid           = RTNL_LINK_IP6_REASMTIMEOUT,
         .txid           = -1,
 },
 {
         .name           = "ip6fragok",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Reasm/Frag OK",
         .rxid           = RTNL_LINK_IP6_REASMOKS,
         .txid           = RTNL_LINK_IP6_FRAGOKS,
 },
 {
         .name           = "ip6fragfail",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Reasm/Frag Failures",
         .rxid           = RTNL_LINK_IP6_REASMFAILS,
         .txid           = RTNL_LINK_IP6_FRAGFAILS,
 },
 {
         .name           = "ip6fragcreate",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Ip6 Reasm/Frag Requests",
         .rxid           = RTNL_LINK_IP6_REASMREQDS,
         .txid           = RTNL_LINK_IP6_FRAGCREATES,
 }
 };
   
static struct nl_handle nl_h = NL_INIT_HANDLE();static struct attr_map tc_attrs[] = {
static struct nl_cache link_cache = RTNL_INIT_LINK_CACHE();{
static struct nl_cache *qdisc_cache;        .name           = "tc_bytes",
static struct nl_cache *class_cache;        .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_BYTE,
         .description    = "Bytes",
         .rxid           = -1,
         .txid                = RTNL_TC_BYTES,
 },
 {
         .name           = "tc_packets",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Packets",
         .rxid           = -1,
         .txid           = RTNL_TC_PACKETS,
 },
 {
         .name           = "tc_overlimits",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Overlimits",
         .rxid           = -1,
         .txid           = RTNL_TC_OVERLIMITS,
 },
 {
         .name           = "tc_drop",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Dropped",
         .rxid           = -1,
         .txid           = RTNL_TC_DROPS,
 },
 {
         .name           = "tc_bps",
         .type           = ATTR_TYPE_RATE,
         .unit           = UNIT_BYTE,
         .description    = "Byte Rate/s",
         .rxid           = -1,
         .txid           = RTNL_TC_RATE_BPS,
 },
 {
         .name           = "tc_pps",
         .type           = ATTR_TYPE_RATE,
         .unit           = UNIT_NUMBER,
         .description    = "Packet Rate/s",
         .rxid           = -1,
         .txid           = RTNL_TC_RATE_PPS,
 },
 {
         .name           = "tc_qlen",
         .type           = ATTR_TYPE_RATE,
         .unit           = UNIT_NUMBER,
         .description    = "Queue Length",
         .rxid           = -1,
         .txid           = RTNL_TC_QLEN,
 },
 {
         .name           = "tc_backlog",
         .type           = ATTR_TYPE_RATE,
         .unit           = UNIT_NUMBER,
         .description    = "Backlog",
         .rxid           = -1,
         .txid           = RTNL_TC_BACKLOG,
 },
 {
         .name           = "tc_requeues",
         .type           = ATTR_TYPE_COUNTER,
         .unit           = UNIT_NUMBER,
         .description    = "Requeues",
         .rxid           = -1,
         .txid           = RTNL_TC_REQUEUES,
 }
 };
   
struct xdata {struct rdata {
        item_t *intf;        struct element *        parent;
        struct rtnl_link *link;        int                     level;
        int level; 
        item_t *parent; 
 };  };
   
static void read_map(const char *file)static struct nl_sock *sock;
 static struct nl_cache *link_cache, *qdisc_cache, *class_cache;
 
 static void update_tc_attrs(struct element *e, struct rtnl_tc *tc)
 {  {
        FILE *f;        int i;
        char buf[1024]; 
        int line = 0; 
   
        f = fopen(file, "r");        for (i = 0; i < ARRAY_SIZE(tc_attrs); i++) {
        if (f == NULL)                uint64_t c_tx = rtnl_tc_get_stat(tc, tc_attrs[i].txid);
                quit("Could not open mapfile %s: %s\n", file, strerror(errno));                attr_update(e, tc_attrs[i].attrid, 0, c_tx, UPDATE_FLAG_TX);
         }
 }
   
        while (fgets(buf, sizeof(buf), f)) {static void update_tc_infos(struct element *e, struct rtnl_tc *tc)
                struct hmap *m;{
                char *p, *id, *name;        char buf[64];
                line++; 
                if (*buf == '#' || *buf == '\r' || *buf == '\n') 
                        continue; 
   
                for (p = buf; *p == ' ' || *p == '\t'; p++);        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mtu(tc));
                if (*p == '\0')        element_update_info(e, "MTU", buf);
                        quit("%s: Parse error at line %d: Missing handle\n", 
                            file, line); 
                id = p; 
   
                for (; *p != ' ' && *p != '\t' && *p != '\0'; p++);        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mpu(tc));
                if (*p == '\0')        element_update_info(e, "MPU", buf);
                        quit("%s: Parse error at line %d: Missing name\n", 
                            file, line); 
                *p = '\0'; 
   
                for (++p; *p == ' ' || *p == '\t'; p++);        snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_overhead(tc));
                name = p;        element_update_info(e, "Overhead", buf);
                for (; *p != ' ' && *p != '\t' && *p != '\0' && 
                       *p != '\r' && *p != '\n'; p++); 
                *p = '\0'; 
   
                if (strlen(id) <= 0 || strlen(name) <= 0)        snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_handle(tc));
                        quit("%s: Parse error at line %d: Invalid id or handle\n",        element_update_info(e, "Id", buf);
                            file, line); 
   
                m = xcalloc(1, sizeof(*m));        snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_parent(tc));
                m->id = strdup(id);        element_update_info(e, "Parent", buf);
                m->name = strdup(name); 
                m->next = map; 
                map = m; 
        } 
   
         fclose(f);  
 }  }
   
static const char *lookup_map(const char *handle)static void handle_qdisc(struct nl_object *obj, void *);
 static void find_classes(uint32_t, struct rdata *);
 static void find_qdiscs(uint32_t, struct rdata *);
 
 static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
                                      struct rdata *rdata)
 {  {
        struct hmap *m;        char buf[IFNAME_MAX], name[IFNAME_MAX];
         uint32_t id = rtnl_tc_get_handle(tc);
         struct element *e;
   
        for (m = map; m; m = m->next)        rtnl_tc_handle2str(id, buf, sizeof(buf));
                if (!strcmp(handle, m->id))        snprintf(name, sizeof(name), "%s %s (%s)",
                        return m->name;                 prefix, buf, rtnl_tc_get_kind(tc));
   
        return handle;        if (!(e = element_lookup(grp, name, id, rdata ? rdata->parent : NULL, ELEMENT_CREAT)))
                 return NULL;
 
         if (e->e_flags & ELEMENT_FLAG_CREATED) {
                 e->e_level = rdata ? rdata->level : 0;
 
                 if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
                     element_set_usage_attr(e, "tc_bytes"))
                         BUG();
 
                 update_tc_infos(e, tc);
 
                 e->e_flags &= ~ELEMENT_FLAG_CREATED;
         }
 
         update_tc_attrs(e, tc);
 
         element_notify_update(e, NULL);
         element_lifesign(e, 1);
 
         return e;
 }  }
   
static void handle_qdisc(struct nl_common *, void *);static void handle_cls(struct nl_object *obj, void *arg)
 {
         struct rtnl_cls *cls = (struct rtnl_cls *) obj;
         struct rdata *rdata = arg;
   
#if 0        handle_tc_obj((struct rtnl_tc *) cls, "cls", rdata);
static void handle_filter(struct nl_common *c, void *arg)}
 
 static void handle_class(struct nl_object *obj, void *arg)
 {  {
        struct rtnl_filter *filter = (struct rtnl_filter *) c;        struct rtnl_tc *tc = (struct rtnl_tc *) obj;
        struct xdata *x = arg;        struct element *e;
        item_t *intf;        struct rdata *rdata = arg;
        char name[IFNAME_MAX];        struct rdata ndata = {
                 .level = rdata->level + 1,
         };
   
        printf("HAHAH!\n");        if (!(e = handle_tc_obj(tc, "class", rdata)))
                 return;
   
        if (filter->f_handle) {        ndata.parent = e;
                const char *h = lookup_map(nl_handle2str(filter->f_handle)); 
                snprintf(name, sizeof(name), "f:%s %s", filter->f_kind, h); 
        } else 
                snprintf(name, sizeof(name), "f:%s", filter->f_kind); 
   
        intf = lookup_item(get_local_node(), name, filter->f_handle, x->parent);        if (!strcmp(rtnl_tc_get_kind(tc), "htb"))
                 element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc));
   
        if (intf == NULL)        find_classes(rtnl_tc_get_handle(tc), &ndata);
         find_qdiscs(rtnl_tc_get_handle(tc), &ndata);
 }
 
 static void find_qdiscs(uint32_t parent, struct rdata *rdata)
 {
         struct rtnl_qdisc *filter;
 
         if (!(filter = rtnl_qdisc_alloc()))
                 return;                  return;
   
        intf->i_link = x->intf->i_index;        rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
        intf->i_flags |= ITEM_FLAG_IS_CHILD; 
        intf->i_level = x->level; 
   
        update_attr(intf, PACKETS, 0, 0, 0);        nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
        update_attr(intf, BYTES, 0, 0, 0);                                handle_qdisc, rdata);
   
        notify_update(intf, NULL);        rtnl_qdisc_put(filter);
        increase_lifetime(intf, 1); 
 }  }
 #endif  
   
static void handle_class(struct nl_common *c, void *arg)static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata)
 {  {
        struct rtnl_class *class = (struct rtnl_class *) c;        struct nl_cache *cls_cache;
        struct rtnl_qdisc *leaf; 
        struct xdata *x = arg; 
        item_t *intf; 
        char name[IFNAME_MAX]; 
        struct xdata xn = { 
                .intf = x->intf, 
                .link = x->link, 
                .level = x->level + 1, 
        }; 
   
        if (class->c_handle) {        if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
                const char *h = lookup_map(nl_handle2str(class->c_handle));                return;
                snprintf(name, sizeof(name), "c:%s(%s)", class->c_kind, h); 
        } else 
                snprintf(name, sizeof(name), "c:%s", class->c_kind); 
   
        intf = lookup_item(get_local_node(), name, class->c_handle, x->parent);        nl_cache_foreach(cls_cache, handle_cls, rdata);
   
        if (intf == NULL)        nl_cache_free(cls_cache);
                return;}
   
        xn.parent = intf;static void find_classes(uint32_t parent, struct rdata *rdata)
 {
         struct rtnl_class *filter;
   
        intf->i_link = x->intf->i_index;        if (!(filter = rtnl_class_alloc()))
        intf->i_flags |= ITEM_FLAG_IS_CHILD;                return;
        intf->i_level = x->level; 
        intf->i_major_attr = BYTES; 
        intf->i_minor_attr = PACKETS; 
   
        update_attr(intf, PACKETS, 0, class->c_stats.tcs_basic.packets, TX_PROVIDED);        rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
        update_attr(intf, BYTES, 0, class->c_stats.tcs_basic.bytes, TX_PROVIDED); 
        update_attr(intf, DROP, 0, class->c_stats.tcs_queue.drops, TX_PROVIDED); 
        update_attr(intf, OVERLIMITS, 0, class->c_stats.tcs_queue.overlimits, TX_PROVIDED); 
        update_attr(intf, BPS, 0, class->c_stats.tcs_rate_est.bps, TX_PROVIDED); 
        update_attr(intf, PPS, 0, class->c_stats.tcs_rate_est.pps, TX_PROVIDED); 
        update_attr(intf, QLEN, 0, class->c_stats.tcs_queue.qlen, TX_PROVIDED); 
        update_attr(intf, BACKLOG, 0, class->c_stats.tcs_queue.backlog, TX_PROVIDED); 
        update_attr(intf, REQUEUES, 0, class->c_stats.tcs_queue.requeues, TX_PROVIDED); 
   
        notify_update(intf, NULL);        nl_cache_foreach_filter(class_cache, OBJ_CAST(filter),
        increase_lifetime(intf, 1);                                handle_class, rdata);
   
        if ((leaf = rtnl_class_leaf_qdisc(class, qdisc_cache)))        rtnl_class_put(filter);
                handle_qdisc((struct nl_common *) leaf, &xn); 
        rtnl_class_foreach_child(class, class_cache, &handle_class, &xn); 
#if 0 
        rtnl_class_foreach_filter_nocache(&nl_h, class, &handle_filter, &xn); 
#endif 
 }  }
   
static void handle_qdisc(struct nl_common *c, void *arg)static void handle_qdisc(struct nl_object *obj, void *arg)
 {  {
        struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) c;        struct rtnl_tc *tc = (struct rtnl_tc *) obj;
        struct xdata *x = arg;        struct element *e;
        item_t *intf;        struct rdata *rdata = arg;
        char name[IFNAME_MAX];        struct rdata ndata = {
        struct xdata xn = {                .level = rdata->level + 1,
                .intf = x->intf, 
                .link = x->link, 
                .level = x->level + 1, 
         };          };
   
        if (qdisc->q_handle) {        if (!(e = handle_tc_obj(tc, "qdisc", rdata)))
                const char *h = lookup_map(nl_handle2str(qdisc->q_handle)); 
                snprintf(name, sizeof(name), "q:%s(%s)", qdisc->q_kind, h); 
        } else 
                snprintf(name, sizeof(name), "q:%s", qdisc->q_kind); 
 
        intf = lookup_item(get_local_node(), name, qdisc->q_handle, x->parent); 
        if (intf == NULL) 
                 return;                  return;
   
        xn.parent = intf;        ndata.parent = e;
   
        intf->i_link = x->intf->i_index;        find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);
        intf->i_flags |= ITEM_FLAG_IS_CHILD; 
        intf->i_level = x->level; 
        intf->i_major_attr = BYTES; 
        intf->i_minor_attr = PACKETS; 
   
        if (qdisc->q_handle == 0xffff00) {        if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
                update_attr(intf, BYTES, qdisc->q_stats.tcs_basic.bytes, 0, RX_PROVIDED);                find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata);
                update_attr(intf, PACKETS, qdisc->q_stats.tcs_basic.packets, 0, RX_PROVIDED);                find_classes(TC_H_ROOT, &ndata);
                update_attr(intf, DROP, qdisc->q_stats.tcs_queue.drops, 0, RX_PROVIDED); 
                update_attr(intf, OVERLIMITS, qdisc->q_stats.tcs_queue.overlimits, 0, RX_PROVIDED); 
                update_attr(intf, BPS, qdisc->q_stats.tcs_rate_est.bps, 0, RX_PROVIDED); 
                update_attr(intf, PPS, qdisc->q_stats.tcs_rate_est.pps, 0, RX_PROVIDED); 
                update_attr(intf, QLEN, qdisc->q_stats.tcs_queue.qlen, 0, RX_PROVIDED); 
                update_attr(intf, BACKLOG, qdisc->q_stats.tcs_queue.backlog, 0, RX_PROVIDED); 
                update_attr(intf, REQUEUES, qdisc->q_stats.tcs_queue.requeues, 0, RX_PROVIDED); 
        } else { 
                update_attr(intf, BYTES, 0, qdisc->q_stats.tcs_basic.bytes, TX_PROVIDED); 
                update_attr(intf, PACKETS, 0, qdisc->q_stats.tcs_basic.packets, TX_PROVIDED); 
                update_attr(intf, DROP, 0, qdisc->q_stats.tcs_queue.drops, TX_PROVIDED); 
                update_attr(intf, OVERLIMITS, 0, qdisc->q_stats.tcs_queue.overlimits, TX_PROVIDED); 
                update_attr(intf, BPS, 0, qdisc->q_stats.tcs_rate_est.bps, TX_PROVIDED); 
                update_attr(intf, PPS, 0, qdisc->q_stats.tcs_rate_est.pps, TX_PROVIDED); 
                update_attr(intf, QLEN, 0, qdisc->q_stats.tcs_queue.qlen, TX_PROVIDED); 
                update_attr(intf, BACKLOG, 0, qdisc->q_stats.tcs_queue.backlog, TX_PROVIDED); 
                update_attr(intf, REQUEUES, 0, qdisc->q_stats.tcs_queue.requeues, TX_PROVIDED); 
         }          }
   
        notify_update(intf, NULL);        find_classes(rtnl_tc_get_handle(tc), &ndata);
        increase_lifetime(intf, 1); 
 
        rtnl_qdisc_foreach_child(qdisc, class_cache, &handle_class, &xn); 
#if 0 
        rtnl_qdisc_foreach_filter_nocache(&nl_h, qdisc, &handle_filter, &xn); 
#endif 
 }  }
   
static void handle_tc(item_t *intf, struct rtnl_link *link)static void handle_tc(struct element *e, struct rtnl_link *link)
 {  {
         struct rtnl_qdisc *qdisc;          struct rtnl_qdisc *qdisc;
        struct xdata x = {        int ifindex = rtnl_link_get_ifindex(link);
                .intf = intf,        struct rdata rdata = {
                .link = link, 
                 .level = 1,                  .level = 1,
                .parent = intf,                .parent = e,
         };          };
   
        class_cache = rtnl_class_build_cache(&nl_h, link->l_index);        if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
        if (class_cache == NULL) 
                 return;                  return;
   
        if ((qdisc = rtnl_qdisc_get_root(qdisc_cache, link->l_index)))        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
                handle_qdisc((struct nl_common *) qdisc, &x);        if (qdisc) {
        else if ((qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, link->l_index, 0)))                handle_qdisc(OBJ_CAST(qdisc), &rdata);
                handle_qdisc((struct nl_common *) qdisc, &x);                rtnl_qdisc_put(qdisc);
         }
   
        if ((qdisc = rtnl_qdisc_get_ingress(qdisc_cache, link->l_index)))        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
                handle_qdisc((struct nl_common *) qdisc, &x);        if (qdisc) {
                 handle_qdisc(OBJ_CAST(qdisc), &rdata);
                 rtnl_qdisc_put(qdisc);
         }
   
        nl_cache_destroy_and_free(class_cache);        qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
         if (qdisc) {
                 handle_qdisc(OBJ_CAST(qdisc), &rdata);
                 rtnl_qdisc_put(qdisc);
         }
 
         nl_cache_free(class_cache);
 }  }
   
static void do_link(struct nl_common *item, void *arg)static void update_link_infos(struct element *e, struct rtnl_link *link)
 {  {
        struct rtnl_link *link = (struct rtnl_link *) item;        char buf[64];
        struct rtnl_lstats *st; 
        item_t *intf; 
   
        if (!link->l_name[0])        snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link));
                return;        element_update_info(e, "MTU", buf);
   
        if (get_show_only_running() && !(link->l_flags & IFF_UP))        rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf));
         element_update_info(e, "Flags", buf);
 
         rtnl_link_operstate2str(rtnl_link_get_operstate(link),
                                 buf, sizeof(buf));
         element_update_info(e, "Operstate", buf);
 
         snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link));
         element_update_info(e, "IfIndex", buf);
 
         nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf));
         element_update_info(e, "Address", buf);
 
         nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf));
         element_update_info(e, "Broadcast", buf);
 
         rtnl_link_mode2str(rtnl_link_get_linkmode(link),
                            buf, sizeof(buf));
         element_update_info(e, "Mode", buf);
 
         snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link));
         element_update_info(e, "TXQlen", buf);
 
         nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf));
         element_update_info(e, "Family", buf);
 
         element_update_info(e, "Alias",
                 rtnl_link_get_ifalias(link) ? : "");
 
         element_update_info(e, "Qdisc",
                 rtnl_link_get_qdisc(link) ? : "");
 
         if (rtnl_link_get_link(link)) {
                 snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link));
                 element_update_info(e, "SlaveOfIndex", buf);
         }
 }
 
 static void do_link(struct nl_object *obj, void *arg)
 {
         struct rtnl_link *link = (struct rtnl_link *) obj;
         struct element *e, *e_parent = NULL;
         int i, master_ifindex;
 
         if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) {
                 /* FIXME: delete element */
                 return;                  return;
           }
   
        intf = lookup_item(get_local_node(), link->l_name, 0, 0);        /* Check if the interface is a slave of another interface */
         if ((master_ifindex = rtnl_link_get_link(link))) {
                 char parent[IFNAMSIZ+1];
   
        if (NULL == intf)                rtnl_link_i2name(link_cache, master_ifindex,
                                  parent, sizeof(parent));
 
                 e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0);
         }
 
         if (!(e = element_lookup(grp, rtnl_link_get_name(link),
                                  rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT)))
                 return;                  return;
   
        intf->i_major_attr = BYTES;        if (e->e_flags & ELEMENT_FLAG_CREATED) {
        intf->i_minor_attr = PACKETS;                if (e->e_parent)
                         e->e_level = e->e_parent->e_level + 1;
   
        st = &link->l_stats;                if (element_set_key_attr(e, "bytes", "packets") ||
                     element_set_usage_attr(e, "bytes"))
                         BUG();
   
        update_attr(intf, BYTES, st->ls_rx.bytes, st->ls_tx.bytes,                /* FIXME: Update link infos every 1s or so */
                    RX_PROVIDED | TX_PROVIDED);                update_link_infos(e, link);
        update_attr(intf, PACKETS, st->ls_rx.packets, st->ls_tx.packets, 
                    RX_PROVIDED | TX_PROVIDED); 
   
        update_attr(intf, ERRORS, st->ls_rx.errors, st->ls_tx.errors,                e->e_flags &= ~ELEMENT_FLAG_CREATED;
                RX_PROVIDED | TX_PROVIDED);        }
   
        update_attr(intf, DROP, st->ls_rx.dropped, st->ls_tx.dropped,        for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
                RX_PROVIDED | TX_PROVIDED);                struct attr_map *m = &link_attrs[i];
                 uint64_t c_rx = 0, c_tx = 0;
                 int flags = 0;
   
        update_attr(intf, FIFO, st->ls_rx_fifo_errors,                if (m->rxid >= 0) {
                st->ls_tx_fifo_errors, RX_PROVIDED | TX_PROVIDED);                        c_rx = rtnl_link_get_stat(link, m->rxid);
                         flags |= UPDATE_FLAG_RX;
                 }
   
        update_attr(intf, COMPRESSED, st->ls_rx.compressed,                if (m->txid >= 0) {
                st->ls_tx.compressed, RX_PROVIDED | TX_PROVIDED);                        c_tx = rtnl_link_get_stat(link, m->txid);
                         flags |= UPDATE_FLAG_TX;
                 }
   
        update_attr(intf, MULTICAST, st->ls_rx.multicast, 0, RX_PROVIDED);                attr_update(e, m->attrid, c_rx, c_tx, flags);
        update_attr(intf, COLLISIONS, 0, st->ls_tx_collisions, TX_PROVIDED);        }
        update_attr(intf, LENGTH_ERRORS, st->ls_rx_length_errors, 0, RX_PROVIDED); 
        update_attr(intf, OVER_ERRORS, st->ls_rx_over_errors, 0, RX_PROVIDED); 
        update_attr(intf, CRC_ERRORS, st->ls_rx_crc_errors, 0, RX_PROVIDED); 
        update_attr(intf, FRAME, st->ls_rx_frame_errors, 0, RX_PROVIDED); 
        update_attr(intf, MISSED_ERRORS, st->ls_rx_missed_errors, 0, RX_PROVIDED); 
        update_attr(intf, ABORTED_ERRORS, 0, st->ls_tx_aborted_errors, TX_PROVIDED); 
        update_attr(intf, HEARTBEAT_ERRORS, 0, st->ls_tx_heartbeat_errors, 
                TX_PROVIDED); 
        update_attr(intf, WINDOW_ERRORS, 0, st->ls_tx_window_errors, TX_PROVIDED); 
        update_attr(intf, CARRIER_ERRORS, 0, st->ls_tx_carrier_errors, TX_PROVIDED); 
   
         if (!c_notc)          if (!c_notc)
                handle_tc(intf, link);                handle_tc(e, link);
        
        notify_update(intf, NULL);        element_notify_update(e, NULL);
        increase_lifetime(intf, 1);        element_lifesign(e, 1);
 }  }
   
 static void netlink_read(void)  static void netlink_read(void)
 {  {
        if (nl_cache_update(&nl_h, &link_cache) < 0)        int err;
                quit("%s\n", nl_geterror()); 
   
        if (!c_notc) {        if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) {
                if (qdisc_cache == NULL) {                fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err));
                        qdisc_cache = rtnl_qdisc_build_cache(&nl_h);                goto disable;
                        if (qdisc_cache == NULL) 
                                c_notc = 1; 
                } else { 
                        if (nl_cache_update(&nl_h, qdisc_cache) < 0) 
                                c_notc = 1; 
                } 
         }          }
   
        nl_cache_foreach(&link_cache, do_link, NULL);        if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
                 fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err));
                 goto disable;
         }
 
         nl_cache_foreach(link_cache, do_link, NULL);
 
         return;
 
 disable:
         netlink_ops.m_flags &= ~BMON_MODULE_ENABLED;
 }  }
   
 static void netlink_shutdown(void)  static void netlink_shutdown(void)
 {  {
        nl_close(&nl_h);        nl_cache_free(link_cache);
         nl_cache_free(qdisc_cache);
         nl_socket_free(sock);
 }  }
   
static void netlink_do_init(void)static int netlink_do_init(void)
 {  {
        if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)        int err, i;
                quit("%s\n", nl_geterror()); 
   
        nl_use_default_handlers(&nl_h);        if (!(sock = nl_socket_alloc())) {
                 fprintf(stderr, "Unable to allocate netlink socket\n");
                 goto disable;
         }
 
         if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0) {
                 fprintf(stderr, "Unable to connect netlink socket: %s\n", nl_geterror(err));
                 goto disable;
         }
 
         if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
                 fprintf(stderr, "Unable to allocate link cache: %s\n", nl_geterror(err));
                 goto disable;
         }
 
         if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) {
                 fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err));
                 goto disable;
         }
 
         if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) ||
             attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs)))
                 BUG();
 
         if (!(grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE)))
                 BUG();
 
         return 0;
 
 disable:
         return -EOPNOTSUPP;
 }  }
   
 static int netlink_probe(void)  static int netlink_probe(void)
 {  {
        if (nl_connect(&nl_h, NETLINK_ROUTE) < 0)        struct nl_sock *sock;
         struct nl_cache *lc;
         int ret = 0;
 
         if (!(sock = nl_socket_alloc()))
                 return 0;                  return 0;
                   
        if (nl_cache_update(&nl_h, &link_cache) < 0) {        if (nl_connect(sock, NETLINK_ROUTE) < 0)
                nl_close(&nl_h); 
                 return 0;                  return 0;
           
           if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &lc) == 0) {
                   nl_cache_free(lc);
                   ret = 1;
         }          }
   
        nl_cache_destroy(&link_cache);        nl_socket_free(sock);
        nl_close(&nl_h); 
 
        if (c_mapfile) 
                read_map(c_mapfile); 
                   
        return 1;        return ret;
 }  }
   
 static void print_help(void)  static void print_help(void)
Line 418  static void print_help(void) Line 841  static void print_help(void)
         "  Author: Thomas Graf <tgraf@suug.ch>\n" \          "  Author: Thomas Graf <tgraf@suug.ch>\n" \
         "\n" \          "\n" \
         "  Options:\n" \          "  Options:\n" \
        "    notc           Do not collect traffic control statistics\n" \        "    notc           Do not collect traffic control statistics\n");
        "    map=FILE       Translate handles to map using a mapfile\n" \ 
        "\n" \ 
        "  Map File format:\n" \ 
        "    # comment\n" \ 
        "    <handle> <name> # midline comment\n"); 
 }  }
   
static void netlink_set_opts(tv_t *attrs)static void netlink_parse_opt(const char *type, const char *value)
 {  {
        while (attrs) {        if (!strcasecmp(type, "notc"))
                if (!strcasecmp(attrs->type, "notc"))                c_notc = 1;
                        c_notc = 1;        else if (!strcasecmp(type, "help")) {
                else if (!strcasecmp(attrs->type, "map"))                print_help();
                        c_mapfile = attrs->value;                exit(0);
                else if (!strcasecmp(attrs->type, "help")) { 
                        print_help(); 
                        exit(0); 
                } 
                attrs = attrs->next; 
         }          }
 }  }
   
static struct input_module netlink_ops = {static struct bmon_module netlink_ops = {
        .im_name     = "netlink",        .m_name          = "netlink",
        .im_read     = netlink_read,        .m_flags = BMON_MODULE_DEFAULT,
        .im_shutdown = netlink_shutdown,        .m_do                = netlink_read,
        .im_set_opts = netlink_set_opts,        .m_shutdown      = netlink_shutdown,
        .im_probe = netlink_probe,        .m_parse_opt    = netlink_parse_opt,
        .im_init = netlink_do_init,        .m_probe = netlink_probe,
         .m_init          = netlink_do_init,
 };  };
   
 static void __init netlink_init(void)  static void __init netlink_init(void)
 {  {
        register_input_module(&netlink_ops);        input_register(&netlink_ops);
 }  }
   
 #endif  #endif

Removed from v.1.1  
changed lines
  Added in v.1.1.1.2


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