diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-10-03 01:56:37 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2011-10-03 01:56:37 +0200 |
commit | f6b38cb7c9ad0e7feba7cb7d2a1678af5e032000 (patch) | |
tree | bdd8833e10c25ebfc7d017e12d505619aac3ff6a | |
parent | 39f5ec857a31fe65e14cdf9b75927297e78015bb (diff) |
more changes for config reload handling
-rw-r--r-- | config.c | 52 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | device.c | 76 | ||||
-rw-r--r-- | device.h | 10 | ||||
-rw-r--r-- | interface.c | 3 |
5 files changed, 127 insertions, 16 deletions
@@ -274,22 +274,56 @@ config_check_equal(struct blob_attr *c1, struct blob_attr *c2, return true; } -void -config_init_interfaces(const char *name) +struct blob_attr * +config_memdup(struct blob_attr *attr) { - struct uci_context *ctx; + struct blob_attr *ret; + int size = blob_pad_len(attr); + + ret = malloc(size); + if (!ret) + return NULL; + + memcpy(ret, attr, size); + return ret; +} + +static struct uci_package * +config_init_package(const char *config) +{ + struct uci_context *ctx = uci_ctx; struct uci_package *p = NULL; - struct uci_element *e; - ctx = uci_alloc_context(); - uci_ctx = ctx; + if (!ctx) { + ctx = uci_alloc_context(); + uci_ctx = ctx; #ifdef DUMMY_MODE - uci_set_confdir(ctx, "./config"); - uci_set_savedir(ctx, "./tmp"); + uci_set_confdir(ctx, "./config"); + uci_set_savedir(ctx, "./tmp"); #endif + } else { + p = uci_lookup_package(ctx, config); + if (p) + uci_unload(ctx, p); + } + + if (uci_load(ctx, "network", &p)) + return NULL; + + return p; +} + +void +config_init_interfaces(const char *name) +{ + struct uci_context *ctx; + struct uci_package *p = NULL; + struct uci_element *e; - if (uci_load(ctx, "network", &p)) { + p = config_init_package("network"); + ctx = uci_ctx; + if (!p) { fprintf(stderr, "Failed to load network config\n"); return; } @@ -45,4 +45,6 @@ bool config_check_equal(struct blob_attr *c1, struct blob_attr *c2, bool config_diff(struct blob_attr **tb1, struct blob_attr **tb2, const struct config_param_list *config, unsigned long *diff); +struct blob_attr *config_memdup(struct blob_attr *attr); + #endif @@ -298,15 +298,81 @@ device_free_unused(struct device *dev) __device_free_unused(dev); } +enum dev_change_type +device_reload_config(struct device *dev, struct blob_attr *attr) +{ + struct blob_attr *tb[__DEV_ATTR_MAX], *tb1[__DEV_ATTR_MAX]; + + blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, + blob_data(attr), blob_len(attr)); + blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb1, + blob_data(dev->config), blob_len(dev->config)); + + if (!config_diff(tb, tb1, &device_attr_list, NULL)) + return DEV_CONFIG_NO_CHANGE; + + device_init_settings(dev, tb); + return DEV_CONFIG_APPLIED; +} + +static enum dev_change_type +device_check_config(struct device *dev, struct blob_attr *attr) +{ + if (dev->type->reload) + return dev->type->reload(dev, attr); + + return device_reload_config(dev, attr); +} + +static void +device_replace(struct device *dev, struct device *odev) +{ + struct device_user *dep, *tmp; + bool present = odev->present; + + if (present) + device_set_present(odev, false); + + list_for_each_entry_safe(dep, tmp, &odev->users, list) { + list_move_tail(&dep->list, &dev->users); + dep->dev = dev; + } + device_free(odev); + + if (present) + device_set_present(dev, true); +} + struct device * device_create(const char *name, const struct device_type *type, struct blob_attr *config) { - struct device *dev; + struct device *odev = NULL, *dev; + enum dev_change_type change; + + odev = device_get(name, false); + if (odev) { + change = device_check_config(odev, config); + switch (change) { + case DEV_CONFIG_APPLIED: + free(odev->config); + odev->config = config_memdup(config); + if (odev->present) { + device_set_present(odev, false); + device_set_present(odev, true); + } + /* fall through */ + case DEV_CONFIG_NO_CHANGE: + return odev; + case DEV_CONFIG_RECREATE: + break; + } + } - dev = device_get(name, false); - if (dev) - return dev; + dev = type->create(config); + dev->config = config_memdup(config); + if (odev) + device_replace(dev, odev); - return type->create(config); + return dev; } @@ -19,6 +19,12 @@ enum { __DEV_ATTR_MAX, }; +enum dev_change_type { + DEV_CONFIG_NO_CHANGE, + DEV_CONFIG_APPLIED, + DEV_CONFIG_RECREATE, +}; + struct device_type { struct list_head list; const char *name; @@ -26,6 +32,7 @@ struct device_type { const struct config_param_list *config_params; struct device *(*create)(struct blob_attr *attr); + enum dev_change_type (*reload)(struct device *, struct blob_attr *); void (*dump_status)(struct device *, struct blob_buf *buf); int (*check_state)(struct device *); void (*free)(struct device *); @@ -50,6 +57,7 @@ struct device { char ifname[IFNAMSIZ + 1]; int ifindex; + struct blob_attr *config; bool present; int active; @@ -64,8 +72,6 @@ struct device { unsigned int mtu; unsigned int txqueuelen; uint8_t macaddr[6]; - - uint32_t config_hash; }; /* events broadcasted to all users of a device */ diff --git a/interface.c b/interface.c index 5b50314..435b485 100644 --- a/interface.c +++ b/interface.c @@ -384,6 +384,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new) set_config_state(if_old, IFC_RELOAD); free(old_config); + free(if_new); } static void @@ -410,4 +411,6 @@ interface_init_list(void) { vlist_init(&interfaces, avl_strcmp, interface_update, struct interface, node, name); + interfaces.keep_old = true; + interfaces.no_delete = true; } |