[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 03939) UMIP: Dynamic reloading of the configuration



Hi,

The attached patch aims to implement support for dynamically reload the configuration in mip6d daemon. It allows for example to add new MNs in the HA configuration file without loosing all existing bindings. Updating the IPsec policies and bind_acl entries is supported.

More information on what can be changed in the configuration is included in the patch as an addition to the mip6d.conf man page.

The patch applies on the current git tree.

Please feel free to remove the "#ifdef NEMO" sections; these will only be useful to NEPL users.

Please let me know if you have questions with regards to this patch.

Best regards,
Sebastien.
Nautilus6.org
diff --git a/man/mip6d.conf.tmpl b/man/mip6d.conf.tmpl
index 5791fdf..8e9f322 100644
--- a/man/mip6d.conf.tmpl
+++ b/man/mip6d.conf.tmpl
@@ -12,6 +12,10 @@ Below is a list of currently supported configuration options. All
 configuration lines are terminated with a semicolon.  Sub-sections are
 enclosed in '{' and '}'.  Strings are quoted with double quotes.
 
+Default value is given when available.
+
+Indication of supported dynamic changes on SIGHUP is also provided.
+
 .SH COMMON OPTIONS
 
 The file contains the following common definitions:
@@ -23,6 +27,8 @@ Mobile Node mode.
 
 Default: CN
 
+Change on reloading: No support. Daemon must be restarted.
+
 .TP
 .BR "DebugLevel "  number ";"
 
@@ -32,13 +38,16 @@ printed on the controlling tty).
 
 Default: 0
 
+Change on reloading: Partial support. Cannot detach from tty afterwards.
+
 .TP
 .BR "DoRouteOptimizationCN " "boolean" ";"
 
 Indicates if a node should participate in route optimization with a
 Mobile Node.
 
-Default: enabled
+This option is currently ignored. When the daemon is running, the peer 
+always answers RO requests from other MNs.
 
 .TP
 .BR "NonVolatileBindingCache " "boolean" ";"
@@ -86,6 +95,9 @@ this interface, the interface type should be set to CN.
 Default: same as
 .B NodeConfig
 
+Change on reloading: partial support. Only new inet6 interfaces will 
+use the new configuration.
+
 
 .TP
 .BR "UseMnHaIPsec " "boolean" ";"
@@ -94,6 +106,8 @@ Indicates if the MN-HA MIPv6 signalling should be protected with IPsec.
 
 Default: enabled
 
+Change on reloading: no support.
+
 .TP
 .BR "KeyMngMobCapability " "boolean" ";"
 
@@ -103,6 +117,8 @@ acknowledgements.
 
 Default: disabled
 
+Change on reloading: supported.
+
 .TP
 .nf
 .BR "IPsecPolicySet {"
@@ -123,6 +139,9 @@ option.  For home agent, home agent address field contains its own
 address, and home address fields may contain any number of mobile
 nodes for which the same policy applies.
 
+Change on reloading: supported. The sets can be changed, added or removed. 
+Removing rules for established bindings may have unpredicted effects.
+
 .B IPsecPolicy
 has the following format:
 
@@ -157,18 +176,24 @@ Limits the maximum lifetime (in seconds) for Mobile Node home registrations.
 
 Default: 262140
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "SendMobPfxAdvs " "boolean" ";"
 
 Controls whether home agent sends Mobile Prefix Advertisements to
 mobile nodes in foreign networks.
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "SendUnsolMobPfxAdvs " "boolean" ";"
 
 Controls whether home agent send unsolicited Mobile Prefix
 Advertisements to mobile nodes in foreign networks.
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "MinMobPfxAdvInterval " "number" ";"
 
@@ -176,6 +201,8 @@ Sets a minimum interval (in seconds) for Mobile Prefix Advertisements.
 
 Default: 600
 
+Change on reloading: Partial support. Only affects new scheduled MPA.
+
 .TP
 .BR "MaxMobPfxAdvInterval " "number" ";"
 
@@ -183,12 +210,16 @@ Sets a maximum interval (in seconds) for Mobile Prefix Advertisements.
 
 Default: 86400
 
+Change on reloading: Partial support. Only affects new scheduled MPA.
+
 .TP
 .BR "BindingAclPolicy " "address " "allow | deny"
 
 Defines if a MN is allowed to register with the HA or not. The MN home address
 of the MN is given in the address field."
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "DefaultBindingAclPolicy allow | deny"
 
@@ -197,6 +228,8 @@ a MN.
 
 Default: allow
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .SH MOBILE NODE SPECIFIC OPTIONS
 
 The following definitions are ignored unless the node is configured as a MN:
@@ -208,6 +241,8 @@ Limits the maximum lifetime (in seconds) for Mobile Node home registrations.
 
 Default: 262140
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "MnMaxCnBindingLife " "number" ";"
 
@@ -216,6 +251,8 @@ Node registrations.
 
 Default: 420
 
+Change on reloading: Partial support. Only affects new bindings.
+
 .TP
 .BR "MnDiscardHaParamProb " "boolean" ";"
 
@@ -228,20 +265,26 @@ by IPsec.
 
 Default: disabled
 
+Change on reloading: Supported.
+
 .TP
 .BR "SendMobPfxSols " "boolean" ";"
 
 Controls whether mobile node sends Mobile Prefix Solicitations to the
 home network.
 
+Change on reloading: Supported.
+
 .TP
 .BR "DoRouteOptimizationMN " "boolean" ";"
 
 Indicates if the Mobile Node should initialize route optimization with
-Corresponent Nodes.
+Correspondent Nodes.
 
 Default: enabled
 
+Change on reloading: Partial support, deactivation is not supported.
+
 .TP
 .BR "MnUseAllInterfaces enabled | disabled"
 
@@ -253,6 +296,8 @@ options to explicitly list the used interfaces.
 
 Default: disabled
 
+Change on reloading: Same support as "Interface" directive.
+
 .TP
 .BR "UseCnBuAck " "boolean" ";"
 
@@ -261,6 +306,8 @@ Corresponent Nodes.
 
 Default: disabled
 
+Change on reloading: Supported.
+
 .TP
 .BR "MnRouterProbes " "number" ";"
 
@@ -271,6 +318,8 @@ will move to the new router straight away.
 
 Default: 0
 
+Change on reloading: Supported.
+
 .TP
 .BR "MnRouterProbeTimeout " "decimal" ";"
 
@@ -284,6 +333,8 @@ before proceeding with the handoff.
 
 Default: 0
 
+Change on reloading: Supported.
+
 .TP
 .BR "OptimisticHandoff  enabled | disabled"
 
@@ -296,6 +347,8 @@ before using RO or reverse tunneling.
 
 Default: disabled;
 
+Change on reloading: Supported.
+
 .TP
 .nf
 .BR "MnHomeLink " "name " "{"
@@ -314,7 +367,12 @@ set up multiple Home Addresses on the Mobile Node, you need to define
 multiple
 .B MnHomeLink
 structures.  The interface names don't have to be unique in these
-definitions.  All the home link specific definitions are detailed below: 
+definitions. 
+
+Change on reloading: No support. 
+The daemon has to be restarted for the changes in this directive to take effect.
+
+All the home link specific definitions are detailed below: 
 
 .TP
 .BR "HomeAddress " "address/length" ";"
diff --git a/man/mip6d.tmpl b/man/mip6d.tmpl
index 2120d93..ea0f075 100644
--- a/man/mip6d.tmpl
+++ b/man/mip6d.tmpl
@@ -29,6 +29,16 @@ Node is HA
 .IP "\fB\-M, \-\-mobile-node\fP"
 Node is MN
 
+.SH SIGNALS
+
+The following signals can be sent to the daemon:
+.IP "\fB\ SIGHUP\fP"
+Reload the configuration. See 
+.BR mip6d.conf (5)
+for information on supported changes.
+.IP "\fB\ SIGINT, SIGTERM\fP"
+Terminates the daemon operation.
+
 .SH FILES
 
 %etc%/mip6d.conf
diff --git a/src/Makefile.am b/src/Makefile.am
index bea7cbe..9a10734 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,7 @@ sbin_PROGRAMS = mip6d
 
 mip6d_SOURCES = pmgr.c pmgr.h defpath.h \
 		main.c vars.c mipv6.h \
-		conf.c conf.h \
+		conf.c conf.h conf_changes.c \
 		gram.y scan.l \
 		tqueue.c tqueue.h \
 		icmp6.c icmp6.h \
diff --git a/src/conf.c b/src/conf.c
index 4b418ef..2cdb83d 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -46,6 +46,8 @@
 #include "debug.h"
 #include "util.h"
 #include "mipv6.h"
+#include "mn.h"
+#include "xfrm.h"
 #ifdef ENABLE_VT
 #include "vt.h"
 #endif
@@ -195,7 +197,7 @@ static void conf_default(struct mip6_config *c)
 	c->vt_service = VT_DEFAULT_SERVICE;
 #endif
 	c->mip6_entity = MIP6_ENTITY_CN;
-	pmgr_init(NULL, &conf.pmgr);
+	pmgr_init(NULL, &c->pmgr);
 	INIT_LIST_HEAD(&c->net_ifaces);
 	INIT_LIST_HEAD(&c->bind_acl);
 	c->DefaultBindingAclPolicy = IP6_MH_BAS_ACCEPTED;
@@ -263,6 +265,8 @@ int conf_parse(struct mip6_config *c, int argc, char **argv)
 
 void conf_show(struct mip6_config *c)
 {
+	struct list_head *list;
+
 	/* Common options */
 	dbg("config_file = %s\n", c->config_file);
 #ifdef ENABLE_VT
@@ -276,6 +280,23 @@ void conf_show(struct mip6_config *c)
 	if (c->pmgr.so_path)
 		dbg("PolicyModulePath = %s\n", c->pmgr.so_path);
 	dbg("DefaultBindingAclPolicy = %u\n", c->DefaultBindingAclPolicy);
+	list_for_each(list, &c->bind_acl) {
+		struct policy_bind_acl_entry *acl;
+		acl = list_entry(list, struct policy_bind_acl_entry, list);
+#ifdef NEMO
+		dbg("%x:%x:%x:%x:%x:%x:%x:%x (%d): %s\n", 
+		     NIP6ADDR(&acl->hoa), 
+		     acl->mnp_count, 
+		     acl->bind_policy?"allow":"deny"
+		     );
+#else /* NEMO */		  
+		dbg("%x:%x:%x:%x:%x:%x:%x:%x : %s\n", 
+		     NIP6ADDR(&acl->hoa), 
+		     acl->bind_policy?"allow":"deny"
+		     );
+#endif /* NEMO */
+	}
+	
 	dbg("NonVolatileBindingCache = %s\n",
 	    CONF_BOOL_STR(c->NonVolatileBindingCache));
 	
@@ -317,3 +338,78 @@ void conf_show(struct mip6_config *c)
 	dbg("DoRouteOptimizationCN = %s\n",
 	    CONF_BOOL_STR(c->DoRouteOptimizationCN));
 }
+
+
+static void conf_free(struct mip6_config *c)
+{
+	struct list_head *h, *nh, *e, *ne;
+	struct home_addr_info * hai;
+	
+	if (c->config_file)
+		free(c->config_file);
+		
+	pmgr_close(&c->pmgr);
+	
+	/* For each home_addr_info, we have to remove the intern lists mob_net_prefix and ro_policy */
+	list_for_each_safe(h, nh, &c->home_addrs)
+	{
+		hai = list_entry(h, struct home_addr_info, list);
+		
+		list_del(h);
+		
+		list_for_each_safe(e, ne, &hai->ro_policies)
+		{
+			list_del(e);
+			free( list_entry(e, struct xfrm_ro_pol, list) );
+		}
+		
+#ifdef NEMO		
+		list_for_each_safe(e, ne, &hai->mob_net_prefixes)
+		{
+			list_del(e);
+			free( list_entry(e, struct prefix_list_entry, list) );
+		}
+#endif /* NEMO */
+		
+		free(hai);
+	}
+	
+	/* The other lists must have been emptied during the apply_changes_cb function */
+	free(c);
+
+}
+
+
+int conf_update(struct mip6_config *c, void (*apply_changes_cb)(struct mip6_config *, struct mip6_config *))
+{
+	/* c is a pointer to the current config.
+	   We want to update some data from c according to the changed configuration file */
+	struct mip6_config *conf_new = NULL;
+	int ret = 0;
+	
+	conf_new = malloc(sizeof(*conf_new));
+	if (!conf_new)
+	{
+		perror("conf_update");
+		return -1;
+	}
+	
+	conf_default(conf_new);
+	
+	conf_parsed = conf_new;
+	
+	if ((ret = conf_file(conf_new, c->config_file)) < 0)
+	{
+		dbg("Error in the new configuration file, changes not applied\n");
+	}
+	
+	conf_parsed = c;
+	
+	/* Ok now we have the new config in conf_new, we can compute the differences that we are interrested in */
+	if (!ret)
+		apply_changes_cb(c, conf_new);
+	
+	conf_free(conf_new);
+	
+	return ret;
+}
diff --git a/src/conf.h b/src/conf.h
index 96c36f3..143f2a9 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -67,6 +67,7 @@ struct net_iface {
 };
 
 extern struct mip6_config conf;
+extern struct mip6_config *conf_parsed;
 
 #define MIP6_ENTITY_NO -1
 #define MIP6_ENTITY_CN 0
@@ -121,4 +122,6 @@ int yyparse(void);
 
 int yylex(void);
 
+int conf_update(struct mip6_config *c, void (*apply_changes_cb)(struct mip6_config *, struct mip6_config *));
+
 #endif
diff --git a/src/conf_changes.c b/src/conf_changes.c
new file mode 100644
index 0000000..2a1cb6a
--- /dev/null
+++ b/src/conf_changes.c
@@ -0,0 +1,678 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+
+#include "conf.h"
+#include "debug.h"
+#include "list.h"
+#include "policy.h"
+#include "prefix.h"
+#include "ipsec.h"
+
+
+
+/****************************************************************************************************************/
+
+
+#define FCT_LIST_CHANGES(struct_name, member) \
+  static void parse_change_in_##struct_name (	struct list_head *cur_list, \
+  						struct list_head *new_list, \
+						int (*cb_cmp)(struct struct_name * a, struct struct_name * b), \
+						void (*cb_free)(struct struct_name * elem), \
+						void (*cb_add)(struct struct_name * new_item), \
+						void (*cb_rem)(struct struct_name * old_item) )\
+  { \
+  	/* We update the cur_list to add new elements from new_list and remove elements that in are not there. */ \
+	/* The comparison function between elements is cb_cmp (cannot be NULL) */ \
+	/* if cb_free is NULL, free() is called to delete an unused element of the list, otherwise cb_free is called */ \
+	/* if cb_add is not NULL, it is called for each new element that is being added in the list */ \
+	/* if cb_rem is not NULL, it is called for each element that is removed from cur_list */ \
+	struct list_head *cur_i, *cur_n, *new_i, *new_n; \
+	struct struct_name *cur_el, *new_el; \
+	int found; \
+	\
+	list_for_each_safe(cur_i, cur_n, cur_list) \
+	{ \
+		found=0; \
+		cur_el = list_entry(cur_i, struct struct_name, member); \
+		list_for_each_safe(new_i, new_n, new_list) \
+		{ \
+			new_el = list_entry(new_i, struct struct_name, member); \
+			\
+			if (! cb_cmp(cur_el, new_el) )\
+			{ \
+				/* This element is in both lists, not interesting, we remove from new_list */ \
+				found = 1; \
+				list_del(new_i); \
+				if (cb_free) \
+					cb_free(new_el); \
+				else \
+					free(new_el); \
+			} \
+		} \
+		\
+		if ( ! found ) \
+		{ \
+			/* The element was not found in the new list: it has been removed */ \
+			list_del(cur_i); \
+			if (cb_rem) \
+				cb_rem(cur_el); \
+			if (cb_free) \
+				cb_free(cur_el); \
+			else \
+				free(cur_el); \
+		} \
+	} \
+	/* Now new_list contains only the elements that have been added in the config */ \
+	list_for_each_safe(new_i, new_n, new_list) \
+	{ \
+		list_del(new_i); \
+		if (cb_add) \
+		{ \
+			new_el = list_entry(new_i, struct struct_name, member); \
+			cb_add(new_el); \
+		} \
+		list_add_tail(new_i, cur_list); \
+	} \
+	/* The cur_list has been updated */ \
+  }
+
+
+/****************************************************************************************************************/
+
+/*****************************************/
+/****   Updating the net_ifaces list  ****/
+/*****************************************/
+
+/* define parse_change_in_net_iface */
+FCT_LIST_CHANGES(net_iface, list)
+
+/* Compare function */
+int cmp_net_iface(struct net_iface *a, struct net_iface *b)
+{
+	if (	(a->ifindex 		!= b->ifindex		)
+	     || (a->is_rtr		!= b->is_rtr		)
+	     || (a->mip6_if_entity	!= b->mip6_if_entity	)
+	     || (a->mn_if_preference	!= b->mn_if_preference	) )
+		return -1;
+	
+	return strncmp(a->name, b->name, IF_NAMESIZE);
+}
+
+/* Add function (just to be verbose, can be safely removed) */
+void add_net_iface(struct net_iface *nif)
+{
+	char nifname[IF_NAMESIZE + 1];
+	memcpy(&nifname[0], nif->name, IF_NAMESIZE);
+	nifname[IF_NAMESIZE] = '\0';
+	dbg("Added new interface %d:%s with preference %d\n", nif->ifindex, nifname, nif->mn_if_preference);
+}
+
+/* Remove function (just to be verbose, can be safely removed) */
+void rem_net_iface(struct net_iface *nif)
+{
+	char nifname[IF_NAMESIZE + 1];
+	memcpy(&nifname[0], nif->name, IF_NAMESIZE);
+	nifname[IF_NAMESIZE] = '\0';
+	dbg("Removed interface %d:%s with preference %d\n", nif->ifindex, nifname, nif->mn_if_preference);
+}
+
+
+
+/*****************************************/
+/****   Updating the bind_acl list  ****/
+/*****************************************/
+
+/* define parse_change_in_policy_bind_acl_entry */
+FCT_LIST_CHANGES(policy_bind_acl_entry, list)
+
+/* Compare function */
+int cmp_policy_bind_acl_entry(struct policy_bind_acl_entry *a, struct policy_bind_acl_entry *b)
+{
+	struct list_head *a_item, *b_item ;
+	struct prefix_list_entry *a_ple, *b_ple;
+	
+	/* Check if both entries are for the same hoa */
+	if (!IN6_ARE_ADDR_EQUAL(&a->hoa, &b->hoa))
+		return -1;
+	
+	/* Check other parameters */
+	if (	(a->plen 	!= b->plen        )
+	     || (a->bind_policy	!= b->bind_policy )
+#ifdef NEMO
+	     || (a->mnp_count 	!= b->mnp_count   ) 
+#endif /* NEMO */
+	     )
+	{
+		dbg("Found change in bind_acl configuration for hoa: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&a->hoa));
+	     	return -1;
+	}
+	
+#ifdef NEMO
+	/* Now we should check that the prefixes in the mob_net_prefixes are the same 
+	 * We just suppose that the parser would always create the list in the same order.
+	 */
+	for (a_item = (a->mob_net_prefixes).next, b_item = (b->mob_net_prefixes).next; 
+		a_item != (&a->mob_net_prefixes) && b_item != (&b->mob_net_prefixes)  ;
+		a_item = a_item->next,             b_item = b_item->next)
+	{
+		a_ple = list_entry(a_item, struct prefix_list_entry, list);
+		b_ple = list_entry(b_item, struct prefix_list_entry, list);
+		if ((a_ple->ple_plen != b_ple->ple_plen) 
+		    || !IN6_ARE_ADDR_EQUAL(&a_ple->ple_prefix, &b_ple->ple_prefix))
+		{
+			dbg("Found difference in mobiles prefixes lists for hoa %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&a->hoa));
+			dbg("%x:%x:%x:%x:%x:%x:%x:%x/%d and %x:%x:%x:%x:%x:%x:%x:%x/d\n", 
+				NIP6ADDR(&a_ple->ple_prefix), a_ple->ple_plen,
+				NIP6ADDR(&b_ple->ple_prefix), b_ple->ple_plen);
+		    	return -1;
+		}
+	}
+	/* We know already the lists have the same # of elements */
+#endif /* NEMO */
+	
+	return 0;
+}
+
+/* these functions are in policy.c to manage the hash table entries related to the config */
+extern int policy_bind_acl_add(struct policy_bind_acl_entry *acl);
+extern int policy_bind_acl_rem(struct policy_bind_acl_entry *acl);
+
+/* Add function */
+void add_policy_bind_acl_entry(struct policy_bind_acl_entry *nif)
+{
+	dbg("Adding bind_acl entry for hoa: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&nif->hoa));
+	if (policy_bind_acl_add(nif) < 0)
+	{
+		dbg("Adding the bind_acl failed.\n");
+	}
+}
+
+/* Remove function */
+void rem_policy_bind_acl_entry(struct policy_bind_acl_entry *nif)
+{
+	dbg("Removing bind_acl entry for hoa: %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&nif->hoa));
+	if (policy_bind_acl_rem(nif) < 0)
+	{
+		dbg("Removing the bind_acl failed.\n");
+	}
+}
+
+#ifdef NEMO
+/* Cleanup function */
+void free_policy_bind_acl_entry(struct policy_bind_acl_entry *nif)
+{
+	struct list_head *i, *n;
+	struct prefix_list_entry *ple;
+	list_for_each_safe(i, n, &nif->mob_net_prefixes)
+	{
+		ple = list_entry(i, struct prefix_list_entry, list);
+		list_del(i);
+		free(ple);
+	}
+	free(nif);
+}
+#endif /* NEMO */
+
+/*************************************************/
+/****   Updating the DefaultBindingAclPolicy  ****/
+/*************************************************/
+extern int def_bind_policy;
+
+
+
+/*********************************************/
+/****   Updating the ipsec_policies list  ****/
+/*********************************************/
+
+/* define parse_change_in_ipsec_policy_entry */
+FCT_LIST_CHANGES(ipsec_policy_entry, list)
+
+/* Compare function */
+int cmp_ipsec_policy_entry(struct ipsec_policy_entry *a, struct ipsec_policy_entry *b)
+{
+	if (    (! IN6_ARE_ADDR_EQUAL(&a->mn_addr, &b->mn_addr))
+	    ||  (! IN6_ARE_ADDR_EQUAL(&a->ha_addr, &b->ha_addr))
+	    ||  ( a->type != b->type )
+	    ||  ( a->ipsec_protos != b->ipsec_protos )
+	    ||  ( a->action  !=  b->action )
+	    ||  ( a->reqid_toha != b->reqid_toha )
+	    ||  ( a->reqid_tomn != b->reqid_tomn ))
+	   	return -1;
+	
+	return 0;
+}
+
+extern int _ha_mn_ipsec_init(const struct in6_addr *haaddr,
+			     const struct in6_addr *hoa,
+			     struct ipsec_policy_entry *e,
+			     void *arg);
+extern int _ha_mn_ipsec_cleanup(const struct in6_addr *haaddr,
+				const struct in6_addr *hoa,
+				struct ipsec_policy_entry *e,
+				void *arg);
+extern int _mn_ha_ipsec_init(const struct in6_addr *haaddr,
+			     const struct in6_addr *hoa,
+			     struct ipsec_policy_entry *e,
+			     void *arg);
+extern int _mn_ha_ipsec_cleanup(const struct in6_addr *haaddr,
+				const struct in6_addr *hoa,
+				struct ipsec_policy_entry *e,
+				void *arg);
+extern int ipsec_policy_dump_config(const struct in6_addr *haaddr,
+			     const struct in6_addr *hoa,
+			     struct ipsec_policy_entry *e, void *arg);
+
+
+/* Add function */
+void add_ipsec_policy_entry(struct ipsec_policy_entry *e)
+{
+	dbg("New IPsec policy: (HA %x:%x:%x:%x:%x:%x:%x:%x) (MN %x:%x:%x:%x:%x:%x:%x:%x) (t:%x)\n", 
+	      NIP6ADDR(&e->ha_addr), NIP6ADDR(&e->mn_addr), e->type);	
+	if (is_ha())
+		if (_ha_mn_ipsec_init(&e->ha_addr, &e->mn_addr, e, NULL))
+		{
+			fprintf(stderr, "Failed to insert new IPsec policy\n");
+			ipsec_policy_dump_config(&e->ha_addr, &e->mn_addr, e, NULL);
+		}
+	if (is_mn())
+		if (_mn_ha_ipsec_init(&e->ha_addr, &e->mn_addr, e, NULL))
+		{
+			fprintf(stderr, "Failed to insert new IPsec policy\n");
+			ipsec_policy_dump_config(&e->ha_addr, &e->mn_addr, e, NULL);
+		}
+}
+
+/* Remove function */
+void rem_ipsec_policy_entry(struct ipsec_policy_entry *e)
+{
+	dbg("Removing IPsec policy: (HA %x:%x:%x:%x:%x:%x:%x:%x) (MN %x:%x:%x:%x:%x:%x:%x:%x) (t:%x)\n", 
+	      NIP6ADDR(&e->ha_addr), NIP6ADDR(&e->mn_addr), e->type);	
+	if (is_ha())
+		if (_ha_mn_ipsec_cleanup(&e->ha_addr, &e->mn_addr, e, NULL))
+		{
+			fprintf(stderr, "Failed to remove IPsec policy\n");
+			ipsec_policy_dump_config(&e->ha_addr, &e->mn_addr, e, NULL);
+		}
+	if (is_mn())
+		if (_mn_ha_ipsec_cleanup(&e->ha_addr, &e->mn_addr, e, NULL))
+		{
+			fprintf(stderr, "Failed to remove IPsec policy\n");
+			ipsec_policy_dump_config(&e->ha_addr, &e->mn_addr, e, NULL);
+		}
+}
+
+
+
+/*********************************************/
+/****   Updating the ipsec_policies list  ****/
+/*********************************************/
+
+/* define parse_change_in_ipsec_policy_entry */
+FCT_LIST_CHANGES(prefix_list_entry, list)
+
+/* Compare function */
+int cmp_prefix_list_entry(struct prefix_list_entry *a, struct prefix_list_entry *b)
+{
+	if ((a->ple_plen != b->ple_plen) 
+	    || !IN6_ARE_ADDR_EQUAL(&a->ple_prefix, &b->ple_prefix))
+	{
+	    	return -1;
+	}
+	
+	return 0;
+}
+
+/* Add function */
+void add_prefix_list_entry(struct prefix_list_entry *ple)
+{
+	dbg("HaServedPrefix: added prefix: %x:%x:%x:%x:%x:%x:%x:%x/%d\n", 
+			NIP6ADDR(&ple->ple_prefix), ple->ple_plen);
+	return;
+}
+
+/* Rem function */
+void rem_prefix_list_entry(struct prefix_list_entry *ple)
+{
+	dbg("HaServedPrefix: removed prefix: %x:%x:%x:%x:%x:%x:%x:%x/%d\n", 
+			NIP6ADDR(&ple->ple_prefix), ple->ple_plen);
+	return;
+}
+
+
+
+/*****************************************************************************************************************/
+
+
+/*********************************************/
+/*  The function that updates the config     */
+/*********************************************/
+void conf_apply_changes(struct mip6_config *cur, struct mip6_config *new)
+{
+	/* config_file: this field is not changed */
+	
+	/* (NodeConfig) mip6_entity: cannot change on-the-fly */
+	if (cur->mip6_entity != new->mip6_entity)
+	{
+		fprintf(stderr, "Cannot change the role on-the-fly\n");
+		return;
+	}
+	
+	
+#if defined(ENABLE_VT) && 0  /* Actually the VT definition is not in the configuration file so ... we should not change it */ 
+	/* If the vt options are changed, we close the old vt and open a new one */
+	if (   strcmp(cur->vt_hostname, new->vt_hostname) 
+	    || strcmp(cur->vt_service, new->vt_service) )
+	{
+		dbg("Restarting virtual terminal ( %s(%s) -> %s(%s) )\n", cur->vt_hostname, cur->vt_service, new->vt_hostname, new->vt_service);
+
+		vt_fini();
+
+		free(cur->vt_hostname);
+		cur->vt_hostname = new->vt_hosname;
+
+		free(cur->vt_service);
+		cur->vt_service  = new->vt_service;
+		
+		if (vt_start(cur->vt_hostname, cur->vt_service) < 0)
+		{
+			fprintf(stderr, "Failed to restart the virtual terminal on new host/port\n");
+		}
+	}
+#endif /* ENABLE_VT && 0 */
+	
+	
+	/* (DebugLevel) debug_level: update the value */
+	if (new->debug_level != cur->debug_level)
+	{
+		dbg("Changing DebugLogFile (old=%d)\n", cur->debug_level);
+		cur->debug_level = new->debug_level;
+		dbg("Changing DebugLogFile (new=%d)\n", cur->debug_level);
+	}
+	
+		
+	/* (DebugLogFile) debug_log_file: no support yet */
+	if (strcmp(cur->debug_log_file?cur->debug_log_file:"", new->debug_log_file?new->debug_log_file:""))
+	{
+		fprintf(stderr, "Changing the DebugLogFile is not supported currently.\n");
+	}
+	
+	
+	/* (UsePolicyModule) pmgr: not supported */
+	if (strncmp(cur->pmgr.so_path, new->pmgr.so_path, _POSIX_PATH_MAX))
+	{
+		fprintf(stderr, "Changing the UsePolicyModule is not supported currently (%s -> %s).\n", cur->pmgr.so_path, new->pmgr.so_path);
+	}
+	
+	
+	/* (Interface) net_ifaces: update the list */
+	parse_change_in_net_iface(	&cur->net_ifaces, 
+					&new->net_ifaces, 
+					cmp_net_iface, 
+					NULL, 
+					add_net_iface, 
+					rem_net_iface);
+	
+	
+	/* (BindingAclPolicy) bind_acl: update the conf and the hash (policy_bind_acl_hash) in policy.c */
+	parse_change_in_policy_bind_acl_entry(
+					&cur->bind_acl,
+					&new->bind_acl, 
+					cmp_policy_bind_acl_entry, 
+#ifdef NEMO
+					free_policy_bind_acl_entry, 
+#else  /* NEMO */
+					NULL,
+#endif /* NEMO */
+					add_policy_bind_acl_entry, 
+					rem_policy_bind_acl_entry);
+					
+	
+	/* (DefaultBindingAclPolicy) DefaultBindingAclPolicy: update the value in config and copy in policy.c */
+	if (new->DefaultBindingAclPolicy != cur->DefaultBindingAclPolicy)
+	{
+		dbg("New DefaultBindingAclPolicy: %u\n", new->DefaultBindingAclPolicy);
+		cur->DefaultBindingAclPolicy = new->DefaultBindingAclPolicy;
+		def_bind_policy = new->DefaultBindingAclPolicy;
+	}
+	
+
+	/* (NonVolatileBindingCache) NonVolatileBindingCache: update the value in config */
+	if (new->NonVolatileBindingCache != cur->NonVolatileBindingCache)
+	{
+		dbg("New NonVolatileBindingCache: %s\n", new->NonVolatileBindingCache ? "enabled" : "disabled");
+		cur->NonVolatileBindingCache = new->NonVolatileBindingCache;
+	}
+
+
+	/* (KeyMngMobCapability) KeyMngMobCapability: update the value in config */
+	if (new->KeyMngMobCapability != cur->KeyMngMobCapability)
+	{
+		dbg("New KeyMngMobCapability: %s\n", new->KeyMngMobCapability ? "enabled" : "disabled");
+		cur->KeyMngMobCapability = new->KeyMngMobCapability;
+	}
+
+
+	/* (UseMnHaIPsec) UseMnHaIPsec: No change allowed. */
+	if (new->UseMnHaIPsec != cur->UseMnHaIPsec)
+	{
+		fprintf(stderr, "Changing UseMnHaIPsec is not currently supported\n");
+	}
+	
+	
+	/* (IPsecPolicySet) ipsec_policies: update the conf and insert / remove SPD entries if required */
+	if (cur->UseMnHaIPsec)
+		parse_change_in_ipsec_policy_entry(
+					&cur->ipsec_policies,
+					&new->ipsec_policies, 
+					cmp_ipsec_policy_entry, 
+					NULL, 
+					add_ipsec_policy_entry, 
+					rem_ipsec_policy_entry);
+
+
+	/* (MnMaxCnBindingLife) MnMaxCnBindingLife: update the value */
+	if (new->MnMaxCnBindingLife != cur->MnMaxCnBindingLife)
+	{
+		dbg("New MnMaxCnBindingLife: %u (only affects new bindings)\n", new->MnMaxCnBindingLife);
+		cur->MnMaxCnBindingLife = new->MnMaxCnBindingLife;
+	}
+	
+
+	/* (MnRouterProbes) MnRouterProbes: update the value */
+	if (new->MnRouterProbes != cur->MnRouterProbes)
+	{
+		dbg("New MnRouterProbes: %u\n", new->MnRouterProbes);
+		cur->MnRouterProbes = new->MnRouterProbes;
+	}
+
+	
+#define ts_equal(a , b) \
+	(((a).tv_sec == (b).tv_sec) && ((a).tv_nsec == (b).tv_nsec))
+	
+	/* (MnRouterProbeTimeout) MnRouterProbeTimeout_ts: update the value */
+	if (! ts_equal(new->MnRouterProbeTimeout_ts, cur->MnRouterProbeTimeout_ts))
+	{
+		dbg("New MnRouterProbeTimeout: %f\n", tstodsec(new->MnRouterProbeTimeout_ts));
+		cur->MnRouterProbeTimeout_ts = new->MnRouterProbeTimeout_ts;
+	}
+	
+	
+	/* (InitialBindackTimeoutFirstReg) InitialBindackTimeoutFirstReg_ts: update the value */
+	if (! ts_equal(new->InitialBindackTimeoutFirstReg_ts, cur->InitialBindackTimeoutFirstReg_ts))
+	{
+		dbg("New InitialBindackTimeoutFirstReg: %f (will only affect new bindings)\n", tstodsec(new->InitialBindackTimeoutFirstReg_ts));
+		cur->InitialBindackTimeoutFirstReg_ts = new->InitialBindackTimeoutFirstReg_ts;
+	}
+	
+	
+	/* (InitialBindackTimeoutReReg) InitialBindackTimeoutReReg_ts: update the value */
+	if (! ts_equal(new->InitialBindackTimeoutReReg_ts, cur->InitialBindackTimeoutReReg_ts))
+	{
+		dbg("New InitialBindackTimeoutReReg: %f (does not affect existing bindings until they expire)\n", tstodsec(new->InitialBindackTimeoutReReg_ts));
+		cur->InitialBindackTimeoutReReg_ts = new->InitialBindackTimeoutReReg_ts;
+	}
+	
+
+	/* (MnHomeLink) home_addrs: not supported */
+	if (is_mn())
+		dbg("MnHomeLink directive ignored currently (only used on MN nodes)\n");
+	/* TODO:
+		compare the old list and the new one, using hai_name for example.
+		For new entries, call conf_home_addr_info
+		Do not remove deleted entries (or think carefully at the side effects)
+		For the entries that match the hai_name, compare all elements and update the matching entry in 
+		    home_addr_list global list if required.
+	*/
+	
+	
+	/* (UseMovementModule) MoveModulePath: not implemented yet, should be NULL */
+	if (new->MoveModulePath != cur->MoveModulePath)
+	{
+		fprintf(stderr, "Changing UseMovementModule is not supported.\n");
+	}
+	
+	
+	/* (UseCnBuAck) CnBuAck: update the value in config */
+	if (new->CnBuAck != cur->CnBuAck)
+	{
+		dbg("New UseCnBuAck: %s\n", new->CnBuAck ? "enabled" : "disabled");
+		cur->CnBuAck = new->CnBuAck;
+	}
+
+	
+#ifdef NEMO
+	/* (MobRtrUseExplicitMode) MobRtrUseExplicitMode: update the value in config */
+	if (new->MobRtrUseExplicitMode != cur->MobRtrUseExplicitMode)
+	{
+		dbg("New MobRtrUseExplicitMode: %s\n", new->MobRtrUseExplicitMode ? "enabled" : "disabled");
+		cur->MobRtrUseExplicitMode = new->MobRtrUseExplicitMode;
+	}
+#endif /* NEMO */
+
+	/* (DoRouteOptimizationMN) DoRouteOptimizationMN: deactivation not supported (may need changes in xfrm.c) */
+	if (new->DoRouteOptimizationMN != cur->DoRouteOptimizationMN)
+	{
+		if (! new->DoRouteOptimizationMN)
+			fprintf(stderr, "Deactivating DoRouteOptimizationMN is not supported.\n");
+		else
+		{
+			cur->DoRouteOptimizationMN = new->DoRouteOptimizationMN;
+			dbg("New DoRouteOptimizationMN: %s\n", new->DoRouteOptimizationMN ? "enabled" : "disabled");
+		}
+	}
+	
+	
+	/* (MnUseAllInterfaces) MnUseAllInterfaces: update the value in config */
+	if (new->MnUseAllInterfaces != cur->MnUseAllInterfaces)
+	{
+		dbg("New MnUseAllInterfaces: %s (only affects new interfaces)\n", new->MnUseAllInterfaces ? "enabled" : "disabled");
+		cur->MnUseAllInterfaces = new->MnUseAllInterfaces;
+	}
+
+
+	/* (MnDiscardHaParamProb) MnDiscardHaParamProb: update the value in config */
+	if (new->MnDiscardHaParamProb != cur->MnDiscardHaParamProb)
+	{
+		dbg("New MnDiscardHaParamProb: %s\n", new->MnDiscardHaParamProb ? "enabled" : "disabled");
+		cur->MnDiscardHaParamProb = new->MnDiscardHaParamProb;
+	}
+
+	
+	/* (SendMobPfxSols) SendMobPfxSols: update the value in config */
+	if (new->SendMobPfxSols != cur->SendMobPfxSols)
+	{
+		dbg("New SendMobPfxSols: %s\n", new->SendMobPfxSols ? "enabled" : "disabled");
+		cur->SendMobPfxSols = new->SendMobPfxSols;
+		
+		/* If disabled => need to cancel the pending job? (will be the last) */
+		/* If enabled  => need to call mpd_trigger_mps ? With what Hoa / HA ? */
+	}
+
+
+	/* (OptimisticHandoff) OptimisticHandoff: update the value in config */
+	if (new->OptimisticHandoff != cur->OptimisticHandoff)
+	{
+		dbg("New OptimisticHandoff: %s\n", new->OptimisticHandoff ? "enabled" : "disabled");
+		cur->OptimisticHandoff = new->OptimisticHandoff;
+	}
+
+	
+#ifdef NEMO
+	/* (HaAcceptMobRtr) HaAcceptMobRtr: update the value in config */
+	if (new->HaAcceptMobRtr != cur->HaAcceptMobRtr)
+	{
+		dbg("New HaAcceptMobRtr: %s\n", new->HaAcceptMobRtr ? "enabled" : "disabled");
+		cur->HaAcceptMobRtr = new->HaAcceptMobRtr;
+	}
+#endif /* NEMO */
+
+	/* (SendMobPfxAdvs) SendMobPfxAdvs: update the value in config */
+	if (new->SendMobPfxAdvs != cur->SendMobPfxAdvs)
+	{
+		dbg("New SendMobPfxAdvs: %s\n", new->SendMobPfxAdvs ? "enabled" : "disabled");
+		cur->SendMobPfxAdvs = new->SendMobPfxAdvs;
+	}
+
+	
+	/* (SendUnsolMobPfxAdvs) SendUnsolMobPfxAdvs: update the value in config */
+	if (new->SendUnsolMobPfxAdvs != cur->SendUnsolMobPfxAdvs)
+	{
+		dbg("New SendUnsolMobPfxAdvs: %s\n", new->SendUnsolMobPfxAdvs ? "enabled" : "disabled");
+		cur->SendUnsolMobPfxAdvs = new->SendUnsolMobPfxAdvs;
+		
+		/* If enabled  => mpd_start_mpa will be called for following BUs (that s enough) */
+	}
+
+	
+	/* (MaxMobPfxAdvInterval) MaxMobPfxAdvInterval: update the value in config */
+	if (new->MaxMobPfxAdvInterval != cur->MaxMobPfxAdvInterval)
+	{
+		dbg("New MaxMobPfxAdvInterval: %u\n", new->MaxMobPfxAdvInterval);
+		cur->MaxMobPfxAdvInterval = new->MaxMobPfxAdvInterval;
+	}
+
+
+	/* (MinMobPfxAdvInterval) MinMobPfxAdvInterval: update the value in config */
+	if (new->MinMobPfxAdvInterval != cur->MinMobPfxAdvInterval)
+	{
+		dbg("New MinMobPfxAdvInterval: %u\n", new->MinMobPfxAdvInterval);
+		cur->MinMobPfxAdvInterval = new->MinMobPfxAdvInterval;
+	}
+
+	
+	/* (HaMaxBindingLife) HaMaxBindingLife: update the value in config */
+	if (new->HaMaxBindingLife != cur->HaMaxBindingLife)
+	{
+		dbg("New HaMaxBindingLife: %u\n", new->HaMaxBindingLife);
+		cur->HaMaxBindingLife = new->HaMaxBindingLife;
+	}
+
+	
+#ifdef NEMO
+	/* (HaServedPrefix) nemo_ha_served_prefixes: update the value in config */
+	parse_change_in_prefix_list_entry(	&cur->nemo_ha_served_prefixes, 
+						&new->nemo_ha_served_prefixes, 
+						cmp_prefix_list_entry, 
+						NULL,
+						add_prefix_list_entry, 
+						rem_prefix_list_entry);
+#endif /* NEMO */
+	
+
+	/* (DoRouteOptimizationCN) DoRouteOptimizationCN: Update the value, even if it s not used... */
+	if (new->DoRouteOptimizationCN != cur->DoRouteOptimizationCN)
+	{
+		dbg("New DoRouteOptimizationCN: %s\n", new->DoRouteOptimizationCN ? "enabled" : "disabled");
+		cur->DoRouteOptimizationCN = new->DoRouteOptimizationCN;
+	}
+
+
+	return;
+}
+
diff --git a/src/gram.y b/src/gram.y
index ccda368..b13f02b 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -72,7 +72,7 @@ extern int lineno;
 extern char *yytext;
 
 static void yyerror(char *s) {
-	fprintf(stderr, "Error in configuration file %s\n", conf.config_file);
+	fprintf(stderr, "Error in configuration file %s\n", conf_parsed->config_file);
 	fprintf(stderr, "line %d: %s at '%s'\n", lineno, s, yytext);
 }
 
@@ -80,7 +80,7 @@ static void uerror(const char *fmt, ...) {
 	char s[1024];
 	va_list args;
 
-	fprintf(stderr, "Error in configuration file %s\n", conf.config_file);
+	fprintf(stderr, "Error in configuration file %s\n", conf_parsed->config_file);
 	va_start(args, fmt);
 	vsprintf(s, fmt, args);
 	fprintf(stderr, "line %d: %s\n", lineno, s);
@@ -189,48 +189,48 @@ grammar		: topdef
 
 topdef		: MIP6ENTITY mip6entity ';'
 		{
-			conf.mip6_entity = $2;
+			conf_parsed->mip6_entity = $2;
 		}
 		| DEBUGLEVEL NUMBER ';'
 		{
-			conf.debug_level = $2;
+			conf_parsed->debug_level = $2;
 		}
 		| DEBUGLOGFILE QSTRING ';'
 		{
-			conf.debug_log_file = $2;
+			conf_parsed->debug_log_file = $2;
 		}
 		| NONVOLATILEBINDINGCACHE BOOL ';'
 		{
-			conf.NonVolatileBindingCache = $2;
+			conf_parsed->NonVolatileBindingCache = $2;
 		}
 		| INTERFACE ifacedef
 		| SENDMOBPFXSOLS BOOL ';'
 		{
-			conf.SendMobPfxSols = $2;
+			conf_parsed->SendMobPfxSols = $2;
 		}
 		| SENDUNSOLMOBPFXADVS BOOL ';'
 		{
-			conf.SendUnsolMobPfxAdvs = $2;
+			conf_parsed->SendUnsolMobPfxAdvs = $2;
 		}
 		| SENDMOBPFXADVS BOOL ';'
 		{
-			conf.SendMobPfxAdvs = $2;
+			conf_parsed->SendMobPfxAdvs = $2;
 		}
 		| MAXMOBPFXADVINTERVAL NUMBER ';'
 		{
-			conf.MaxMobPfxAdvInterval = $2;
+			conf_parsed->MaxMobPfxAdvInterval = $2;
 		}
 		| MINMOBPFXADVINTERVAL NUMBER ';'
 		{
-			conf.MinMobPfxAdvInterval = $2;
+			conf_parsed->MinMobPfxAdvInterval = $2;
 		}
 		| DOROUTEOPTIMIZATIONCN BOOL ';'
 		{
-			conf.DoRouteOptimizationCN = $2;
+			conf_parsed->DoRouteOptimizationCN = $2;
 		}
 		| DOROUTEOPTIMIZATIONMN BOOL ';'
 		{
-			conf.DoRouteOptimizationMN = $2;
+			conf_parsed->DoRouteOptimizationMN = $2;
 		}
 		| HAMAXBINDINGLIFE NUMBER ';'
 		{
@@ -239,7 +239,7 @@ topdef		: MIP6ENTITY mip6entity ';'
 				       MAX_BINDING_LIFETIME);
 				return -1;
 			}
-			conf.HaMaxBindingLife = $2;
+			conf_parsed->HaMaxBindingLife = $2;
 		}
 		| MNMAXHABINDINGLIFE NUMBER ';'
 		{
@@ -248,7 +248,7 @@ topdef		: MIP6ENTITY mip6entity ';'
 				       MAX_BINDING_LIFETIME);
 				return -1;
 			}
-			conf.MnMaxHaBindingLife = $2;
+			conf_parsed->MnMaxHaBindingLife = $2;
 		}
 		| MNMAXCNBINDINGLIFE NUMBER ';'
 		{
@@ -257,30 +257,30 @@ topdef		: MIP6ENTITY mip6entity ';'
 				       MAX_RR_BINDING_LIFETIME);
 				return -1;
 			}
-			conf.MnMaxCnBindingLife = $2;
+			conf_parsed->MnMaxCnBindingLife = $2;
 		}
 		| INITIALBINDACKTIMEOUTFIRSTREG DECIMAL ';'
 		{
-			tssetdsec(conf.InitialBindackTimeoutFirstReg_ts, $2);
+			tssetdsec(conf_parsed->InitialBindackTimeoutFirstReg_ts, $2);
 		}
 		| INITIALBINDACKTIMEOUTREREG DECIMAL ';'
 		{
-			tssetdsec(conf.InitialBindackTimeoutReReg_ts, $2);
+			tssetdsec(conf_parsed->InitialBindackTimeoutReReg_ts, $2);
 		}
 		| MNHOMELINK linksub
 		| USEMNHAIPSEC BOOL ';'
 		{
-			conf.UseMnHaIPsec = $2;
+			conf_parsed->UseMnHaIPsec = $2;
 		}
 		| KEYMNGMOBCAPABILITY BOOL  ';'
 		{
-			conf.KeyMngMobCapability = $2;
+			conf_parsed->KeyMngMobCapability = $2;
 		}
 		| USEMOVEMENTMODULE movemodule ';'
 		| USEPOLICYMODULE policymodule ';'
 		| DEFAULTBINDINGACLPOLICY bindaclpolval ';'
 		{
-			conf.DefaultBindingAclPolicy = $2;
+			conf_parsed->DefaultBindingAclPolicy = $2;
 		}
 		| BINDINGACLPOLICY bindaclpolicy ';' 
 		{
@@ -288,29 +288,29 @@ topdef		: MIP6ENTITY mip6entity ';'
 		}
 		| USECNBUACK BOOL ';' 
 		{
-			conf.CnBuAck = $2 ? IP6_MH_BU_ACK : 0;
+			conf_parsed->CnBuAck = $2 ? IP6_MH_BU_ACK : 0;
 		}
 		| IPSECPOLICYSET '{' ipsecpolicyset '}'
 		| MNUSEALLINTERFACES BOOL ';' 
 		{
-			conf.MnUseAllInterfaces = $2 ? POL_MN_IF_DEF_PREFERENCE : 0;
+			conf_parsed->MnUseAllInterfaces = $2 ? POL_MN_IF_DEF_PREFERENCE : 0;
 		}
 		| MNROUTERPROBES NUMBER ';' 
 		{
-			conf.MnRouterProbes = $2;
+			conf_parsed->MnRouterProbes = $2;
 		}
 		| MNROUTERPROBETIMEOUT DECIMAL ';' 
 		{
 			if ($2 > 0)
-				tssetdsec(conf.MnRouterProbeTimeout_ts, $2);
+				tssetdsec(conf_parsed->MnRouterProbeTimeout_ts, $2);
 		}
 		| MNDISCARDHAPARAMPROB BOOL ';' 
 		{
-			conf.MnDiscardHaParamProb = $2;
+			conf_parsed->MnDiscardHaParamProb = $2;
 		}
 		| OPTIMISTICHANDOFF BOOL ';' 
 		{
-			conf.OptimisticHandoff = $2;
+			conf_parsed->OptimisticHandoff = $2;
 		}
 		;
 
@@ -335,7 +335,7 @@ ifacedef	: QSTRING ifacesub
 				return -1;
 			}
 			memcpy(nni, &ni, sizeof(struct net_iface));
-			list_add_tail(&nni->list, &conf.net_ifaces);
+			list_add_tail(&nni->list, &conf_parsed->net_ifaces);
 			if (is_if_ha(nni))
 				homeagent_if_init(nni->ifindex);
 
@@ -400,7 +400,7 @@ linksub		: QSTRING '{' linkdefs '}'
 			INIT_LIST_HEAD(&nhai->ha_list.home_agents);
 			nhai->ha_list.dhaad_id = -1;
 			list_splice(&hai.ro_policies, &nhai->ro_policies);
-			list_add_tail(&nhai->list, &conf.home_addrs);
+			list_add_tail(&nhai->list, &conf_parsed->home_addrs);
 
 			memset(&hai, 0, sizeof(struct home_addr_info));
 			INIT_LIST_HEAD(&hai.ro_policies);
@@ -546,7 +546,7 @@ ipsecpolicydef	: ipsectype ipsecprotos ipsecreqid xfrmaction ';'
 					       NIP6ADDR(&e->mn_addr));
 					return -1;
 				}
-				list_add_tail(&e->list, &conf.ipsec_policies);
+				list_add_tail(&e->list, &conf_parsed->ipsec_policies);
 			}
 		}
 		;
@@ -612,17 +612,17 @@ dorouteopt	: BOOL { $$ = $1; }
 
 movemodule	: INTERNAL
 		{
-			conf.MoveModulePath = NULL;
+			conf_parsed->MoveModulePath = NULL;
 		}
 		| QSTRING
 		{
-			conf.MoveModulePath = NULL;
+			conf_parsed->MoveModulePath = NULL;
 		}
 		;
 
 policymodule	: QSTRING
 		{
-			if (pmgr_init($1, &conf.pmgr) < 0) {
+			if (pmgr_init($1, &conf_parsed->pmgr) < 0) {
 				uerror("error loading shared object %s", $1);
 				return -1;
 			}
@@ -650,7 +650,7 @@ bindaclpolicy	: ADDR bindaclpolval
 			bae->hoa = $1;
 			bae->plen = 128;
 			bae->bind_policy = $2;
-			list_add_tail(&bae->list, &conf.bind_acl);
+			list_add_tail(&bae->list, &conf_parsed->bind_acl);
 		}
 		;
 
diff --git a/src/ipsec.c b/src/ipsec.c
index d038c69..9b47e98 100644
--- a/src/ipsec.c
+++ b/src/ipsec.c
@@ -326,7 +326,7 @@ int ipsec_policy_entry_check(const struct in6_addr *haaddr,
 	struct list_head *lp;
 	int ret = 0;
 
-	list_for_each(lp, &conf.ipsec_policies) {
+	list_for_each(lp, &conf_parsed->ipsec_policies) {
 		struct ipsec_policy_entry *e;
 
 		e = list_entry(lp, struct ipsec_policy_entry, list);
diff --git a/src/main.c b/src/main.c
index f5b3b7e..d9499b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -65,15 +65,19 @@ static void sig_child(int unused)
 	while ((pid = waitpid(0, &status, WNOHANG)) > 0);
 }
 
+extern void conf_apply_changes(struct mip6_config *cur, struct mip6_config *new);
+
 static void reinit(void)
 {
 	/* got SIGHUP, reread configuration and reinitialize */
 	dbg("got SIGHUP, reinitilize\n");
+	(void)conf_update(&conf, &conf_apply_changes);
 	return;
 }
 
 
 struct mip6_config conf;
+struct mip6_config *conf_parsed=NULL;
 
 static void terminate(void)
 {
@@ -176,6 +180,8 @@ int main(int argc, char **argv)
 	sigset_t sigblock;
 	int logflags = 0;
 	int ret = 1;
+	
+	conf_parsed = &conf;
 
 	debug_init();
 
diff --git a/src/policy.c b/src/policy.c
index 42beb96..a9f0b5d 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -248,16 +248,24 @@ void policy_cleanup(void)
 	pthread_rwlock_unlock(&policy_lock);
 }
 
-static int policy_bind_acl_add(struct policy_bind_acl_entry *acl)
+int policy_bind_acl_add(struct policy_bind_acl_entry *acl)
 {
 	int err;
 	err = hash_add(&policy_bind_acl_hash, acl, NULL, &acl->hoa);
+#if 0	/* We need to keep data in the config to be able to compare on dynamic reloading */
 	if (!err) {
 		list_del(&acl->list);
 	}
+#endif /* 0 */
 	return err;
 }
 
+int policy_bind_acl_rem(struct policy_bind_acl_entry *acl)
+{
+	hash_delete(&policy_bind_acl_hash, NULL, &acl->hoa);
+	return 0;
+}
+
 static int policy_bind_acl_config(void)
 {
 	struct list_head *list, *n;
diff --git a/src/xfrm.c b/src/xfrm.c
index 8e92e37..0c07f8b 100644
--- a/src/xfrm.c
+++ b/src/xfrm.c
@@ -582,7 +582,7 @@ static void create_ipsec_tmpl(struct xfrm_user_tmpl *tmpl, uint8_t proto,
 	}
 }
 
-static int _mn_ha_ipsec_init(const struct in6_addr *haaddr,
+int _mn_ha_ipsec_init(const struct in6_addr *haaddr,
 			     const struct in6_addr *hoa,
 			     struct ipsec_policy_entry *e,
 			     void *arg)
@@ -722,7 +722,7 @@ static int xfrm_mn_init(void)
 			      XFRM_STATE_WILDRECV);
 }
 
-static int _mn_ha_ipsec_cleanup(const struct in6_addr *haaddr,
+int _mn_ha_ipsec_cleanup(const struct in6_addr *haaddr,
 				const struct in6_addr *hoa,
 				struct ipsec_policy_entry *e,
 				void *arg)
@@ -814,7 +814,7 @@ static void xfrm_mn_cleanup(void)
 
 }
 
-static int _ha_mn_ipsec_init(const struct in6_addr *haaddr,
+int _ha_mn_ipsec_init(const struct in6_addr *haaddr,
 			     const struct in6_addr *hoa,
 			     struct ipsec_policy_entry *e,
 			     void *arg)
@@ -909,7 +909,7 @@ static int xfrm_ha_init(void)
 	return 0;
 }
 
-static int _ha_mn_ipsec_cleanup(const struct in6_addr *haaddr,
+int _ha_mn_ipsec_cleanup(const struct in6_addr *haaddr,
 				const struct in6_addr *hoa,
 				struct ipsec_policy_entry *e,
 				void *arg)