X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fnetlink.c;h=d14e5101dd885824b904b754845aa039dca05630;hb=068ae14b916aa298995433da83302032c5e57c76;hp=1a053d24272e1182f169a439f89125746a666840;hpb=7c6b8505e5557622158574c8dce8ba53c53cec72;p=collectd.git diff --git a/src/netlink.c b/src/netlink.c index 1a053d24..d14e5101 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -25,12 +25,23 @@ #include #include -#include + #include #include -#include - -#include +#if HAVE_LINUX_GEN_STATS_H +# include +#endif +#if HAVE_LINUX_PKT_SCHED_H +# include +#endif + +#if HAVE_LIBNETLINK_H +# include +#elif HAVE_IPROUTE_LIBNETLINK_H +# include +#elif HAVE_LINUX_LIBNETLINK_H +# include +#endif typedef struct ir_ignorelist_s { @@ -45,6 +56,9 @@ static ir_ignorelist_t *ir_ignorelist_head = NULL; static struct rtnl_handle rth; +static char **iflist = NULL; +static size_t iflist_len = 0; + static const char *config_keys[] = { "Interface", @@ -112,20 +126,34 @@ static int check_ignorelist (const char *dev, { ir_ignorelist_t *i; + assert ((dev != NULL) && (type != NULL)); + if (ir_ignorelist_head == NULL) return (ir_ignorelist_invert ? 0 : 1); for (i = ir_ignorelist_head; i != NULL; i = i->next) { - if ((strcasecmp (i->device, dev) != 0) - || (strcasecmp (i->type, type) != 0)) + /* i->device == NULL => match all devices */ + if ((i->device != NULL) + && (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))) + if ((i->inst != NULL) && (type_instance != NULL) + && (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); + return (ir_ignorelist_invert ? 0 : 1); } /* for i */ @@ -143,14 +171,15 @@ static void submit_one (const char *dev, const char *type, vl.values = values; vl.values_len = 1; vl.time = time (NULL); - strcpy (vl.host, hostname_g); - strcpy (vl.plugin, "netlink"); - strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance)); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, type, sizeof (vl.type)); if (type_instance != NULL) - strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); - plugin_dispatch_values (type, &vl); + plugin_dispatch_values (&vl); } /* void submit_one */ static void submit_two (const char *dev, const char *type, @@ -166,18 +195,19 @@ static void submit_two (const char *dev, const char *type, vl.values = values; vl.values_len = 2; vl.time = time (NULL); - strcpy (vl.host, hostname_g); - strcpy (vl.plugin, "netlink"); - strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance)); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, type, sizeof (vl.type)); if (type_instance != NULL) - strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); - plugin_dispatch_values (type, &vl); + plugin_dispatch_values (&vl); } /* void submit_two */ -static int link_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, - void *args) +static int link_filter (const struct sockaddr_nl *sa, + struct nlmsghdr *nmh, void *args) { struct ifinfomsg *msg; int msg_len; @@ -188,7 +218,7 @@ static int link_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, if (nmh->nlmsg_type != RTM_NEWLINK) { - ERROR ("netlink plugin: link_filter: Don't know how to handle type %i.\n", + ERROR ("netlink plugin: link_filter: Don't know how to handle type %i.", nmh->nlmsg_type); return (-1); } @@ -198,28 +228,56 @@ static int link_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, msg_len = nmh->nlmsg_len - sizeof (struct ifinfomsg); if (msg_len < 0) { - ERROR ("netlink plugin: link_filter: msg_len = %i < 0;\n", msg_len); + ERROR ("netlink plugin: link_filter: msg_len = %i < 0;", msg_len); return (-1); } memset (attrs, '\0', sizeof (attrs)); if (parse_rtattr (attrs, IFLA_MAX, IFLA_RTA (msg), msg_len) != 0) { - ERROR ("netlink plugin: link_filter: parse_rtattr failed.\n"); + ERROR ("netlink plugin: link_filter: parse_rtattr failed."); return (-1); } - if (attrs[IFLA_STATS] == NULL) - return (-1); - stats = RTA_DATA (attrs[IFLA_STATS]); - if (attrs[IFLA_IFNAME] == NULL) { - ERROR ("netlink plugin: link_filter: attrs[IFLA_IFNAME] == NULL\n"); + ERROR ("netlink plugin: link_filter: attrs[IFLA_IFNAME] == NULL"); return (-1); } dev = RTA_DATA (attrs[IFLA_IFNAME]); + /* Update the `iflist'. It's used to know which interfaces exist and query + * them later for qdiscs and classes. */ + if (msg->ifi_index >= iflist_len) + { + char **temp; + + temp = (char **) realloc (iflist, (msg->ifi_index + 1) * sizeof (char *)); + if (temp == NULL) + { + ERROR ("netlink plugin: link_filter: realloc failed."); + return (-1); + } + + memset (temp + iflist_len, '\0', + (msg->ifi_index + 1 - iflist_len) * sizeof (char *)); + iflist = temp; + iflist_len = msg->ifi_index + 1; + } + if ((iflist[msg->ifi_index] == NULL) + || (strcmp (iflist[msg->ifi_index], dev) != 0)) + { + sfree (iflist[msg->ifi_index]); + iflist[msg->ifi_index] = strdup (dev); + } + + if (attrs[IFLA_STATS] == NULL) + { + DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev); + return (0); + } + stats = RTA_DATA (attrs[IFLA_STATS]); + if (check_ignorelist (dev, "interface", NULL) == 0) { submit_two (dev, "if_octets", NULL, stats->rx_bytes, stats->tx_bytes); @@ -258,13 +316,15 @@ static int link_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, return (0); } /* int link_filter */ -static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, - void *args) +static int qos_filter (const struct sockaddr_nl *sa, + struct nlmsghdr *nmh, void *args) { struct tcmsg *msg; int msg_len; struct rtattr *attrs[TCA_MAX + 1]; + int wanted_ifindex = *((int *) args); + const char *dev; /* char *type_instance; */ @@ -279,7 +339,7 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, tc_type = "filter"; else { - ERROR ("netlink plugin: qos_filter: Don't know how to handle type %i.\n", + ERROR ("netlink plugin: qos_filter: Don't know how to handle type %i.", nmh->nlmsg_type); return (-1); } @@ -289,14 +349,30 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, msg_len = nmh->nlmsg_len - sizeof (struct tcmsg); if (msg_len < 0) { - ERROR ("netlink plugin: qos_filter: msg_len = %i < 0;\n", msg_len); + ERROR ("netlink plugin: qos_filter: msg_len = %i < 0;", msg_len); return (-1); } - dev = ll_index_to_name (msg->tcm_ifindex); + if (msg->tcm_ifindex != wanted_ifindex) + { + DEBUG ("netlink plugin: qos_filter: Got %s for interface #%i, " + "but expected #%i.", + tc_type, msg->tcm_ifindex, wanted_ifindex); + return (0); + } + + if (msg->tcm_ifindex >= iflist_len) + { + ERROR ("netlink plugin: qos_filter: msg->tcm_ifindex = %i " + ">= iflist_len = %zu", + msg->tcm_ifindex, iflist_len); + return (-1); + } + + dev = iflist[msg->tcm_ifindex]; if (dev == NULL) { - ERROR ("netlink plugin: qos_filter: ll_index_to_name (%i) failed.\n", + ERROR ("netlink plugin: qos_filter: iflist[%i] == NULL", msg->tcm_ifindex); return (-1); } @@ -304,13 +380,13 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, memset (attrs, '\0', sizeof (attrs)); if (parse_rtattr (attrs, TCA_MAX, TCA_RTA (msg), msg_len) != 0) { - ERROR ("netlink plugin: qos_filter: parse_rtattr failed.\n"); + ERROR ("netlink plugin: qos_filter: parse_rtattr failed."); return (-1); } if (attrs[TCA_KIND] == NULL) { - ERROR ("netlink plugin: qos_filter: attrs[TCA_KIND] == NULL\n"); + ERROR ("netlink plugin: qos_filter: attrs[TCA_KIND] == NULL"); return (-1); } @@ -321,16 +397,19 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, if (strcmp (tc_type, "filter") == 0) numberic_id = msg->tcm_parent; - snprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x", + ssnprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x", (const char *) RTA_DATA (attrs[TCA_KIND]), numberic_id >> 16, numberic_id & 0x0000FFFF); - tc_inst[sizeof (tc_inst) - 1] = '\0'; } + + DEBUG ("netlink plugin: qos_filter: got %s for %s (%i).", + tc_type, dev, msg->tcm_ifindex); if (check_ignorelist (dev, tc_type, tc_inst)) return (0); +#if HAVE_TCA_STATS2 if (attrs[TCA_STATS2]) { struct rtattr *attrs_stats[TCA_STATS_MAX + 1]; @@ -343,9 +422,8 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, struct gnet_stats_basic bs; char type_instance[DATA_MAX_NAME_LEN]; - snprintf (type_instance, sizeof (type_instance), "%s-%s", + ssnprintf (type_instance, sizeof (type_instance), "%s-%s", tc_type, tc_inst); - type_instance[sizeof (type_instance) - 1] = '\0'; memset (&bs, '\0', sizeof (bs)); memcpy (&bs, RTA_DATA (attrs_stats[TCA_STATS_BASIC]), @@ -355,6 +433,34 @@ static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh, submit_one (dev, "ipt_packets", type_instance, bs.packets); } } +#endif /* TCA_STATS2 */ +#if HAVE_TCA_STATS && HAVE_TCA_STATS2 + else +#endif +#if HAVE_TCA_STATS + if (attrs[TCA_STATS] != NULL) + { + struct tc_stats ts; + char type_instance[DATA_MAX_NAME_LEN]; + + ssnprintf (type_instance, sizeof (type_instance), "%s-%s", + tc_type, tc_inst); + + memset(&ts, '\0', sizeof (ts)); + memcpy(&ts, RTA_DATA (attrs[TCA_STATS]), + MIN (RTA_PAYLOAD (attrs[TCA_STATS]), sizeof (ts))); + + submit_one (dev, "ipt_bytes", type_instance, ts.bytes); + submit_one (dev, "ipt_packets", type_instance, ts.packets); + } +#endif /* TCA_STATS */ +#if HAVE_TCA_STATS || HAVE_TCA_STATS2 + else +#endif + { + DEBUG ("netlink plugin: qos_filter: Have neither TCA_STATS2 nor " + "TCA_STATS."); + } return (0); } /* int qos_filter */ @@ -411,7 +517,7 @@ static int ir_config (const char *key, const char *value) status = 0; } } - else if (strcasecmp (key, "IgnoreSelected")) + else if (strcasecmp (key, "IgnoreSelected") == 0) { if (fields_num != 1) { @@ -442,13 +548,7 @@ static int ir_init (void) if (rtnl_open (&rth, 0) != 0) { - ERROR ("netlink plugin: print_stats: rtnl_open failed.\n"); - return (-1); - } - - if (ll_init_map (&rth) != 0) - { - ERROR ("netlink plugin: print_stats: ll_init_map failed.\n"); + ERROR ("netlink plugin: ir_init: rtnl_open failed."); return (-1); } @@ -459,71 +559,69 @@ static int ir_read (void) { struct ifinfomsg im; struct tcmsg tm; + int ifindex; + + static const int type_id[] = { RTM_GETQDISC, RTM_GETTCLASS, RTM_GETTFILTER }; + static const char *type_name[] = { "qdisc", "class", "filter" }; memset (&im, '\0', sizeof (im)); im.ifi_type = AF_UNSPEC; - memset (&tm, '\0', sizeof (tm)); - tm.tcm_family = AF_UNSPEC; - if (rtnl_dump_request (&rth, RTM_GETLINK, &im, sizeof (im)) < 0) { - ERROR ("netlink plugin: print_stats: rtnl_dump_request failed.\n"); + ERROR ("netlink plugin: ir_read: rtnl_dump_request failed."); return (-1); } if (rtnl_dump_filter (&rth, link_filter, /* arg1 = */ NULL, NULL, NULL) != 0) { - ERROR ("netlink plugin: print_stats: rtnl_dump_filter failed.\n"); - return (-1); - } - - /* Get QDisc stats */ - if (rtnl_dump_request (&rth, RTM_GETQDISC, &tm, sizeof (tm)) < 0) - { - ERROR ("netlink plugin: print_stats: rtnl_dump_request failed.\n"); + ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed."); return (-1); } - if (rtnl_dump_filter (&rth, qos_filter, /* arg1 = */ NULL, - NULL, NULL) != 0) + /* `link_filter' will update `iflist' which is used here to iterate over all + * interfaces. */ + for (ifindex = 0; ifindex < iflist_len; ifindex++) { - ERROR ("netlink plugin: print_stats: rtnl_dump_filter failed.\n"); - return (-1); - } + int type_index; - /* Get Class stats */ - if (rtnl_dump_request (&rth, RTM_GETTCLASS, &tm, sizeof (tm)) < 0) - { - ERROR ("netlink plugin: print_stats: rtnl_dump_request failed.\n"); - return (-1); - } - - if (rtnl_dump_filter (&rth, qos_filter, /* arg1 = */ NULL, - NULL, NULL) != 0) - { - ERROR ("netlink plugin: print_stats: rtnl_dump_filter failed.\n"); - return (-1); - } - - /* Get Filter stats */ - if (rtnl_dump_request (&rth, RTM_GETTFILTER, &tm, sizeof (tm)) < 0) - { - ERROR ("netlink plugin: print_stats: rtnl_dump_request failed.\n"); - return (-1); - } - - if (rtnl_dump_filter (&rth, qos_filter, /* arg1 = */ NULL, - NULL, NULL) != 0) - { - ERROR ("netlink plugin: print_stats: rtnl_dump_filter failed.\n"); - return (-1); - } + if (iflist[ifindex] == NULL) + continue; + for (type_index = 0; type_index < STATIC_ARRAY_SIZE (type_id); type_index++) + { + 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: querying %s from %s (%i).", + type_name[type_index], iflist[ifindex], ifindex); + + memset (&tm, '\0', sizeof (tm)); + tm.tcm_family = AF_UNSPEC; + tm.tcm_ifindex = ifindex; + + if (rtnl_dump_request (&rth, type_id[type_index], &tm, sizeof (tm)) < 0) + { + ERROR ("netlink plugin: ir_read: rtnl_dump_request failed."); + continue; + } + + if (rtnl_dump_filter (&rth, qos_filter, (void *) &ifindex, + NULL, NULL) != 0) + { + ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed."); + continue; + } + } /* for (type_index) */ + } /* for (if_index) */ return (0); -} /* int print_stats */ +} /* int ir_read */ static int ir_shutdown (void) {