File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / in_netlink.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 14:58:35 2019 UTC (5 years, 8 months ago) by misho
Branches: bmon, MAIN
CVS tags: v4_0p0, HEAD
bmon ver 4.0

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

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