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>