Annotation of embedaddon/bmon/src/in_netlink.c, revision 1.1.1.3
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:
1.1.1.3 ! misho 40: #include <linux/if.h>
! 41:
1.1 misho 42: #include <netlink/netlink.h>
43: #include <netlink/cache.h>
1.1.1.2 misho 44: #include <netlink/utils.h>
1.1 misho 45: #include <netlink/route/link.h>
1.1.1.2 misho 46: #include <netlink/route/tc.h>
1.1 misho 47: #include <netlink/route/qdisc.h>
48: #include <netlink/route/class.h>
1.1.1.2 misho 49: #include <netlink/route/classifier.h>
50: #include <netlink/route/qdisc/htb.h>
1.1 misho 51:
1.1.1.3 ! misho 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:
1.1.1.2 misho 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: {
1.1.1.3 ! misho 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: {
1.1.1.2 misho 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: {
1.1.1.3 ! misho 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: {
1.1.1.2 misho 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: {
1.1.1.3 ! misho 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: {
1.1.1.2 misho 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,
1.1.1.3 ! misho 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,
1.1.1.2 misho 428: }
429: };
1.1 misho 430:
1.1.1.2 misho 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 {
1.1.1.3 ! misho 507: struct nl_cache * class_cache;
1.1.1.2 misho 508: struct element * parent;
509: int level;
1.1 misho 510: };
511:
1.1.1.2 misho 512: static struct nl_sock *sock;
1.1.1.3 ! misho 513: static struct nl_cache *link_cache, *qdisc_cache;
1.1.1.2 misho 514:
515: static void update_tc_attrs(struct element *e, struct rtnl_tc *tc)
1.1 misho 516: {
1.1.1.2 misho 517: int i;
1.1 misho 518:
1.1.1.2 misho 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: }
1.1 misho 524:
1.1.1.2 misho 525: static void update_tc_infos(struct element *e, struct rtnl_tc *tc)
526: {
527: char buf[64];
1.1 misho 528:
1.1.1.2 misho 529: snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mtu(tc));
530: element_update_info(e, "MTU", buf);
1.1 misho 531:
1.1.1.2 misho 532: snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mpu(tc));
533: element_update_info(e, "MPU", buf);
1.1 misho 534:
1.1.1.2 misho 535: snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_overhead(tc));
536: element_update_info(e, "Overhead", buf);
1.1 misho 537:
1.1.1.2 misho 538: snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_handle(tc));
539: element_update_info(e, "Id", buf);
1.1 misho 540:
1.1.1.2 misho 541: snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_parent(tc));
542: element_update_info(e, "Parent", buf);
1.1 misho 543:
544: }
545:
1.1.1.2 misho 546: static void handle_qdisc(struct nl_object *obj, void *);
547: static void find_classes(uint32_t, struct rdata *);
1.1.1.3 ! misho 548: static void find_qdiscs(int, uint32_t, struct rdata *);
1.1.1.2 misho 549:
550: static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
1.1.1.3 ! misho 551: const struct rdata *rdata)
1.1 misho 552: {
1.1.1.2 misho 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:
1.1.1.3 ! misho 561: if (!rdata || !rdata->parent)
! 562: BUG();
! 563:
! 564: if (!(e = element_lookup(grp, name, id, rdata->parent, ELEMENT_CREAT)))
1.1.1.2 misho 565: return NULL;
566:
567: if (e->e_flags & ELEMENT_FLAG_CREATED) {
1.1.1.3 ! misho 568: e->e_level = rdata->level;
1.1 misho 569:
1.1.1.2 misho 570: if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
571: element_set_usage_attr(e, "tc_bytes"))
572: BUG();
1.1 misho 573:
1.1.1.2 misho 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;
1.1 misho 585: }
586:
1.1.1.2 misho 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: }
1.1 misho 594:
1.1.1.2 misho 595: static void handle_class(struct nl_object *obj, void *arg)
1.1 misho 596: {
1.1.1.2 misho 597: struct rtnl_tc *tc = (struct rtnl_tc *) obj;
598: struct element *e;
1.1.1.3 ! misho 599: const struct rdata *rdata = arg;
1.1.1.2 misho 600: struct rdata ndata = {
1.1.1.3 ! misho 601: .class_cache = rdata->class_cache,
1.1.1.2 misho 602: .level = rdata->level + 1,
603: };
1.1 misho 604:
1.1.1.2 misho 605: if (!(e = handle_tc_obj(tc, "class", rdata)))
606: return;
1.1 misho 607:
1.1.1.2 misho 608: ndata.parent = e;
1.1 misho 609:
1.1.1.2 misho 610: if (!strcmp(rtnl_tc_get_kind(tc), "htb"))
611: element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc));
1.1 misho 612:
1.1.1.2 misho 613: find_classes(rtnl_tc_get_handle(tc), &ndata);
1.1.1.3 ! misho 614: find_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);
1.1.1.2 misho 615: }
616:
1.1.1.3 ! misho 617: static void find_qdiscs(int ifindex, uint32_t parent, struct rdata *rdata)
1.1.1.2 misho 618: {
619: struct rtnl_qdisc *filter;
620:
621: if (!(filter = rtnl_qdisc_alloc()))
1.1 misho 622: return;
623:
1.1.1.2 misho 624: rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
1.1.1.3 ! misho 625: rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex);
1.1 misho 626:
1.1.1.2 misho 627: nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
628: handle_qdisc, rdata);
1.1 misho 629:
1.1.1.2 misho 630: rtnl_qdisc_put(filter);
1.1 misho 631: }
632:
1.1.1.2 misho 633: static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata)
1.1 misho 634: {
1.1.1.2 misho 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);
1.1 misho 641:
1.1.1.2 misho 642: nl_cache_free(cls_cache);
643: }
1.1 misho 644:
1.1.1.2 misho 645: static void find_classes(uint32_t parent, struct rdata *rdata)
646: {
647: struct rtnl_class *filter;
1.1 misho 648:
1.1.1.2 misho 649: if (!(filter = rtnl_class_alloc()))
1.1 misho 650: return;
651:
1.1.1.2 misho 652: rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
1.1 misho 653:
1.1.1.3 ! misho 654: nl_cache_foreach_filter(rdata->class_cache, OBJ_CAST(filter),
1.1.1.2 misho 655: handle_class, rdata);
656:
657: rtnl_class_put(filter);
1.1 misho 658: }
659:
1.1.1.2 misho 660: static void handle_qdisc(struct nl_object *obj, void *arg)
1.1 misho 661: {
1.1.1.2 misho 662: struct rtnl_tc *tc = (struct rtnl_tc *) obj;
663: struct element *e;
1.1.1.3 ! misho 664: const struct rdata *rdata = arg;
1.1.1.2 misho 665: struct rdata ndata = {
1.1.1.3 ! misho 666: .class_cache = rdata->class_cache,
1.1.1.2 misho 667: .level = rdata->level + 1,
1.1 misho 668: };
669:
1.1.1.2 misho 670: if (!(e = handle_tc_obj(tc, "qdisc", rdata)))
1.1 misho 671: return;
672:
1.1.1.2 misho 673: ndata.parent = e;
1.1 misho 674:
1.1.1.2 misho 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);
1.1 misho 683: }
684:
1.1.1.2 misho 685: static void handle_tc(struct element *e, struct rtnl_link *link)
1.1 misho 686: {
687: struct rtnl_qdisc *qdisc;
1.1.1.3 ! misho 688: struct nl_cache *class_cache;
1.1.1.2 misho 689: int ifindex = rtnl_link_get_ifindex(link);
690: struct rdata rdata = {
1.1 misho 691: .level = 1,
1.1.1.2 misho 692: .parent = e,
1.1 misho 693: };
694:
1.1.1.2 misho 695: if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
1.1 misho 696: return;
697:
1.1.1.3 ! misho 698: rdata.class_cache = class_cache;
! 699:
1.1.1.2 misho 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);
1.1 misho 750:
1.1.1.2 misho 751: nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf));
752: element_update_info(e, "Family", buf);
1.1 misho 753:
1.1.1.2 misho 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: }
1.1 misho 764: }
765:
1.1.1.2 misho 766: static void do_link(struct nl_object *obj, void *arg)
1.1 misho 767: {
1.1.1.2 misho 768: struct rtnl_link *link = (struct rtnl_link *) obj;
769: struct element *e, *e_parent = NULL;
770: int i, master_ifindex;
1.1 misho 771:
1.1.1.2 misho 772: if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) {
773: /* FIXME: delete element */
1.1 misho 774: return;
1.1.1.2 misho 775: }
1.1 misho 776:
1.1.1.2 misho 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));
1.1 misho 783:
1.1.1.2 misho 784: e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0);
785: }
1.1 misho 786:
1.1.1.2 misho 787: if (!(e = element_lookup(grp, rtnl_link_get_name(link),
788: rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT)))
1.1 misho 789: return;
790:
1.1.1.2 misho 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();
1.1 misho 798:
1.1.1.2 misho 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: }
1.1 misho 819:
1.1.1.2 misho 820: attr_update(e, m->attrid, c_rx, c_tx, flags);
821: }
1.1 misho 822:
1.1.1.3 ! misho 823: if (!c_notc && qdisc_cache)
1.1.1.2 misho 824: handle_tc(e, link);
825:
826: element_notify_update(e, NULL);
827: element_lifesign(e, 1);
1.1 misho 828: }
829:
830: static void netlink_read(void)
831: {
1.1.1.2 misho 832: int err;
1.1 misho 833:
1.1.1.2 misho 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;
1.1 misho 837: }
838:
1.1.1.3 ! misho 839: if (qdisc_cache &&
! 840: (err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
1.1.1.2 misho 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;
1.1 misho 851: }
852:
853: static void netlink_shutdown(void)
854: {
1.1.1.2 misho 855: nl_cache_free(link_cache);
856: nl_cache_free(qdisc_cache);
857: nl_socket_free(sock);
1.1 misho 858: }
859:
1.1.1.3 ! misho 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:
1.1.1.2 misho 871: static int netlink_do_init(void)
1.1 misho 872: {
1.1.1.3 ! misho 873: int err;
1.1.1.2 misho 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) {
1.1.1.3 ! misho 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;
1.1.1.2 misho 894: }
895:
1.1.1.3 ! misho 896: netlink_use_bit(link_attrs, ARRAY_SIZE(link_attrs));
! 897: netlink_use_bit(tc_attrs, ARRAY_SIZE(tc_attrs));
1.1.1.2 misho 898: if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) ||
899: attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs)))
900: BUG();
1.1 misho 901:
1.1.1.2 misho 902: if (!(grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE)))
903: BUG();
904:
905: return 0;
906:
907: disable:
908: return -EOPNOTSUPP;
1.1 misho 909: }
910:
911: static int netlink_probe(void)
912: {
1.1.1.2 misho 913: struct nl_sock *sock;
914: struct nl_cache *lc;
915: int ret = 0;
916:
917: if (!(sock = nl_socket_alloc()))
1.1 misho 918: return 0;
1.1.1.3 ! misho 919:
1.1.1.2 misho 920: if (nl_connect(sock, NETLINK_ROUTE) < 0)
1.1 misho 921: return 0;
1.1.1.3 ! misho 922:
1.1.1.2 misho 923: if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &lc) == 0) {
924: nl_cache_free(lc);
925: ret = 1;
1.1 misho 926: }
927:
1.1.1.2 misho 928: nl_socket_free(sock);
1.1.1.3 ! misho 929:
1.1.1.2 misho 930: return ret;
1.1 misho 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" \
1.1.1.2 misho 943: " notc Do not collect traffic control statistics\n");
1.1 misho 944: }
945:
1.1.1.2 misho 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);
1.1 misho 953: }
954: }
955:
1.1.1.2 misho 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,
1.1 misho 964: };
965:
966: static void __init netlink_init(void)
967: {
1.1.1.2 misho 968: input_register(&netlink_ops);
1.1 misho 969: }
970: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>