From d64c608820ddb4817ef7dff1f993a5801ff99ca2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Oct 2011 15:29:05 +0200 Subject: [PATCH] implement a new ubus object "network.device", add a method for dumping detailed device information --- bridge.c | 6 +-- device.c | 33 ++++++++++++++++ device.h | 4 +- system-dummy.c | 5 +++ system-linux.c | 45 ++++++++++++++++++++++ system.h | 1 + ubus.c | 102 ++++++++++++++++++++++++++----------------------- 7 files changed, 145 insertions(+), 51 deletions(-) diff --git a/bridge.c b/bridge.c index caf6197..5ac5cfe 100644 --- a/bridge.c +++ b/bridge.c @@ -44,7 +44,7 @@ static const struct config_param_list bridge_attr_list = { static struct device *bridge_create(struct blob_attr *attr); static void bridge_config_init(struct device *dev); static void bridge_free(struct device *dev); -static void bridge_dump_status(struct device *dev, struct blob_buf *b); +static void bridge_dump_info(struct device *dev, struct blob_buf *b); const struct device_type bridge_device_type = { .name = "Bridge", @@ -53,7 +53,7 @@ const struct device_type bridge_device_type = { .create = bridge_create, .config_init = bridge_config_init, .free = bridge_free, - .dump_status = bridge_dump_status, + .dump_info = bridge_dump_info, }; struct bridge_state { @@ -303,7 +303,7 @@ bridge_free(struct device *dev) } static void -bridge_dump_status(struct device *dev, struct blob_buf *b) +bridge_dump_info(struct device *dev, struct blob_buf *b) { struct bridge_state *bst; struct bridge_member *bm; diff --git a/device.c b/device.c index 6929177..092a8ed 100644 --- a/device.c +++ b/device.c @@ -469,3 +469,36 @@ device_create(const char *name, const struct device_type *type, return dev; } + +void +device_dump_status(struct blob_buf *b, struct device *dev) +{ + void *c, *s; + + if (!dev) { + avl_for_each_element(&devices, dev, avl) { + if (!dev->present) + continue; + c = blobmsg_open_table(b, dev->ifname); + device_dump_status(b, dev); + blobmsg_close_table(b, c); + } + + return; + } + + if (!dev->present) + return; + + blobmsg_add_string(b, "type", dev->type->name); + blobmsg_add_u8(b, "up", !!dev->active); + if (dev->type->dump_info) + dev->type->dump_info(dev, b); + + s = blobmsg_open_table(b, "statistics"); + if (dev->type->dump_stats) + dev->type->dump_stats(dev, b); + else + system_if_dump_stats(dev, b); + blobmsg_close_table(b, s); +} diff --git a/device.h b/device.h index 176d1ef..659bcf1 100644 --- a/device.h +++ b/device.h @@ -34,7 +34,8 @@ struct device_type { struct device *(*create)(struct blob_attr *attr); void (*config_init)(struct device *); enum dev_change_type (*reload)(struct device *, struct blob_attr *); - void (*dump_status)(struct device *, struct blob_buf *buf); + void (*dump_info)(struct device *, struct blob_buf *buf); + void (*dump_stats)(struct device *, struct blob_buf *buf); int (*check_state)(struct device *); void (*free)(struct device *); }; @@ -132,6 +133,7 @@ void device_set_present(struct device *dev, bool state); int device_claim(struct device_user *dep); void device_release(struct device_user *dep); int device_check_state(struct device *dev); +void device_dump_status(struct blob_buf *b, struct device *dev); static inline void device_free(struct device *dev) diff --git a/system-dummy.c b/system-dummy.c index 4c9a8fc..e6187f3 100644 --- a/system-dummy.c +++ b/system-dummy.c @@ -79,6 +79,11 @@ int system_if_check(struct device *dev) return 0; } +int system_if_dump_stats(struct device *dev, struct blob_buf *b) +{ + return 0; +} + int system_add_address(struct device *dev, struct device_addr *addr) { uint8_t *a = (uint8_t *) &addr->addr.in; diff --git a/system-linux.c b/system-linux.c index aba603f..e04fa23 100644 --- a/system-linux.c +++ b/system-linux.c @@ -1,3 +1,5 @@ +#define _GNU_SOURCE + #include #include #include @@ -316,6 +318,49 @@ int system_if_check(struct device *dev) return 0; } +int system_if_dump_stats(struct device *dev, struct blob_buf *b) +{ + const char *const counters[] = { + "collisions", "rx_frame_errors", "tx_compressed", + "multicast", "rx_length_errors", "tx_dropped", + "rx_bytes", "rx_missed_errors", "tx_errors", + "rx_compressed", "rx_over_errors", "tx_fifo_errors", + "rx_crc_errors", "rx_packets", "tx_heartbeat_errors", + "rx_dropped", "tx_aborted_errors", "tx_packets", + "rx_errors", "tx_bytes", "tx_window_errors", + "rx_fifo_errors", "tx_carrier_errors", + }; + char buf[64]; + int stats_dir; + int i, fd, len; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname); + stats_dir = open(buf, O_DIRECTORY); + if (stats_dir < 0) + return -1; + + for (i = 0; i < ARRAY_SIZE(counters); i++) { + fd = openat(stats_dir, counters[i], O_RDONLY); + if (fd < 0) + continue; + +retry: + len = read(fd, buf, sizeof(buf)); + if (len < 0) { + if (errno == EINTR) + goto retry; + continue; + } + + buf[len] = 0; + blobmsg_add_u32(b, counters[i], strtoul(buf, NULL, 0)); + close(fd); + } + + close(stats_dir); + return 0; +} + static int system_addr(struct device *dev, struct device_addr *addr, int cmd) { int alen = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16; diff --git a/system.h b/system.h index 392e46b..4155281 100644 --- a/system.h +++ b/system.h @@ -37,6 +37,7 @@ void system_if_clear_state(struct device *dev); int system_if_up(struct device *dev); int system_if_down(struct device *dev); int system_if_check(struct device *dev); +int system_if_dump_stats(struct device *dev, struct blob_buf *b); int system_add_address(struct device *dev, struct device_addr *addr); int system_del_address(struct device *dev, struct device_addr *addr); diff --git a/ubus.c b/ubus.c index 973718c..8c237c3 100644 --- a/ubus.c +++ b/ubus.c @@ -11,44 +11,6 @@ static struct blob_buf b; /* global object */ -enum { - DEV_NAME, - DEV_FORCE, - __DEV_MAX, - __DEV_MAX_NOFORCE = __DEV_MAX - 1, -}; - -static const struct blobmsg_policy dev_policy[__DEV_MAX] = { - [DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, - [DEV_FORCE] = { .name = "force", .type = BLOBMSG_TYPE_INT8 }, -}; - -static int -netifd_handle_device(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct device *dev; - struct blob_attr *tb[__DEV_MAX]; - bool add = !strncmp(method, "add", 3); - - blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg)); - - if (!tb[DEV_NAME]) - return UBUS_STATUS_INVALID_ARGUMENT; - - dev = device_get(blobmsg_data(tb[DEV_NAME]), false); - if (!dev) - return UBUS_STATUS_NOT_FOUND; - - if (!add || (tb[DEV_FORCE] && blobmsg_get_u8(tb[DEV_FORCE]))) - device_set_present(dev, add); - else - device_check_state(dev); - - return 0; -} - static int netifd_handle_restart(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -68,8 +30,6 @@ netifd_handle_reload(struct ubus_context *ctx, struct ubus_object *obj, } static struct ubus_method main_object_methods[] = { - UBUS_METHOD("add_device", netifd_handle_device, dev_policy), - UBUS_METHOD("remove_device", netifd_handle_device, dev_policy), { .name = "restart", .handler = netifd_handle_restart }, { .name = "reload", .handler = netifd_handle_reload }, }; @@ -84,6 +44,52 @@ static struct ubus_object main_object = { .n_methods = ARRAY_SIZE(main_object_methods), }; +enum { + DEV_NAME, + __DEV_MAX, +}; + +static const struct blobmsg_policy dev_policy[__DEV_MAX] = { + [DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, +}; + +static int +netifd_dev_status(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct device *dev = NULL; + struct blob_attr *tb[__DEV_MAX]; + + blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg)); + + if (tb[DEV_NAME]) { + dev = device_get(blobmsg_data(tb[DEV_NAME]), false); + if (!dev) + return UBUS_STATUS_INVALID_ARGUMENT; + } + + blob_buf_init(&b, 0); + device_dump_status(&b, dev); + ubus_send_reply(ctx, req, b.head); + + return 0; +} + +static struct ubus_method dev_object_methods[] = { + UBUS_METHOD("status", netifd_dev_status, dev_policy) +}; + +static struct ubus_object_type dev_object_type = + UBUS_OBJECT_TYPE("device", dev_object_methods); + +static struct ubus_object dev_object = { + .name = "network.device", + .type = &dev_object_type, + .methods = dev_object_methods, + .n_methods = ARRAY_SIZE(dev_object_methods), +}; + int netifd_ubus_init(const char *path) { @@ -98,10 +104,15 @@ netifd_ubus_init(const char *path) ubus_add_uloop(ctx); ret = ubus_add_object(ctx, &main_object); + if (ret) + goto out; + + ret = ubus_add_object(ctx, &dev_object); + +out: if (ret != 0) fprintf(stderr, "Failed to publish object: %s\n", ubus_strerror(ret)); - - return 0; + return ret; } void @@ -198,9 +209,6 @@ netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj, devinfo = blobmsg_open_table(&b, field); blobmsg_add_string(&b, "name", dev->ifname); - if (dev->type->dump_status) - dev->type->dump_status(dev, &b); - blobmsg_close_table(&b, devinfo); } @@ -304,9 +312,9 @@ static struct ubus_method iface_object_methods[] = { { .name = "down", .handler = netifd_handle_down }, { .name = "status", .handler = netifd_handle_status }, { .name = "add_device", .handler = netifd_iface_handle_device, - .policy = dev_policy, .n_policy = __DEV_MAX_NOFORCE }, + .policy = dev_policy, .n_policy = __DEV_MAX }, { .name = "remove_device", .handler = netifd_iface_handle_device, - .policy = dev_policy, .n_policy = __DEV_MAX_NOFORCE }, + .policy = dev_policy, .n_policy = __DEV_MAX }, { .name = "notify_proto", .handler = netifd_iface_notify_proto }, { .name = "remove", .handler = netifd_iface_remove } }; -- 2.25.1