]> git.proxmox.com Git - mirror_frr.git/blobdiff - ldpd/ldpd.c
bgpd: resolve crash in workqueue processing due to invalid safi
[mirror_frr.git] / ldpd / ldpd.c
index 3023d94469c6568d8cb1b696268136680aa05083..bdf70973234559c47c333fd8c479e2d0c9219b4a 100644 (file)
@@ -44,8 +44,7 @@
 #include "libfrr.h"
 
 static void             ldpd_shutdown(void);
-static pid_t            start_child(enum ldpd_process, char *, int, int,
-                           const char *, const char *, const char *, const char *);
+static pid_t            start_child(enum ldpd_process, char *, int, int);
 static int              main_dispatch_ldpe(struct thread *);
 static int              main_dispatch_lde(struct thread *);
 static int              main_imsg_send_ipc_sockets(struct imsgbuf *,
@@ -56,6 +55,7 @@ static int             main_imsg_send_config(struct ldpd_conf *);
 static void             ldp_config_normalize(struct ldpd_conf *);
 static void             ldp_config_reset_main(struct ldpd_conf *);
 static void             ldp_config_reset_af(struct ldpd_conf *, int);
+static void             ldp_config_reset_l2vpns(struct ldpd_conf *);
 static void             merge_global(struct ldpd_conf *, struct ldpd_conf *);
 static void             merge_af(int, struct ldpd_af_conf *,
                            struct ldpd_af_conf *);
@@ -76,6 +76,7 @@ DEFINE_QOBJ_TYPE(l2vpn)
 DEFINE_QOBJ_TYPE(ldpd_conf)
 
 struct ldpd_global      global;
+struct ldpd_init        init;
 struct ldpd_conf       *ldpd_conf, *vty_conf;
 
 static struct imsgev   *iev_ldpe, *iev_ldpe_sync;
@@ -131,9 +132,8 @@ sighup(void)
        log_info("SIGHUP received");
 
        /* reset vty_conf */
-       ldp_clear_config(vty_conf);
-       vty_conf = config_new_empty();
        ldp_config_reset_main(vty_conf);
+       ldp_config_reset_l2vpns(vty_conf);
 
        /* read configuration file without applying any changes */
        global.sighup = 1;
@@ -200,14 +200,10 @@ main(int argc, char *argv[])
        int                      lflag = 0, eflag = 0;
        int                      pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
        int                      pipe_parent2lde[2], pipe_parent2lde_sync[2];
-       char                    *ctl_sock_custom_path = NULL;
        char                    *ctl_sock_name;
-       const char              *user = NULL;
-       const char              *group = NULL;
-       u_short                  instance = 0;
-       const char              *instance_char = NULL;
 
        ldpd_process = PROC_MAIN;
+       log_procname = log_procnames[ldpd_process];
 
        saved_argv0 = argv[0];
        if (saved_argv0 == NULL)
@@ -241,17 +237,14 @@ main(int argc, char *argv[])
                                 * sensible config
                                 */
                                ctl_sock_name = (char *)LDPD_SOCKET;
-                       ctl_sock_custom_path = optarg;
-                       strlcpy(ctl_sock_path, ctl_sock_custom_path,
-                           sizeof(ctl_sock_path));
+                       strlcpy(ctl_sock_path, optarg, sizeof(ctl_sock_path));
                        strlcat(ctl_sock_path, "/", sizeof(ctl_sock_path));
                        strlcat(ctl_sock_path, ctl_sock_name,
                            sizeof(ctl_sock_path));
                        break;
                case 'n':
-                       instance = atoi(optarg);
-                       instance_char = optarg;
-                       if (instance < 1)
+                       init.instance = atoi(optarg);
+                       if (init.instance < 1)
                                exit(0);
                        break;
                case 'L':
@@ -266,8 +259,11 @@ main(int argc, char *argv[])
                }
        }
 
-       user = ldpd_privs.user;
-       group = ldpd_privs.group;
+       strlcpy(init.user, ldpd_privs.user, sizeof(init.user));
+       strlcpy(init.group, ldpd_privs.group, sizeof(init.group));
+       strlcpy(init.ctl_sock_path, ctl_sock_path, sizeof(init.ctl_sock_path));
+       strlcpy(init.zclient_serv_path, zclient_serv_path_get(),
+           sizeof(init.zclient_serv_path));
 
        argc -= optind;
        argv += optind;
@@ -281,14 +277,14 @@ main(int argc, char *argv[])
                exit(1);
        }
 
-       if (lflag)
-               lde(user, group, instance);
-       else if (eflag)
-               ldpe(user, group, ctl_sock_path);
-
        openzlog(ldpd_di.progname, "LDP", 0,
            LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
 
+       if (lflag)
+               lde();
+       else if (eflag)
+               ldpe();
+
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)
                fatal("socketpair");
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
@@ -316,11 +312,9 @@ main(int argc, char *argv[])
 
        /* start children */
        lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
-           pipe_parent2lde[1], pipe_parent2lde_sync[1],
-           user, group, ctl_sock_custom_path, instance_char);
+           pipe_parent2lde[1], pipe_parent2lde_sync[1]);
        ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
-           pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1],
-           user, group, ctl_sock_custom_path, instance_char);
+           pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1]);
 
        /* drop privileges */
        zprivs_init(&ldpd_privs);
@@ -338,20 +332,20 @@ main(int argc, char *argv[])
        vrf_init();
        access_list_init();
        ldp_vty_init();
-       ldp_vty_if_init();
        ldp_zebra_init(master);
 
        /* create base configuration with sane defaults */
        ldpd_conf = config_new_empty();
        ldp_config_reset_main(ldpd_conf);
-       QOBJ_REG(ldpd_conf, ldpd_conf);
 
        /*
         * Create vty_conf as a duplicate of the main configuration. All
         * configuration requests (e.g. CLI) act on vty_conf and then call
         * ldp_reload() to merge the changes into ldpd_conf.
         */
-       vty_conf = ldp_dup_config(ldpd_conf);
+       vty_conf = config_new_empty();
+       ldp_config_reset_main(vty_conf);
+       QOBJ_REG(vty_conf, ldpd_conf);
 
        /* read configuration file and daemonize  */
        frr_config_fork();
@@ -388,6 +382,7 @@ main(int argc, char *argv[])
 
        if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf))
                fatal("could not establish imsg links");
+       main_imsg_compose_both(IMSG_INIT, &init, sizeof(init));
        main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
            sizeof(ldp_debug));
        main_imsg_send_config(ldpd_conf);
@@ -416,7 +411,11 @@ ldpd_shutdown(void)
        close(iev_lde->ibuf.fd);
 
        config_clear(ldpd_conf);
-       QOBJ_UNREG(ldpd_conf);
+
+       ldp_config_reset_main(vty_conf);
+       ldp_config_reset_l2vpns(vty_conf);
+       QOBJ_UNREG(vty_conf);
+       free(vty_conf);
 
        log_debug("waiting for children to terminate");
        do {
@@ -448,11 +447,9 @@ ldpd_shutdown(void)
 }
 
 static pid_t
-start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
-    const char *user, const char *group, const char *ctl_sock_custom_path,
-    const char *instance)
+start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
 {
-       char    *argv[13];
+       char    *argv[3];
        int      argc = 0;
        pid_t    pid;
 
@@ -483,26 +480,6 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
                argv[argc++] = (char *)"-E";
                break;
        }
-       if (user) {
-               argv[argc++] = (char *)"-u";
-               argv[argc++] = (char *)user;
-       }
-       if (group) {
-               argv[argc++] = (char *)"-g";
-               argv[argc++] = (char *)group;
-       }
-       if (ctl_sock_custom_path) {
-               argv[argc++] = (char *)"--ctl_socket";
-               argv[argc++] = (char *)ctl_sock_custom_path;
-       }
-       /* zclient serv path */
-       argv[argc++] = (char *)"-z";
-       argv[argc++] = (char *)zclient_serv_path_get();
-       /* instance */
-       if (instance) {
-               argv[argc++] = (char *)"-n";
-               argv[argc++] = (char *)instance;
-       }
        argv[argc++] = NULL;
 
        execvp(argv0, argv);
@@ -993,16 +970,16 @@ ldp_reload(struct ldpd_conf *xconf)
 
        merge_config(ldpd_conf, xconf);
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        return (0);
 }
 
 static void
 ldp_config_normalize(struct ldpd_conf *xconf)
 {
+       struct iface            *iface, *itmp;
+       struct nbr_params       *nbrp, *ntmp;
        struct l2vpn            *l2vpn;
-       struct l2vpn_pw         *pw;
+       struct l2vpn_pw         *pw, *ptmp;
 
        if (!(xconf->flags & F_LDPD_ENABLED))
                ldp_config_reset_main(xconf);
@@ -1011,22 +988,51 @@ ldp_config_normalize(struct ldpd_conf *xconf)
                        ldp_config_reset_af(xconf, AF_INET);
                if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED))
                        ldp_config_reset_af(xconf, AF_INET6);
-       }
 
-       RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
-                       if (pw->flags & F_PW_STATIC_NBR_ADDR)
+               RB_FOREACH_SAFE(iface, iface_head, &xconf->iface_tree, itmp) {
+                       if (iface->ipv4.enabled || iface->ipv6.enabled)
                                continue;
 
-                       pw->af = AF_INET;
-                       pw->addr.v4 = pw->lsr_id;
+                       QOBJ_UNREG(iface);
+                       RB_REMOVE(iface_head, &vty_conf->iface_tree, iface);
+                       free(iface);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) {
-                       if (pw->flags & F_PW_STATIC_NBR_ADDR)
+
+               RB_FOREACH_SAFE(nbrp, nbrp_head, &xconf->nbrp_tree, ntmp) {
+                       if (nbrp->flags & (F_NBRP_KEEPALIVE|F_NBRP_GTSM))
+                               continue;
+                       if (nbrp->auth.method != AUTH_NONE)
                                continue;
 
-                       pw->af = AF_INET;
-                       pw->addr.v4 = pw->lsr_id;
+                       QOBJ_UNREG(nbrp);
+                       RB_REMOVE(nbrp_head, &vty_conf->nbrp_tree, nbrp);
+                       free(nbrp);
+               }
+       }
+
+       RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
+               RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) {
+                       if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+                               pw->af = AF_INET;
+                               pw->addr.v4 = pw->lsr_id;
+                       }
+
+                       if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0)
+                               continue;
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+               }
+               RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree,
+                   ptmp) {
+                       if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+                               pw->af = AF_INET;
+                               pw->addr.v4 = pw->lsr_id;
+                       }
+
+                       if (pw->lsr_id.s_addr == INADDR_ANY || pw->pwid == 0)
+                               continue;
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
                }
        }
 }
@@ -1038,11 +1044,13 @@ ldp_config_reset_main(struct ldpd_conf *conf)
        struct nbr_params       *nbrp;
 
        while ((iface = RB_ROOT(&conf->iface_tree)) != NULL) {
+               QOBJ_UNREG(iface);
                RB_REMOVE(iface_head, &conf->iface_tree, iface);
                free(iface);
        }
 
        while ((nbrp = RB_ROOT(&conf->nbrp_tree)) != NULL) {
+               QOBJ_UNREG(nbrp);
                RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp);
                free(nbrp);
        }
@@ -1075,6 +1083,7 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af)
                if (tnbr->af != af)
                        continue;
 
+               QOBJ_UNREG(tnbr);
                RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
                free(tnbr);
        }
@@ -1089,70 +1098,33 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af)
        af_conf->flags = 0;
 }
 
-struct ldpd_conf *
-ldp_dup_config(struct ldpd_conf *conf)
+static void
+ldp_config_reset_l2vpns(struct ldpd_conf *conf)
 {
-       struct ldpd_conf        *xconf;
-       struct iface            *iface, *xi;
-       struct tnbr             *tnbr, *xt;
-       struct nbr_params       *nbrp, *xn;
-       struct l2vpn            *l2vpn, *xl;
-       struct l2vpn_if         *lif, *xf;
-       struct l2vpn_pw         *pw, *xp;
-
-#define COPY(a, b) do { \
-               a = calloc(1, sizeof(*a)); \
-               if (a == NULL) \
-                       fatal(__func__); \
-               *a = *b; \
-       } while (0)
-
-       COPY(xconf, conf);
-       RB_INIT(&xconf->iface_tree);
-       RB_INIT(&xconf->tnbr_tree);
-       RB_INIT(&xconf->nbrp_tree);
-       RB_INIT(&xconf->l2vpn_tree);
-
-       RB_FOREACH(iface, iface_head, &conf->iface_tree) {
-               COPY(xi, iface);
-               xi->ipv4.iface = xi;
-               xi->ipv6.iface = xi;
-               RB_INSERT(iface_head, &xconf->iface_tree, xi);
-       }
-       RB_FOREACH(tnbr, tnbr_head, &conf->tnbr_tree) {
-               COPY(xt, tnbr);
-               RB_INSERT(tnbr_head, &xconf->tnbr_tree, xt);
-       }
-       RB_FOREACH(nbrp, nbrp_head, &conf->nbrp_tree) {
-               COPY(xn, nbrp);
-               RB_INSERT(nbrp_head, &xconf->nbrp_tree, xn);
-       }
-       RB_FOREACH(l2vpn, l2vpn_head, &conf->l2vpn_tree) {
-               COPY(xl, l2vpn);
-               RB_INIT(&xl->if_tree);
-               RB_INIT(&xl->pw_tree);
-               RB_INIT(&xl->pw_inactive_tree);
-               RB_INSERT(l2vpn_head, &xconf->l2vpn_tree, xl);
+       struct l2vpn            *l2vpn;
+       struct l2vpn_if         *lif;
+       struct l2vpn_pw         *pw;
 
-               RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) {
-                       COPY(xf, lif);
-                       xf->l2vpn = xl;
-                       RB_INSERT(l2vpn_if_head, &xl->if_tree, xf);
+       while ((l2vpn = RB_ROOT(&conf->l2vpn_tree)) != NULL) {
+               while ((lif = RB_ROOT(&l2vpn->if_tree)) != NULL) {
+                       QOBJ_UNREG(lif);
+                       RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
+                       free(lif);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
-                       COPY(xp, pw);
-                       xp->l2vpn = xl;
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_tree, xp);
+               while ((pw = RB_ROOT(&l2vpn->pw_tree)) != NULL) {
+                       QOBJ_UNREG(pw);
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       free(pw);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) {
-                       COPY(xp, pw);
-                       xp->l2vpn = xl;
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
+               while ((pw = RB_ROOT(&l2vpn->pw_inactive_tree)) != NULL) {
+                       QOBJ_UNREG(pw);
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       free(pw);
                }
+               QOBJ_UNREG(l2vpn);
+               RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
+               free(l2vpn);
        }
-#undef COPY
-
-       return (xconf);
 }
 
 void
@@ -1183,6 +1155,13 @@ ldp_clear_config(struct ldpd_conf *xconf)
        free(xconf);
 }
 
+#define COPY(a, b) do { \
+               a = malloc(sizeof(*a)); \
+               if (a == NULL) \
+                       fatal(__func__); \
+               *a = *b; \
+       } while (0)
+
 void
 merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
@@ -1193,7 +1172,6 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
        merge_tnbrs(conf, xconf);
        merge_nbrps(conf, xconf);
        merge_l2vpns(conf, xconf);
-       free(xconf);
 }
 
 static void
@@ -1337,31 +1315,34 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
        RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
                /* find deleted interfaces */
                if ((xi = if_lookup_name(xconf, iface->name)) == NULL) {
-                       RB_REMOVE(iface_head, &conf->iface_tree, iface);
-
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               if_exit(iface);
+                               ldpe_if_exit(iface);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_UNREG (iface);
                                break;
                        }
+                       RB_REMOVE(iface_head, &conf->iface_tree, iface);
                        free(iface);
                }
        }
        RB_FOREACH_SAFE(xi, iface_head, &xconf->iface_tree, itmp) {
                /* find new interfaces */
                if ((iface = if_lookup_name(conf, xi->name)) == NULL) {
-                       RB_REMOVE(iface_head, &xconf->iface_tree, xi);
-                       RB_INSERT(iface_head, &conf->iface_tree, xi);
+                       COPY(iface, xi);
+                       RB_INSERT(iface_head, &conf->iface_tree, iface);
 
-                       if (ldpd_process == PROC_MAIN) {
-                               QOBJ_REG (xi, iface);
+                       switch (ldpd_process) {
+                       case PROC_LDP_ENGINE:
+                               ldpe_if_init(iface);
+                               break;
+                       case PROC_LDE_ENGINE:
+                               break;
+                       case PROC_MAIN:
                                /* resend addresses to activate new interfaces */
-                               kif_redistribute(xi->name);
+                               kif_redistribute(iface->name);
+                               break;
                        }
                        continue;
                }
@@ -1369,8 +1350,6 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                /* update existing interfaces */
                merge_iface_af(&iface->ipv4, &xi->ipv4);
                merge_iface_af(&iface->ipv6, &xi->ipv6);
-               RB_REMOVE(iface_head, &xconf->iface_tree, xi);
-               free(xi);
        }
 }
 
@@ -1398,17 +1377,13 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                /* find deleted tnbrs */
                if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) {
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
-                               free(tnbr);
-                               break;
                        case PROC_LDP_ENGINE:
                                tnbr->flags &= ~F_TNBR_CONFIGURED;
                                tnbr_check(conf, tnbr);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
                                RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
-                               QOBJ_UNREG (tnbr);
                                free(tnbr);
                                break;
                        }
@@ -1417,17 +1392,15 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
        RB_FOREACH_SAFE(xt, tnbr_head, &xconf->tnbr_tree, ttmp) {
                /* find new tnbrs */
                if ((tnbr = tnbr_find(conf, xt->af, &xt->addr)) == NULL) {
-                       RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
-                       RB_INSERT(tnbr_head, &conf->tnbr_tree, xt);
+                       COPY(tnbr, xt);
+                       RB_INSERT(tnbr_head, &conf->tnbr_tree, tnbr);
 
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               tnbr_update(xt);
+                               tnbr_update(tnbr);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_REG (xt, tnbr);
                                break;
                        }
                        continue;
@@ -1436,8 +1409,6 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                /* update existing tnbrs */
                if (!(tnbr->flags & F_TNBR_CONFIGURED))
                        tnbr->flags |= F_TNBR_CONFIGURED;
-               RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
-               free(xt);
        }
 }
 
@@ -1452,8 +1423,6 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                /* find deleted nbrps */
                if ((xn = nbr_params_find(xconf, nbrp->lsr_id)) == NULL) {
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
                                nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
                                if (nbr) {
@@ -1471,8 +1440,8 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                                                nbr_establish_connection(nbr);
                                }
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_UNREG (nbrp);
                                break;
                        }
                        RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp);
@@ -1482,33 +1451,31 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
        RB_FOREACH_SAFE(xn, nbrp_head, &xconf->nbrp_tree, ntmp) {
                /* find new nbrps */
                if ((nbrp = nbr_params_find(conf, xn->lsr_id)) == NULL) {
-                       RB_REMOVE(nbrp_head, &xconf->nbrp_tree, xn);
-                       RB_INSERT(nbrp_head, &conf->nbrp_tree, xn);
+                       COPY(nbrp, xn);
+                       RB_INSERT(nbrp_head, &conf->nbrp_tree, nbrp);
 
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               nbr = nbr_find_ldpid(xn->lsr_id.s_addr);
+                               nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
                                if (nbr) {
                                        session_shutdown(nbr, S_SHUTDOWN, 0, 0);
-                                       nbr->auth.method = xn->auth.method;
+                                       nbr->auth.method = nbrp->auth.method;
 #ifdef __OpenBSD__
-                                       if (pfkey_establish(nbr, xn) == -1)
+                                       if (pfkey_establish(nbr, nbrp) == -1)
                                                fatalx("pfkey setup failed");
 #else
                                        sock_set_md5sig(
                                            (ldp_af_global_get(&global,
                                            nbr->af))->ldp_session_socket,
                                            nbr->af, &nbr->raddr,
-                                           xn->auth.md5key);
+                                           nbrp->auth.md5key);
 #endif
                                        if (nbr_session_active_role(nbr))
                                                nbr_establish_connection(nbr);
                                }
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_REG (xn, nbr_params);
                                break;
                        }
                        continue;
@@ -1553,8 +1520,6 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                                        nbr_establish_connection(nbr);
                        }
                }
-               RB_REMOVE(nbrp_head, &xconf->nbrp_tree, xn);
-               free(xn);
        }
 }
 
@@ -1562,14 +1527,10 @@ static void
 merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
        struct l2vpn            *l2vpn, *ltmp, *xl;
-       struct l2vpn_if         *lif;
-       struct l2vpn_pw         *pw;
 
        RB_FOREACH_SAFE(l2vpn, l2vpn_head, &conf->l2vpn_tree, ltmp) {
                /* find deleted l2vpns */
                if ((xl = l2vpn_find(xconf, l2vpn->name)) == NULL) {
-                       RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
-
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
                                l2vpn_exit(l2vpn);
@@ -1578,58 +1539,35 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                                ldpe_l2vpn_exit(l2vpn);
                                break;
                        case PROC_MAIN:
-                               RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
-                                       QOBJ_UNREG (lif);
-                               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
-                                       QOBJ_UNREG (pw);
-                               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree)
-                                       QOBJ_UNREG (pw);
-                               QOBJ_UNREG (l2vpn);
                                break;
                        }
+                       RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
                        l2vpn_del(l2vpn);
                }
        }
        RB_FOREACH_SAFE(xl, l2vpn_head, &xconf->l2vpn_tree, ltmp) {
-               struct l2vpn_pw *xp, *ptmp;
-
-               /* check if the pseudowires should be enabled or disabled */
-               RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_tree, ptmp) {
-                       if (xp->lsr_id.s_addr != INADDR_ANY && xp->pwid != 0)
-                               continue;
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-               }
-               RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_inactive_tree, ptmp) {
-                       if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0)
-                               continue;
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_tree, xp);
-               }
-
                /* find new l2vpns */
                if ((l2vpn = l2vpn_find(conf, xl->name)) == NULL) {
-                       RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
-                       RB_INSERT(l2vpn_head, &conf->l2vpn_tree, xl);
+                       COPY(l2vpn, xl);
+                       RB_INSERT(l2vpn_head, &conf->l2vpn_tree, l2vpn);
+                       RB_INIT(&l2vpn->if_tree);
+                       RB_INIT(&l2vpn->pw_tree);
+                       RB_INIT(&l2vpn->pw_inactive_tree);
 
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
-                               l2vpn_init(xl);
+                               l2vpn_init(l2vpn);
                                break;
                        case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_init(xl);
+                               ldpe_l2vpn_init(l2vpn);
                                break;
                        case PROC_MAIN:
-                               QOBJ_REG (xl, l2vpn);
                                break;
                        }
-                       continue;
                }
 
                /* update existing l2vpns */
                merge_l2vpn(conf, l2vpn, xl);
-               RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
-               free(xl);
        }
 }
 
@@ -1649,8 +1587,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
        RB_FOREACH_SAFE(lif, l2vpn_if_head, &l2vpn->if_tree, ftmp) {
                /* find deleted interfaces */
                if ((xf = l2vpn_if_find(xl, lif->ifname)) == NULL) {
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_UNREG (lif);
                        RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
                        free(lif);
                }
@@ -1658,16 +1594,19 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
        RB_FOREACH_SAFE(xf, l2vpn_if_head, &xl->if_tree, ftmp) {
                /* find new interfaces */
                if ((lif = l2vpn_if_find(l2vpn, xf->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
-                       RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, xf);
-                       xf->l2vpn = l2vpn;
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_REG (xf, l2vpn_if);
-                       continue;
-               }
+                       COPY(lif, xf);
+                       RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
+                       lif->l2vpn = l2vpn;
 
-               RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
-               free(xf);
+                       switch (ldpd_process) {
+                       case PROC_LDP_ENGINE:
+                       case PROC_LDE_ENGINE:
+                               break;
+                       case PROC_MAIN:
+                               kif_redistribute(lif->ifname);
+                               break;
+                       }
+               }
        }
 
        /* merge active pseudowires */
@@ -1682,7 +1621,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
                                ldpe_l2vpn_pw_exit(pw);
                                break;
                        case PROC_MAIN:
-                               QOBJ_UNREG (pw);
                                break;
                        }
 
@@ -1693,19 +1631,19 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
        RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_tree, ptmp) {
                /* find new active pseudowires */
                if ((pw = l2vpn_pw_find_active(l2vpn, xp->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, xp);
-                       xp->l2vpn = l2vpn;
+                       COPY(pw, xp);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       pw->l2vpn = l2vpn;
 
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
-                               l2vpn_pw_init(xp);
+                               l2vpn_pw_init(pw);
                                break;
                        case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_pw_init(xp);
+                               ldpe_l2vpn_pw_init(pw);
                                break;
                        case PROC_MAIN:
-                               QOBJ_REG (xp, l2vpn_pw);
+                               kif_redistribute(pw->ifname);
                                break;
                        }
                        continue;
@@ -1772,9 +1710,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
                        l2vpn->pw_type = previous_pw_type;
                        l2vpn->mtu = previous_mtu;
                }
-
-               RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
-               free(xp);
        }
 
        /* merge inactive pseudowires */
@@ -1782,19 +1717,24 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
                /* find deleted inactive pseudowires */
                if ((xp = l2vpn_pw_find_inactive(xl, pw->ifname)) == NULL) {
                        RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_UNREG (pw);
                        free(pw);
                }
        }
        RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_inactive_tree, ptmp) {
                /* find new inactive pseudowires */
                if ((pw = l2vpn_pw_find_inactive(l2vpn, xp->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, xp);
-                       xp->l2vpn = l2vpn;
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_REG (xp, l2vpn_pw);
+                       COPY(pw, xp);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       pw->l2vpn = l2vpn;
+
+                       switch (ldpd_process) {
+                       case PROC_LDE_ENGINE:
+                       case PROC_LDP_ENGINE:
+                               break;
+                       case PROC_MAIN:
+                               kif_redistribute(pw->ifname);
+                               break;
+                       }
                        continue;
                }
 
@@ -1806,9 +1746,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
                strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname));
                pw->ifindex = xp->ifindex;
                pw->flags = xp->flags;
-
-               RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-               free(xp);
        }
 
        l2vpn->pw_type = xl->pw_type;
@@ -1852,5 +1789,6 @@ config_clear(struct ldpd_conf *conf)
        xconf->trans_pref = conf->trans_pref;
        xconf->flags = conf->flags;
        merge_config(conf, xconf);
+       free(xconf);
        free(conf);
 }