]> git.proxmox.com Git - mirror_frr.git/blobdiff - ldpd/lde.c
*: remove --enable-tcp-zebra, rework ZAPI path
[mirror_frr.git] / ldpd / lde.c
index 1c7458ce7386d4e89c2d507feb5128b4769619d7..11fcbfa46dba8af6d8fbd0f9893cd579c5214baa 100644 (file)
 #include "zclient.h"
 #include "stream.h"
 #include "network.h"
+#include "libfrr.h"
 
 static void             lde_shutdown(void);
 static int              lde_dispatch_imsg(struct thread *);
 static int              lde_dispatch_parent(struct thread *);
-static __inline        int      lde_nbr_compare(struct lde_nbr *,
-                           struct lde_nbr *);
+static __inline        int      lde_nbr_compare(const struct lde_nbr *,
+                           const struct lde_nbr *);
 static struct lde_nbr  *lde_nbr_new(uint32_t, struct lde_nbr *);
 static void             lde_nbr_del(struct lde_nbr *);
 static struct lde_nbr  *lde_nbr_find(uint32_t);
 static void             lde_nbr_clear(void);
 static void             lde_nbr_addr_update(struct lde_nbr *,
                            struct lde_addr *, int);
-static __inline int     lde_map_compare(struct lde_map *, struct lde_map *);
+static __inline int     lde_map_compare(const struct lde_map *,
+                           const struct lde_map *);
 static void             lde_map_free(void *);
 static int              lde_address_add(struct lde_nbr *, struct lde_addr *);
 static int              lde_address_del(struct lde_nbr *, struct lde_addr *);
 static void             lde_address_list_free(struct lde_nbr *);
-static void             zclient_sync_init (u_short instance);
+static void             zclient_sync_init(u_short instance);
 static void             lde_label_list_init(void);
-static int              lde_get_label_chunk (void);
+static int              lde_get_label_chunk(void);
 static void             on_get_label_chunk_response(uint32_t start, uint32_t end);
 static uint32_t                 lde_get_next_label(void);
 
@@ -80,10 +82,6 @@ static zebra_capabilities_t _caps_p [] =
 
 static struct zebra_privs_t lde_privs =
 {
-#if defined(FRR_USER) && defined(FRR_GROUP)
-       .user = FRR_USER,
-       .group = FRR_GROUP,
-#endif
 #if defined(VTY_GROUP)
        .vty_group = VTY_GROUP,
 #endif
@@ -93,8 +91,11 @@ static struct zebra_privs_t lde_privs =
 };
 
 /* List of chunks of labels externally assigned by Zebra */
-struct list *label_chunk_list;
-struct listnode *current_label_chunk;
+static struct list *label_chunk_list;
+static struct listnode *current_label_chunk;
+
+/* Synchronous zclient to request labels */
+static struct zclient *zclient_sync;
 
 /* SIGINT / SIGTERM handler. */
 static void
@@ -119,30 +120,6 @@ static struct quagga_signal_t lde_signals[] =
        },
 };
 
-struct zclient *zclient_sync = NULL;
-static void
-zclient_sync_init(u_short instance)
-{
-       /* Initialize special zclient for synchronous message exchanges. */
-       log_debug("Initializing synchronous zclient for label manager");
-       zclient_sync = zclient_new(master);
-       zclient_sync->sock = -1;
-       zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
-       zclient_sync->instance = instance;
-       while (zclient_socket_connect (zclient_sync) < 0) {
-               log_warnx("Error connecting synchronous zclient!");
-               sleep(1);
-       }
-       /* make socket non-blocking */
-       sock_set_nonblock(zclient_sync->sock);
-
-       /* Connect to label manager */
-       while (lm_label_manager_connect (zclient_sync) != 0) {
-               log_warnx("Error connecting to label manager!");
-               sleep(1);
-       }
-}
-
 /* label decision engine */
 void
 lde(void)
@@ -155,7 +132,7 @@ lde(void)
        ldpd_process = PROC_LDE_ENGINE;
        log_procname = log_procnames[PROC_LDE_ENGINE];
 
-       master = thread_master_create();
+       master = thread_master_create(NULL);
 
        /* setup signal handler */
        signal_init(master, array_size(lde_signals), lde_signals);
@@ -165,8 +142,9 @@ lde(void)
                fatal(NULL);
        imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC);
        iev_main->handler_read = lde_dispatch_parent;
-       iev_main->ev_read = thread_add_read(master, iev_main->handler_read,
-           iev_main, iev_main->ibuf.fd);
+       iev_main->ev_read = NULL;
+       thread_add_read(master, iev_main->handler_read, iev_main, iev_main->ibuf.fd,
+                       &iev_main->ev_read);
        iev_main->handler_write = ldp_write_handler;
 
        if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL)
@@ -185,22 +163,16 @@ void
 lde_init(struct ldpd_init *init)
 {
        /* drop privileges */
-       if (init->user)
-               lde_privs.user = init->user;
-       if (init->group)
-               lde_privs.group = init->group;
+       lde_privs.user = init->user;
+       lde_privs.group = init->group;
        zprivs_init(&lde_privs);
 
-#ifdef HAVE_PLEDGE
-       if (pledge("stdio recvfd unix", NULL) == -1)
-               fatal("pledge");
-#endif
-
        /* start the LIB garbage collector */
        lde_gc_start_timer();
 
        /* Init synchronous zclient and label list */
-       zclient_serv_path_set(init->zclient_serv_path);
+       frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+                        init->zclient_serv_path);
        zclient_sync_init(init->instance);
        lde_label_list_init();
 }
@@ -553,8 +525,9 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        imsg_init(&iev_ldpe->ibuf, fd);
                        iev_ldpe->handler_read = lde_dispatch_imsg;
-                       iev_ldpe->ev_read = thread_add_read(master,
-                           iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd);
+                       iev_ldpe->ev_read = NULL;
+                       thread_add_read(master, iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd,
+                                       &iev_ldpe->ev_read);
                        iev_ldpe->handler_write = ldp_write_handler;
                        iev_ldpe->ev_write = NULL;
                        break;
@@ -572,10 +545,10 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
 
-                       RB_INIT(&nconf->iface_tree);
-                       RB_INIT(&nconf->tnbr_tree);
-                       RB_INIT(&nconf->nbrp_tree);
-                       RB_INIT(&nconf->l2vpn_tree);
+                       RB_INIT(iface_head, &nconf->iface_tree);
+                       RB_INIT(tnbr_head, &nconf->tnbr_tree);
+                       RB_INIT(nbrp_head, &nconf->nbrp_tree);
+                       RB_INIT(l2vpn_head, &nconf->l2vpn_tree);
                        break;
                case IMSG_RECONF_IFACE:
                        if ((niface = malloc(sizeof(struct iface))) == NULL)
@@ -603,9 +576,9 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
 
-                       RB_INIT(&nl2vpn->if_tree);
-                       RB_INIT(&nl2vpn->pw_tree);
-                       RB_INIT(&nl2vpn->pw_inactive_tree);
+                       RB_INIT(l2vpn_if_head, &nl2vpn->if_tree);
+                       RB_INIT(l2vpn_pw_head, &nl2vpn->pw_tree);
+                       RB_INIT(l2vpn_pw_head, &nl2vpn->pw_inactive_tree);
 
                        RB_INSERT(l2vpn_head, &nconf->l2vpn_tree, nl2vpn);
                        break;
@@ -735,7 +708,7 @@ lde_update_label(struct fec_node *fn)
            fn->local_label > MPLS_LABEL_RESERVED_MAX)
                return (fn->local_label);
 
-       return lde_get_next_label ();
+       return (lde_get_next_label());
 }
 
 void
@@ -917,10 +890,23 @@ lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec)
 void
 lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
 {
-       struct lde_req  *lre;
-       struct lde_map  *me;
-       struct map       map;
-       struct l2vpn_pw *pw;
+       struct lde_wdraw        *lw;
+       struct lde_map          *me;
+       struct lde_req          *lre;
+       struct map               map;
+       struct l2vpn_pw         *pw;
+
+       /*
+        * We shouldn't send a new label mapping if we have a pending
+        * label release to receive. In this case, schedule to send a
+        * label mapping as soon as a label release is received.
+        */
+       lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
+       if (lw) {
+               if (!fec_find(&ln->sent_map_pending, &fn->fec))
+                       lde_map_pending_add(ln, fn);
+               return;
+       }
 
        /*
         * This function skips SL.1 - 3 and SL.9 - 14 because the label
@@ -1206,7 +1192,7 @@ lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
 }
 
 static __inline int
-lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b)
+lde_nbr_compare(const struct lde_nbr *a, const struct lde_nbr *b)
 {
        return (a->peerid - b->peerid);
 }
@@ -1226,6 +1212,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
        ln->peerid = peerid;
        fec_init(&ln->recv_map);
        fec_init(&ln->sent_map);
+       fec_init(&ln->sent_map_pending);
        fec_init(&ln->recv_req);
        fec_init(&ln->sent_req);
        fec_init(&ln->sent_wdraw);
@@ -1281,6 +1268,7 @@ lde_nbr_del(struct lde_nbr *ln)
 
        fec_clear(&ln->recv_map, lde_map_free);
        fec_clear(&ln->sent_map, lde_map_free);
+       fec_clear(&ln->sent_map_pending, free);
        fec_clear(&ln->recv_req, free);
        fec_clear(&ln->sent_req, free);
        fec_clear(&ln->sent_wdraw, free);
@@ -1329,7 +1317,7 @@ lde_nbr_clear(void)
 {
        struct lde_nbr  *ln;
 
-        while ((ln = RB_ROOT(&lde_nbrs)) != NULL)
+        while ((ln = RB_ROOT(nbr_tree, &lde_nbrs)) != NULL)
                lde_nbr_del(ln);
 }
 
@@ -1342,7 +1330,6 @@ lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
        struct lde_map          *me;
 
        RB_FOREACH(fec, fec_tree, &ln->recv_map) {
-               fn = (struct fec_node *)fec_find(&ft, fec);
                switch (fec->type) {
                case FEC_TYPE_IPV4:
                        if (lde_addr->af != AF_INET)
@@ -1356,6 +1343,11 @@ lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
                        continue;
                }
 
+               fn = (struct fec_node *)fec_find(&ft, fec);
+               if (fn == NULL)
+                       /* shouldn't happen */
+                       continue;
+
                LIST_FOREACH(fnh, &fn->nexthops, entry) {
                        if (ldp_addrcmp(fnh->af, &fnh->nexthop,
                            &lde_addr->addr))
@@ -1375,7 +1367,7 @@ lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
 }
 
 static __inline int
-lde_map_compare(struct lde_map *a, struct lde_map *b)
+lde_map_compare(const struct lde_map *a, const struct lde_map *b)
 {
        return (ldp_addrcmp(AF_INET, (union ldpd_addr *)&a->nexthop->id,
            (union ldpd_addr *)&b->nexthop->id));
@@ -1431,6 +1423,30 @@ lde_map_free(void *ptr)
        free(map);
 }
 
+struct fec *
+lde_map_pending_add(struct lde_nbr *ln, struct fec_node *fn)
+{
+       struct fec      *map;
+
+       map = calloc(1, sizeof(*map));
+       if (map == NULL)
+               fatal(__func__);
+
+       *map = fn->fec;
+       if (fec_insert(&ln->sent_map_pending, map))
+               log_warnx("failed to add %s to sent map (pending)",
+                   log_fec(map));
+
+       return (map);
+}
+
+void
+lde_map_pending_del(struct lde_nbr *ln, struct fec *map)
+{
+       fec_remove(&ln->sent_map_pending, map);
+       free(map);
+}
+
 struct lde_req *
 lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent)
 {
@@ -1596,29 +1612,53 @@ lde_address_list_free(struct lde_nbr *ln)
        }
 }
 
+static void
+zclient_sync_init(u_short instance)
+{
+       /* Initialize special zclient for synchronous message exchanges. */
+       log_debug("Initializing synchronous zclient for label manager");
+       zclient_sync = zclient_new(master);
+       zclient_sync->sock = -1;
+       zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
+       zclient_sync->instance = instance;
+       while (zclient_socket_connect(zclient_sync) < 0) {
+               log_warnx("Error connecting synchronous zclient!");
+               sleep(1);
+       }
+       /* make socket non-blocking */
+       sock_set_nonblock(zclient_sync->sock);
+
+       /* Connect to label manager */
+       while (lm_label_manager_connect(zclient_sync) != 0) {
+               log_warnx("Error connecting to label manager!");
+               sleep(1);
+       }
+}
+
 static void
 lde_del_label_chunk(void *val)
 {
        free(val);
 }
+
 static int
 lde_get_label_chunk(void)
 {
-       int ret;
-       uint32_t start, end;
+       int              ret;
+       uint32_t         start, end;
 
        log_debug("Getting label chunk");
        ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                log_warnx("Error getting label chunk!");
                return -1;
        }
 
        on_get_label_chunk_response(start, end);
 
-       return 0;
+       return (0);
 }
+
 static void
 lde_label_list_init(void)
 {
@@ -1659,9 +1699,9 @@ on_get_label_chunk_response(uint32_t start, uint32_t end)
 static uint32_t
 lde_get_next_label(void)
 {
-       struct label_chunk *label_chunk;
-       uint32_t i, pos, size;
-       uint32_t label = NO_LABEL;
+       struct label_chunk      *label_chunk;
+       uint32_t                 i, pos, size;
+       uint32_t                 label = NO_LABEL;
 
        while (current_label_chunk) {
                label_chunk = listgetdata(current_label_chunk);
@@ -1683,12 +1723,13 @@ lde_get_next_label(void)
 end:
        /* we moved till the last chunk, or were not able to find a label,
           so let's ask for another one */
-       if (!current_label_chunk || current_label_chunk == listtail(label_chunk_list)
-               || label == NO_LABEL) {
+       if (!current_label_chunk ||
+           current_label_chunk == listtail(label_chunk_list) ||
+           label == NO_LABEL) {
                if (lde_get_label_chunk() != 0)
                        log_warn("%s: Error getting label chunk!", __func__);
 
        }
 
-       return label;
+       return (label);
 }