From 3603060d6fd06e67e27696b3925bbe9bd464b5aa Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner <michal.vaner@nic.cz> Date: Wed, 25 Nov 2015 14:42:52 +0100 Subject: [PATCH] fwup: Don't delete the set when changing only the size When the set size is being changed, it is not needed to remove the set from kernel and create it again. And it wouldn't even work in case the ipset is already linked into the firewall. Simply reloading the content by swapping with a newly created set is OK. --- src/plugins/fwup/main.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/plugins/fwup/main.c b/src/plugins/fwup/main.c index c6d34bdf..4d3e266c 100644 --- a/src/plugins/fwup/main.c +++ b/src/plugins/fwup/main.c @@ -159,6 +159,8 @@ static void version_ask(struct context *context, const char *setname) { uplink_plugin_send_message(context, message, len); } +static void set_reload(struct context *context, struct set *set); + static void config_parse(struct context *context, const uint8_t *data, size_t length) { struct config c; sanity(length >= sizeof c, "Not enough FWUp data for config, got %zu, needed %zu\n", length, sizeof c); @@ -202,12 +204,21 @@ static void config_parse(struct context *context, const uint8_t *data, size_t le // Go through the new ones and look for corresponding sets in the old config for (size_t i = 0; i < target_count; i ++) { for (size_t j = 0; j < u->set_count; j ++) - if (strcmp(sets[i].name, u->sets[j].name) == 0 && sets[i].type == u->sets[j].type && sets[i].max_size == u->sets[j].max_size && sets[i].hash_size == u->sets[j].hash_size) { + if (strcmp(sets[i].name, u->sets[j].name) == 0 && sets[i].type == u->sets[j].type) { switch (u->sets[j].state) { case SS_DEAD: diff_addr_store_cp(sets[i].store, u->sets[j].store, context->temp_pool); sets[i].state = SS_VALID; // We got the data, it is valid now u->sets[j].state = SS_COPIED; + if (sets[i].hash_size != u->sets[j].hash_size || sets[i].max_size != u->sets[j].max_size) { + /* + * It is the same set with the same content, + * but the sizes changed. Therefore, we need + * to reload the set in kernel. Swapping sets + * of different sizes seems to work. + */ + set_reload(context, &sets[i]); + } break; case SS_DEAD_PENDING: // No valid data inside. So nothing to copy, really. @@ -396,17 +407,21 @@ static void replace_add(const uint8_t *key, size_t key_size, struct trie_data *d add_item(store, key, key_size); } +static void set_reload(struct context *context, struct set *set) { + set->context = context; + // Reuse the hooks to replace the content of the set and to add items there. + replace_start(set->store); + trie_walk(set->store->trie, replace_add, set->store, context->temp_pool); + replace_end(set->store); + set->context = NULL; +} + static void sets_reload(struct context *context) { ulog(LLOG_INFO, "Reloading all IPsets\n"); struct user_data *u = context->user_data; for (size_t i = 0; i < u->set_count; i ++) { struct set *s = &u->sets[i]; - s->context = context; - // Reuse the hooks to replace the content of the set and to add items there. - replace_start(s->store); - trie_walk(s->store->trie, replace_add, s->store, context->temp_pool); - replace_end(s->store); - s->context = NULL; + set_reload(context, s); } } -- GitLab