From f87baeb3e0096a43d4647f549078c53bec68543f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 10 Jun 2009 14:37:36 +0000 Subject: wprobe: move measurement task to the kernel, add some configurability (work in progress) SVN-Revision: 16402 --- package/wprobe/src/user/wprobe-info.c | 117 ++++++++++++++++++---------- package/wprobe/src/user/wprobe.c | 139 +++++++++++++++++++++++++++++----- package/wprobe/src/user/wprobe.h | 60 +++++++++------ 3 files changed, 232 insertions(+), 84 deletions(-) (limited to 'package/wprobe/src/user') diff --git a/package/wprobe/src/user/wprobe-info.c b/package/wprobe/src/user/wprobe-info.c index b8918711c6..8361c02754 100644 --- a/package/wprobe/src/user/wprobe-info.c +++ b/package/wprobe/src/user/wprobe-info.c @@ -64,15 +64,15 @@ wprobe_dump_value(struct wprobe_attribute *attr) static void -wprobe_dump_data(const char *ifname, struct list_head *gl, struct list_head *ll, struct list_head *ls) +wprobe_dump_data(struct wprobe_iface *dev) { struct wprobe_attribute *attr; struct wprobe_link *link; bool first = true; fprintf(stderr, "\n"); - wprobe_request_data(ifname, gl, NULL, 2); - list_for_each_entry(attr, gl, list) { + wprobe_request_data(dev, NULL); + list_for_each_entry(attr, &dev->global_attr, list) { fprintf(stderr, (first ? "Global: %s=%s\n" : " %s=%s\n"), @@ -82,10 +82,10 @@ wprobe_dump_data(const char *ifname, struct list_head *gl, struct list_head *ll, first = false; } - list_for_each_entry(link, ls, list) { + list_for_each_entry(link, &dev->links, list) { first = true; - wprobe_request_data(ifname, ll, link->addr, 2); - list_for_each_entry(attr, ll, list) { + wprobe_request_data(dev, link->addr); + list_for_each_entry(attr, &dev->link_attr, list) { if (first) { fprintf(stderr, "%02x:%02x:%02x:%02x:%02x:%02x: %s=%s\n", @@ -119,57 +119,92 @@ static const char *attr_typestr[] = { static int usage(const char *prog) { - fprintf(stderr, "Usage: %s \n", prog); - return 1; + fprintf(stderr, + "Usage: %s [options]\n" + "\n" + "Options:\n" + " -c: Only apply configuration\n" + " -h: This help text\n" + " -i : Set measurement interval\n" + " -m: Run measurement loop\n" + "\n" + , prog); + exit(1); } -int main(int argc, char **argv) +static void show_attributes(struct wprobe_iface *dev) { struct wprobe_attribute *attr; - const char *ifname; - LIST_HEAD(global_attr); - LIST_HEAD(link_attr); - LIST_HEAD(links); - int i = 0; + list_for_each_entry(attr, &dev->global_attr, list) { + fprintf(stderr, "Global attribute: '%s' (%s)\n", + attr->name, attr_typestr[attr->type]); + } + list_for_each_entry(attr, &dev->link_attr, list) { + fprintf(stderr, "Link attribute: '%s' (%s)\n", + attr->name, attr_typestr[attr->type]); + } +} - if (argc < 2) - return usage(argv[0]); +static void loop_measurement(struct wprobe_iface *dev) +{ + while (1) { + sleep(1); + wprobe_update_links(dev); + wprobe_dump_data(dev); + } +} - ifname = argv[1]; +int main(int argc, char **argv) +{ + struct wprobe_iface *dev; + const char *ifname; + const char *prog = argv[0]; + enum { + CMD_NONE, + CMD_CONFIG, + CMD_MEASURE, + } cmd = CMD_NONE; + int ch; - if (wprobe_init() != 0) - return -1; + if ((argc < 2) || (argv[1][0] == '-')) + return usage(prog); - wprobe_dump_attributes(ifname, false, &global_attr, NULL); - wprobe_dump_attributes(ifname, true, &link_attr, NULL); + ifname = argv[1]; + dev = wprobe_get_dev(ifname); + argv++; + argc--; - if (list_empty(&global_attr) && - list_empty(&link_attr)) { + if (!dev || (list_empty(&dev->global_attr) && + list_empty(&dev->link_attr))) { fprintf(stderr, "Interface '%s' not found\n", ifname); return -1; } - list_for_each_entry(attr, &global_attr, list) { - fprintf(stderr, "Global attribute: '%s' (%s)\n", - attr->name, attr_typestr[attr->type]); - } - list_for_each_entry(attr, &link_attr, list) { - fprintf(stderr, "Link attribute: '%s' (%s)\n", - attr->name, attr_typestr[attr->type]); + while ((ch = getopt(argc, argv, "chi:m")) != -1) { + switch(ch) { + case 'c': + cmd = CMD_CONFIG; + break; + case 'm': + cmd = CMD_MEASURE; + break; + case 'i': + dev->interval = strtoul(optarg, NULL, 10); + break; + case 'h': + default: + usage(prog); + break; + } } - while (1) { - usleep(100 * 1000); - wprobe_measure(ifname); - - if (i-- > 0) - continue; + wprobe_apply_config(dev); + if (cmd != CMD_CONFIG) + show_attributes(dev); + if (cmd == CMD_MEASURE) + loop_measurement(dev); - i = 10; - wprobe_update_links(ifname, &links); - wprobe_dump_data(ifname, &global_attr, &link_attr, &links); - } - wprobe_free(); + wprobe_free_dev(dev); return 0; } diff --git a/package/wprobe/src/user/wprobe.c b/package/wprobe/src/user/wprobe.c index 1f8df6c7e9..e48f768e54 100644 --- a/package/wprobe/src/user/wprobe.c +++ b/package/wprobe/src/user/wprobe.c @@ -35,6 +35,7 @@ #define DPRINTF(fmt, ...) do {} while (0) #endif +static int n_devs = 0; static struct nl_sock *handle = NULL; static struct nl_cache *cache = NULL; static struct genl_family *family = NULL; @@ -83,9 +84,16 @@ ack_handler(struct nl_msg *msg, void *arg) } -void +static void wprobe_free(void) { + /* should not happen */ + if (n_devs == 0) + return; + + if (--n_devs != 0) + return; + if (cache) nl_cache_free(cache); if (handle) @@ -94,11 +102,14 @@ wprobe_free(void) cache = NULL; } -int +static int wprobe_init(void) { int ret; + if (n_devs++ > 0) + return 0; + handle = nl_socket_alloc(); if (!handle) { DPRINTF("Failed to create handle\n"); @@ -233,8 +244,8 @@ save_attribute_handler(struct nl_msg *msg, void *arg) } -int -wprobe_dump_attributes(const char *ifname, bool link, struct list_head *list, char *addr) +static int +dump_attributes(const char *ifname, bool link, struct list_head *list, char *addr) { struct nl_msg *msg; struct wprobe_attr_cb cb; @@ -255,6 +266,64 @@ nla_put_failure: return -EINVAL; } +struct wprobe_iface * +wprobe_get_dev(const char *ifname) +{ + struct wprobe_iface *dev; + + if (wprobe_init() != 0) + return NULL; + + dev = malloc(sizeof(struct wprobe_iface)); + if (!dev) + return NULL; + + memset(dev, 0, sizeof(struct wprobe_iface)); + dev->ifname = strdup(ifname); + if (!dev->ifname) + goto error; + + dev->interval = -1; + dev->scale_min = -1; + dev->scale_max = -1; + dev->scale_m = -1; + dev->scale_d = -1; + + INIT_LIST_HEAD(&dev->global_attr); + INIT_LIST_HEAD(&dev->link_attr); + INIT_LIST_HEAD(&dev->links); + + dump_attributes(ifname, false, &dev->global_attr, NULL); + dump_attributes(ifname, true, &dev->link_attr, NULL); + + return dev; + +error: + free(dev); + return NULL; +} + +static void +free_attr_list(struct list_head *list) +{ + struct wprobe_attribute *attr, *tmp; + + list_for_each_entry_safe(attr, tmp, list, list) { + list_del(&attr->list); + free(attr); + } +} + +void +wprobe_free_dev(struct wprobe_iface *dev) +{ + wprobe_free(); + free_attr_list(&dev->global_attr); + free_attr_list(&dev->link_attr); + free((void *)dev->ifname); + free(dev); +} + static struct wprobe_link * get_link(struct list_head *list, const char *addr) { @@ -313,7 +382,7 @@ save_link_handler(struct nl_msg *msg, void *arg) int -wprobe_update_links(const char *ifname, struct list_head *list) +wprobe_update_links(struct wprobe_iface *dev) { struct wprobe_link *l, *tmp; struct nl_msg *msg; @@ -321,10 +390,10 @@ wprobe_update_links(const char *ifname, struct list_head *list) int err; INIT_LIST_HEAD(&cb.old_list); - list_splice_init(list, &cb.old_list); - cb.list = list; + list_splice_init(&dev->links, &cb.old_list); + cb.list = &dev->links; - msg = wprobe_new_msg(ifname, WPROBE_CMD_GET_LINKS, true); + msg = wprobe_new_msg(dev->ifname, WPROBE_CMD_GET_LINKS, true); if (!msg) return -ENOMEM; @@ -340,16 +409,37 @@ wprobe_update_links(const char *ifname, struct list_head *list) return 0; } -void -wprobe_measure(const char *ifname) +int +wprobe_apply_config(struct wprobe_iface *dev) { struct nl_msg *msg; - msg = wprobe_new_msg(ifname, WPROBE_CMD_MEASURE, false); + msg = wprobe_new_msg(dev->ifname, WPROBE_CMD_CONFIG, false); if (!msg) - return; + return -ENOMEM; + + if (dev->interval >= 0) + NLA_PUT_MSECS(msg, WPROBE_ATTR_INTERVAL, dev->interval); + + wprobe_send_msg(msg, NULL, NULL); + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; +} + +int +wprobe_measure(struct wprobe_iface *dev) +{ + struct nl_msg *msg; + + msg = wprobe_new_msg(dev->ifname, WPROBE_CMD_MEASURE, false); + if (!msg) + return -ENOMEM; wprobe_send_msg(msg, NULL, NULL); + return 0; } struct wprobe_request_cb { @@ -431,6 +521,10 @@ found: if (attr->val.n > 0) { float avg = ((float) attr->val.s) / attr->val.n; float stdev = sqrt((((float) attr->val.ss) / attr->val.n) - (avg * avg)); + if (isnan(stdev)) + stdev = 0.0f; + if (isnan(avg)) + avg = 0.0f; attr->val.avg = avg; attr->val.stdev = stdev; } @@ -443,25 +537,24 @@ out: int -wprobe_request_data(const char *ifname, struct list_head *attrs, const unsigned char *addr, int scale) +wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr) { struct wprobe_request_cb cb; + struct list_head *attrs; struct nl_msg *msg; int err; - msg = wprobe_new_msg(ifname, WPROBE_CMD_GET_INFO, true); + msg = wprobe_new_msg(dev->ifname, WPROBE_CMD_GET_INFO, true); if (!msg) return -ENOMEM; - if (scale < 0) - NLA_PUT_U32(msg, WPROBE_ATTR_FLAGS, WPROBE_F_RESET); - else if (scale > 0) - NLA_PUT_U32(msg, WPROBE_ATTR_SCALE, scale); - - if (addr) + if (addr) { + attrs = &dev->link_attr; NLA_PUT(msg, WPROBE_ATTR_MAC, 6, addr); + } else { + attrs = &dev->global_attr; + } -nla_put_failure: INIT_LIST_HEAD(&cb.old_list); list_splice_init(attrs, &cb.old_list); cb.list = attrs; @@ -469,6 +562,10 @@ nla_put_failure: err = wprobe_send_msg(msg, save_attrdata_handler, &cb); list_splice(&cb.old_list, attrs->prev); return err; + +nla_put_failure: + nlmsg_free(msg); + return -ENOMEM; } diff --git a/package/wprobe/src/user/wprobe.h b/package/wprobe/src/user/wprobe.h index e0c33faef2..c0b4902f3c 100644 --- a/package/wprobe/src/user/wprobe.h +++ b/package/wprobe/src/user/wprobe.h @@ -87,15 +87,21 @@ struct wprobe_link { unsigned char addr[6]; }; -/** - * wprobe_init: initialize internal data structures and connect to the wprobe netlink api - */ -extern int wprobe_init(void); +struct wprobe_iface { + const char *ifname; + char addr[6]; -/** - * wprobe_free: free all internally allocated data structures - */ -extern void wprobe_free(void); + struct list_head global_attr; + struct list_head link_attr; + struct list_head links; + + /* config */ + int interval; + int scale_min; + int scale_max; + int scale_m; + int scale_d; +}; /** * wprobe_update_links: get a list of all link partners @@ -105,7 +111,7 @@ extern void wprobe_free(void); * when wprobe_update_links is called multiple times, the linked list * is updated with new link partners, old entries are automatically expired */ -extern int wprobe_update_links(const char *ifname, struct list_head *list); +extern int wprobe_update_links(struct wprobe_iface *dev); /** * wprobe_measure: start a measurement request for all global attributes @@ -115,29 +121,39 @@ extern int wprobe_update_links(const char *ifname, struct list_head *list); * it may be desirable to control the sampling interval from user space * you can use this function to do that. */ -extern void wprobe_measure(const char *ifname); +extern int wprobe_measure(struct wprobe_iface *dev); /** - * wprobe_dump_attributes: create a linked list of available attributes + * wprobe_get_dev: get device information * @ifname: name of the wprobe interface - * @link: false: get the list of global attributes; true: get the list of per-link attributes - * @list: linked list to store the attributes in - * @addr: buffer to store the interface's mac address in (optional) * - * attributes must be freed by the caller + * queries the wprobe interface for all attributes + * must be freed with wprobe_free_dev + */ +extern struct wprobe_iface *wprobe_get_dev(const char *ifname); + +/** + * wprobe_get_dev: free all device information + * @dev: wprobe device structure + */ +extern void wprobe_free_dev(struct wprobe_iface *dev); + +/** + * wprobe_apply_config: apply configuration data + * @dev: wprobe device structure + * + * uploads all configuration values from @dev that are not set to -1 */ -extern int wprobe_dump_attributes(const char *ifname, bool link, struct list_head *list, char *addr); +extern int wprobe_apply_config(struct wprobe_iface *dev); /** * wprobe_request_data: request new sampling values for the given list of attributes - * @ifname: name of the wprobe interface - * @attrs: attribute list + * @dev: wprobe device structure * @addr: (optional) mac address of the link partner - * @scale: scale down values by a factor (scale < 0: reset statistics entirely) * - * if addr is unset, attrs must point to the list of global attributes, - * if addr is set, attrs must point to the list of per-link attributes + * if addr is unset, global values are stored in the global attributes list + * if addr is set, per-link values for the given address are stored in the link attributes list */ -extern int wprobe_request_data(const char *ifname, struct list_head *attrs, const unsigned char *addr, int scale); +extern int wprobe_request_data(struct wprobe_iface *dev, const unsigned char *addr); #endif -- cgit v1.2.3