X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fnetlink.c;h=aa9760f9328b78eb87e14f70501bc1622a57f12d;hb=0003c4d3c184f0f437499d6073cd023dc7b659c2;hp=5aaa25bd3c3d9b43c5de51f183c110cd2215e950;hpb=00345ba775a0c12d7c68e1f28edbd17cbdbc96ef;p=collectd.git diff --git a/src/netlink.c b/src/netlink.c index 5aaa25bd..aa9760f9 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,6 +1,9 @@ /** * collectd - src/netlink.c * Copyright (C) 2007-2010 Florian octo Forster + * Copyright (C) 2008-2012 Sebastian Harl + * Copyright (C) 2013 Andreas Henriksson + * Copyright (C) 2013 Marc Fournier * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,6 +20,9 @@ * * Authors: * Florian octo Forster + * Sebastian Harl + * Andreas Henriksson + * Marc Fournier **/ #include "collectd.h" @@ -35,10 +41,42 @@ # include #endif -#include #include -//#include -//#include + +struct ir_link_stats_storage_s { + + uint64_t rx_packets; + uint64_t tx_packets; + uint64_t rx_bytes; + uint64_t tx_bytes; + uint64_t rx_errors; + uint64_t tx_errors; + + uint64_t rx_dropped; + uint64_t tx_dropped; + uint64_t multicast; + uint64_t collisions; + + uint64_t rx_length_errors; + uint64_t rx_over_errors; + uint64_t rx_crc_errors; + uint64_t rx_frame_errors; + uint64_t rx_fifo_errors; + uint64_t rx_missed_errors; + + uint64_t tx_aborted_errors; + uint64_t tx_carrier_errors; + uint64_t tx_fifo_errors; + uint64_t tx_heartbeat_errors; + uint64_t tx_window_errors; +}; + +union ir_link_stats_u { + struct rtnl_link_stats *stats32; +#ifdef HAVE_RTNL_LINK_STATS64 + struct rtnl_link_stats64 *stats64; +#endif +}; typedef struct ir_ignorelist_s { @@ -58,12 +96,12 @@ static size_t iflist_len = 0; static const char *config_keys[] = { - "Interface", - "VerboseInterface", - "QDisc", - "Class", - "Filter", - "IgnoreSelected" + "Interface", + "VerboseInterface", + "QDisc", + "Class", + "Filter", + "IgnoreSelected" }; static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); @@ -114,7 +152,7 @@ static int add_ignorelist (const char *dev, const char *type, return (0); } /* int add_ignorelist */ -/* +/* * Checks wether a data set should be ignored. Returns `true' is the value * should be ignored, `false' otherwise. */ @@ -132,24 +170,24 @@ static int check_ignorelist (const char *dev, { /* i->device == NULL => match all devices */ if ((i->device != NULL) - && (strcasecmp (i->device, dev) != 0)) + && (strcasecmp (i->device, dev) != 0)) continue; if (strcasecmp (i->type, type) != 0) continue; if ((i->inst != NULL) && (type_instance != NULL) - && (strcasecmp (i->inst, type_instance) != 0)) + && (strcasecmp (i->inst, type_instance) != 0)) continue; DEBUG ("netlink plugin: check_ignorelist: " - "(dev = %s; type = %s; inst = %s) matched " - "(dev = %s; type = %s; inst = %s)", - dev, type, - type_instance == NULL ? "(nil)" : type_instance, - i->device == NULL ? "(nil)" : i->device, - i->type, - i->inst == NULL ? "(nil)" : i->inst); + "(dev = %s; type = %s; inst = %s) matched " + "(dev = %s; type = %s; inst = %s)", + dev, type, + type_instance == NULL ? "(nil)" : type_instance, + i->device == NULL ? "(nil)" : i->device, + i->type, + i->inst == NULL ? "(nil)" : i->inst); return (ir_ignorelist_invert ? 0 : 1); } /* for i */ @@ -201,7 +239,7 @@ static void submit_two (const char *dev, const char *type, plugin_dispatch_values (&vl); } /* void submit_two */ -static int update_iflist(struct ifinfomsg *msg, const char *dev) +static int update_iflist (struct ifinfomsg *msg, const char *dev) { /* Update the `iflist'. It's used to know which interfaces exist and query * them later for qdiscs and classes. */ @@ -217,7 +255,7 @@ static int update_iflist(struct ifinfomsg *msg, const char *dev) } memset (temp + iflist_len, '\0', - (msg->ifi_index + 1 - iflist_len) * sizeof (char *)); + (msg->ifi_index + 1 - iflist_len) * sizeof (char *)); iflist = temp; iflist_len = msg->ifi_index + 1; } @@ -229,11 +267,10 @@ static int update_iflist(struct ifinfomsg *msg, const char *dev) } return (0); -} - +} /* int update_iflist */ -static void check_ignorelist_and_submit(const char *dev, - struct rtnl_link_stats *stats) +static void check_ignorelist_and_submit (const char *dev, + struct ir_link_stats_storage_s *stats) { if (check_ignorelist (dev, "interface", NULL) == 0) @@ -271,23 +308,72 @@ static void check_ignorelist_and_submit(const char *dev, DEBUG ("netlink plugin: Ignoring %s/if_detail.", dev); } +} /* void check_ignorelist_and_submit */ + +#define COPY_RTNL_LINK_VALUE(dst_stats, src_stats, value_name) \ + (dst_stats)->value_name = (src_stats)->value_name + +#define COPY_RTNL_LINK_STATS(dst_stats, src_stats) \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_packets); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_packets); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_bytes); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_bytes); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_dropped); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_dropped); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, multicast); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, collisions); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_length_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_over_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_crc_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_frame_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_fifo_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_missed_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_aborted_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_carrier_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_fifo_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_heartbeat_errors); \ + COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_window_errors) + +#ifdef HAVE_RTNL_LINK_STATS64 +static void check_ignorelist_and_submit64 (const char *dev, + struct rtnl_link_stats64 *stats) +{ + struct ir_link_stats_storage_s s; + + COPY_RTNL_LINK_STATS (&s, stats); + + check_ignorelist_and_submit (dev, &s); +} +#endif + +static void check_ignorelist_and_submit32 (const char *dev, + struct rtnl_link_stats *stats) +{ + struct ir_link_stats_storage_s s; + + COPY_RTNL_LINK_STATS(&s, stats); + + check_ignorelist_and_submit (dev, &s); } static int link_filter_cb (const struct nlmsghdr *nlh, - void __attribute__((unused)) *args) + void *args __attribute__((unused))) { - struct ifinfomsg *ifm = mnl_nlmsg_get_payload (nlh); + struct ifinfomsg *ifm = mnl_nlmsg_get_payload (nlh); struct nlattr *attr; - struct rtnl_link_stats *stats = NULL; const char *dev = NULL; + union ir_link_stats_u stats; if (nlh->nlmsg_type != RTM_NEWLINK) { ERROR ("netlink plugin: link_filter_cb: Don't know how to handle type %i.", - nlh->nlmsg_type); + nlh->nlmsg_type); return MNL_CB_ERROR; } + /* Scan attribute list for device name. */ mnl_attr_for_each (attr, nlh, sizeof (*ifm)) { if (mnl_attr_get_type (attr) != IFLA_IFNAME) @@ -310,49 +396,63 @@ static int link_filter_cb (const struct nlmsghdr *nlh, ERROR ("netlink plugin: link_filter_cb: dev == NULL"); return MNL_CB_ERROR; } +#ifdef HAVE_RTNL_LINK_STATS64 + mnl_attr_for_each (attr, nlh, sizeof (*ifm)) + { + if (mnl_attr_get_type (attr) != IFLA_STATS64) + continue; + + if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats64)) < 0) + { + ERROR ("netlink plugin: link_filter_cb: IFLA_STATS64 mnl_attr_validate2 failed."); + return MNL_CB_ERROR; + } + stats.stats64 = mnl_attr_get_payload (attr); + check_ignorelist_and_submit64 (dev, stats.stats64); + + return MNL_CB_OK; + } +#endif mnl_attr_for_each (attr, nlh, sizeof (*ifm)) { if (mnl_attr_get_type (attr) != IFLA_STATS) continue; - if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof(*stats)) < 0) + if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats32)) < 0) { ERROR ("netlink plugin: link_filter_cb: IFLA_STATS mnl_attr_validate2 failed."); return MNL_CB_ERROR; } - stats = mnl_attr_get_payload(attr); + stats.stats32 = mnl_attr_get_payload (attr); - check_ignorelist_and_submit(dev, stats); - break; - } + check_ignorelist_and_submit32 (dev, stats.stats32); - if (stats == NULL) - { - DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev); return MNL_CB_OK; } + DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev); return MNL_CB_OK; + } /* int link_filter_cb */ #if HAVE_TCA_STATS2 static int qos_attr_cb (const struct nlattr *attr, void *data) { - struct gnet_stats_basic *bs = *(struct gnet_stats_basic **)data; + struct gnet_stats_basic **bs = (struct gnet_stats_basic **)data; - /* skip unsupported attribute in user-space */ - if (mnl_attr_type_valid(attr, TCA_STATS_MAX) < 0) + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid (attr, TCA_STATS_MAX) < 0) return MNL_CB_OK; - if (mnl_attr_get_type(attr) == TCA_STATS_BASIC) + if (mnl_attr_get_type (attr) == TCA_STATS_BASIC) { - if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*bs)) < 0) + if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (**bs)) < 0) { ERROR ("netlink plugin: qos_attr_cb: TCA_STATS_BASIC mnl_attr_validate2 failed."); return MNL_CB_ERROR; } - bs = mnl_attr_get_payload(attr); + *bs = mnl_attr_get_payload (attr); return MNL_CB_STOP; } @@ -362,27 +462,19 @@ static int qos_attr_cb (const struct nlattr *attr, void *data) static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) { - struct tcmsg *tm = mnl_nlmsg_get_payload(nlh); + struct tcmsg *tm = mnl_nlmsg_get_payload (nlh); struct nlattr *attr; int wanted_ifindex = *((int *) args); const char *dev; const char *kind = NULL; - struct gnet_stats_basic *bs = NULL; - struct tc_stats *ts = NULL; /* char *type_instance; */ char *tc_type; char tc_inst[DATA_MAX_NAME_LEN]; - if (tm->tcm_ifindex != wanted_ifindex) - { - DEBUG ("netlink plugin: qos_filter_cb: Got %s for interface #%i, " - "but expected #%i.", - tc_type, msg->tcm_ifindex, wanted_ifindex); - return MNL_CB_OK; - } + _Bool stats_submitted = 0; if (nlh->nlmsg_type == RTM_NEWQDISC) tc_type = "qdisc"; @@ -393,16 +485,24 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) else { ERROR ("netlink plugin: qos_filter_cb: Don't know how to handle type %i.", - nlh->nlmsg_type); + nlh->nlmsg_type); return MNL_CB_ERROR; } + if (tm->tcm_ifindex != wanted_ifindex) + { + DEBUG ("netlink plugin: qos_filter_cb: Got %s for interface #%i, " + "but expected #%i.", + tc_type, tm->tcm_ifindex, wanted_ifindex); + return MNL_CB_OK; + } + if ((tm->tcm_ifindex >= 0) && ((size_t) tm->tcm_ifindex >= iflist_len)) { ERROR ("netlink plugin: qos_filter_cb: tm->tcm_ifindex = %i " - ">= iflist_len = %zu", - tm->tcm_ifindex, iflist_len); + ">= iflist_len = %zu", + tm->tcm_ifindex, iflist_len); return MNL_CB_ERROR; } @@ -410,13 +510,13 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) if (dev == NULL) { ERROR ("netlink plugin: qos_filter_cb: iflist[%i] == NULL", - tm->tcm_ifindex); + tm->tcm_ifindex); return MNL_CB_ERROR; } mnl_attr_for_each (attr, nlh, sizeof (*tm)) { - if (mnl_attr_get_type(attr) != TCA_KIND) + if (mnl_attr_get_type (attr) != TCA_KIND) continue; if (mnl_attr_validate (attr, MNL_TYPE_STRING) < 0) @@ -425,7 +525,7 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) return MNL_CB_ERROR; } - kind = mnl_attr_get_str(attr); + kind = mnl_attr_get_str (attr); break; } @@ -435,7 +535,7 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) return (-1); } - { /* The the ID */ + { /* The ID */ uint32_t numberic_id; numberic_id = tm->tcm_handle; @@ -443,13 +543,13 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) numberic_id = tm->tcm_parent; ssnprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x", - kind, - numberic_id >> 16, - numberic_id & 0x0000FFFF); + kind, + numberic_id >> 16, + numberic_id & 0x0000FFFF); } DEBUG ("netlink plugin: qos_filter_cb: got %s for %s (%i).", - tc_type, dev, msg->tcm_ifindex); + tc_type, dev, tm->tcm_ifindex); if (check_ignorelist (dev, tc_type, tc_inst)) return MNL_CB_OK; @@ -457,36 +557,42 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) #if HAVE_TCA_STATS2 mnl_attr_for_each (attr, nlh, sizeof (*tm)) { - if (mnl_attr_get_type(attr) != TCA_STATS2) + struct gnet_stats_basic *bs = NULL; + + if (mnl_attr_get_type (attr) != TCA_STATS2) continue; - if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + if (mnl_attr_validate (attr, MNL_TYPE_NESTED) < 0) { ERROR ("netlink plugin: qos_filter_cb: TCA_STATS2 mnl_attr_validate failed."); return MNL_CB_ERROR; } - mnl_attr_parse_nested(attr, qos_attr_cb, &bs); + mnl_attr_parse_nested (attr, qos_attr_cb, &bs); - break; - } + if (bs != NULL) + { + char type_instance[DATA_MAX_NAME_LEN]; - if (bs != NULL) - { - char type_instance[DATA_MAX_NAME_LEN]; + stats_submitted = 1; - ssnprintf (type_instance, sizeof (type_instance), "%s-%s", - tc_type, tc_inst); + ssnprintf (type_instance, sizeof (type_instance), "%s-%s", + tc_type, tc_inst); + + submit_one (dev, "ipt_bytes", type_instance, bs->bytes); + submit_one (dev, "ipt_packets", type_instance, bs->packets); + } - submit_one (dev, "ipt_bytes", type_instance, bs->bytes); - submit_one (dev, "ipt_packets", type_instance, bs->packets); + break; } #endif /* TCA_STATS2 */ #if HAVE_TCA_STATS mnl_attr_for_each (attr, nlh, sizeof (*tm)) { - if (mnl_attr_get_type(attr) != TCA_STATS) + struct tc_stats *ts = NULL; + + if (mnl_attr_get_type (attr) != TCA_STATS) continue; if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*ts)) < 0) @@ -494,20 +600,22 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args) ERROR ("netlink plugin: qos_filter_cb: TCA_STATS mnl_attr_validate2 failed."); return MNL_CB_ERROR; } - ts = mnl_attr_get_payload(attr); - break; - } + ts = mnl_attr_get_payload (attr); - if (bs == NULL && ts != NULL) - { - char type_instance[DATA_MAX_NAME_LEN]; + if (!stats_submitted && ts != NULL) + { + char type_instance[DATA_MAX_NAME_LEN]; - ssnprintf (type_instance, sizeof (type_instance), "%s-%s", - tc_type, tc_inst); + ssnprintf (type_instance, sizeof (type_instance), "%s-%s", + tc_type, tc_inst); + + submit_one (dev, "ipt_bytes", type_instance, ts->bytes); + submit_one (dev, "ipt_packets", type_instance, ts->packets); + } - submit_one (dev, "ipt_bytes", type_instance, ts->bytes); - submit_one (dev, "ipt_packets", type_instance, ts->packets); + break; } + #endif /* TCA_STATS */ #if !(HAVE_TCA_STATS && HAVE_TCA_STATS2) @@ -542,14 +650,14 @@ static int ir_config (const char *key, const char *value) if (fields_num != 1) { ERROR ("netlink plugin: Invalid number of fields for option " - "`%s'. Got %i, expected 1.", key, fields_num); + "`%s'. Got %i, expected 1.", key, fields_num); status = -1; } else { add_ignorelist (fields[0], "interface", NULL); if (strcasecmp (key, "VerboseInterface") == 0) - add_ignorelist (fields[0], "if_detail", NULL); + add_ignorelist (fields[0], "if_detail", NULL); status = 0; } } @@ -560,13 +668,13 @@ static int ir_config (const char *key, const char *value) if ((fields_num < 1) || (fields_num > 2)) { ERROR ("netlink plugin: Invalid number of fields for option " - "`%s'. Got %i, expected 1 or 2.", key, fields_num); + "`%s'. Got %i, expected 1 or 2.", key, fields_num); return (-1); } else { add_ignorelist (fields[0], key, - (fields_num == 2) ? fields[1] : NULL); + (fields_num == 2) ? fields[1] : NULL); status = 0; } } @@ -575,15 +683,15 @@ static int ir_config (const char *key, const char *value) if (fields_num != 1) { ERROR ("netlink plugin: Invalid number of fields for option " - "`IgnoreSelected'. Got %i, expected 1.", fields_num); + "`IgnoreSelected'. Got %i, expected 1.", fields_num); status = -1; } else { if (IS_TRUE (fields[0])) - ir_ignorelist_invert = 0; + ir_ignorelist_invert = 0; else - ir_ignorelist_invert = 1; + ir_ignorelist_invert = 1; status = 0; } } @@ -595,14 +703,14 @@ static int ir_config (const char *key, const char *value) static int ir_init (void) { - nl = mnl_socket_open(NETLINK_ROUTE); + nl = mnl_socket_open (NETLINK_ROUTE); if (nl == NULL) { ERROR ("netlink plugin: ir_init: mnl_socket_open failed."); return (-1); } - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + if (mnl_socket_bind (nl, 0, MNL_SOCKET_AUTOPID) < 0) { ERROR ("netlink plugin: ir_init: mnl_socket_bind failed."); return (-1); @@ -624,7 +732,7 @@ static int ir_read (void) static const int type_id[] = { RTM_GETQDISC, RTM_GETTCLASS, RTM_GETTFILTER }; static const char *type_name[] = { "qdisc", "class", "filter" }; - portid = mnl_socket_get_portid(nl); + portid = mnl_socket_get_portid (nl); nlh = mnl_nlmsg_put_header (buf); nlh->nlmsg_type = RTM_GETLINK; @@ -645,7 +753,7 @@ static int ir_read (void) ret = mnl_cb_run (buf, ret, seq, portid, link_filter_cb, NULL); if (ret <= MNL_CB_STOP) break; - ret = mnl_socket_recvfrom (nl, buf, sizeof(buf)); + ret = mnl_socket_recvfrom (nl, buf, sizeof (buf)); } if (ret < 0) { @@ -655,10 +763,9 @@ static int ir_read (void) /* `link_filter_cb' will update `iflist' which is used here to iterate * over all interfaces. */ - for (ifindex = 0; ifindex < iflist_len; ifindex++) + for (ifindex = 1; ifindex < iflist_len; ifindex++) { struct tcmsg *tm; - int ifindex; size_t type_index; if (iflist[ifindex] == NULL) @@ -668,13 +775,13 @@ static int ir_read (void) { if (check_ignorelist (iflist[ifindex], type_name[type_index], NULL)) { - DEBUG ("netlink plugin: ir_read: check_ignorelist (%s, %s, (nil)) " - "== TRUE", iflist[ifindex], type_name[type_index]); - continue; + DEBUG ("netlink plugin: ir_read: check_ignorelist (%s, %s, (nil)) " + "== TRUE", iflist[ifindex], type_name[type_index]); + continue; } - DEBUG ("netlink plugin: ir_read: querying %s from %s (%i).", - type_name[type_index], iflist[ifindex], ifindex); + DEBUG ("netlink plugin: ir_read: querying %s from %s (%zu).", + type_name[type_index], iflist[ifindex], ifindex); nlh = mnl_nlmsg_put_header (buf); nlh->nlmsg_type = type_id[type_index]; @@ -687,14 +794,14 @@ static int ir_read (void) if (mnl_socket_sendto (nl, nlh, nlh->nlmsg_len) < 0) { ERROR ("netlink plugin: ir_read: mnl_socket_sendto failed."); - continue; + continue; } ret = mnl_socket_recvfrom (nl, buf, sizeof (buf)); while (ret > 0) { ret = mnl_cb_run (buf, ret, seq, portid, qos_filter_cb, &ifindex); - if (ret <= MNL_CB_STOP) + if (ret <= MNL_CB_STOP) break; ret = mnl_socket_recvfrom (nl, buf, sizeof (buf)); } @@ -714,7 +821,7 @@ static int ir_shutdown (void) { if (nl) { - mnl_socket_close(nl); + mnl_socket_close (nl); nl = NULL; }