more changes for config reload handling
authorFelix Fietkau <nbd@openwrt.org>
Sun, 2 Oct 2011 23:56:37 +0000 (01:56 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 2 Oct 2011 23:56:37 +0000 (01:56 +0200)
config.c
config.h
device.c
device.h
interface.c

index ff0410da10f44bf8a48a9aa16c96b3831a55b511..4f3a3cd77fd5860190f44a2797a9fc038c88e789 100644 (file)
--- a/config.c
+++ b/config.c
@@ -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;
        }
index 6dfb236186b47c64d1a56bf62477c13d6ab082b4..c4953c6ddc82abe0b307be29ef3f46a10a015c7b 100644 (file)
--- a/config.h
+++ b/config.h
@@ -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
index 77594be367ce1dfb6ba70c176b05ea4135d9128d..caadbc3cd731e156f7424b5fefba752ff421f9ad 100644 (file)
--- a/device.c
+++ b/device.c
@@ -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;
 }
index f1cdda00efaeb06aeb37fa9beff4eb727536eff8..907b9c660684327feb7e39b18f9915795be50826 100644 (file)
--- a/device.h
+++ b/device.h
@@ -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 */
index 5b503144ba0d73a8fd2e96654efbd471068037a2..435b485dc901ba2226e572e9f41392a6d4bf5165 100644 (file)
@@ -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;
 }