]> git.proxmox.com Git - mirror_frr.git/commitdiff
ldpd: schedule the sending of label messages when necessary
authorRenato Westphal <renato@opensourcerouting.org>
Sat, 22 Apr 2017 01:10:42 +0000 (22:10 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Mon, 5 Jun 2017 15:24:11 +0000 (12:24 -0300)
Once we send a Label Withdraw, we can't send a Label Mapping for the
same FEC until we receive a Label Release from the peer. This is due to
some limitations in the LDP algorithms described in Appendix A. ("LDP
Label Distribution Procedures") of RFC 5036.

To workaround this issue, make it possible to schedule the sending of
a Label Mapping as soon as a Label Release is received for the same FEC.

The easiest way to test this patch is by typing the "label local advertise
explicit-null" command. ldpd will withdraw all null labels using a
Wildcard FEC and then send new Label Mappings as soon the corresponding
Label Releases are received.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c

index 1c7458ce7386d4e89c2d507feb5128b4769619d7..e5d1402832c04b0eb0693542ae524cd8cde769aa 100644 (file)
@@ -917,10 +917,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
@@ -1226,6 +1239,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 +1295,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);
@@ -1431,6 +1446,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)
 {
index c1d66f9fffee94c8c424044cac76956f0c09e6a8..1cce483832d19283e81a1466f5d2530259faedf1 100644 (file)
@@ -95,6 +95,7 @@ struct lde_nbr {
        struct fec_tree          sent_req;
        struct fec_tree          recv_map;
        struct fec_tree          sent_map;
+       struct fec_tree          sent_map_pending;
        struct fec_tree          sent_wdraw;
        TAILQ_HEAD(, lde_addr)   addr_list;
 };
@@ -171,6 +172,8 @@ struct lde_nbr      *lde_nbr_find_by_lsrid(struct in_addr);
 struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
 struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
 void            lde_map_del(struct lde_nbr *, struct lde_map *, int);
+struct fec     *lde_map_pending_add(struct lde_nbr *, struct fec_node *);
+void            lde_map_pending_del(struct lde_nbr *, struct fec *);
 struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int);
 void            lde_req_del(struct lde_nbr *, struct lde_req *, int);
 struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *);
index b074bf34981a0b7f8e08630d16518e0a59e97b03..37a670bc8ca58be4988cba4cfa7172df69b4bb5b 100644 (file)
@@ -662,6 +662,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
        struct fec_node         *fn;
        struct lde_wdraw        *lw;
        struct lde_map          *me;
+       struct fec              *pending_map;
 
        /* wildcard label release */
        if (map->type == MAP_TYPE_WILDCARD ||
@@ -677,17 +678,24 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
        if (fn == NULL)
                return;
 
+       /* LRl.6: check sent map list and remove it if available */
+       me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+       if (me && (map->label == NO_LABEL || map->label == me->map.label))
+               lde_map_del(ln, me, 1);
+
        /* LRl.3: first check if we have a pending withdraw running */
        lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
        if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                /* LRl.4: delete record of outstanding label withdraw */
                lde_wdraw_del(ln, lw);
-       }
 
-       /* LRl.6: check sent map list and remove it if available */
-       me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
-       if (me && (map->label == NO_LABEL || map->label == me->map.label))
-               lde_map_del(ln, me, 1);
+               /* send pending label mapping if any */
+               pending_map = fec_find(&ln->sent_map_pending, &fn->fec);
+               if (pending_map) {
+                       lde_send_labelmapping(ln, fn, 1);
+                       lde_map_pending_del(ln, pending_map);
+               }
+       }
 
        /*
         * LRl.11 - 13 are unnecessary since we remove the label from
@@ -702,6 +710,7 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
        struct fec_node         *fn;
        struct lde_wdraw        *lw;
        struct lde_map          *me;
+       struct fec              *pending_map;
 
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
@@ -711,17 +720,24 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
                if (lde_wildcard_apply(map, &fn->fec, me) == 0)
                        continue;
 
+               /* LRl.6: check sent map list and remove it if available */
+               if (me &&
+                   (map->label == NO_LABEL || map->label == me->map.label))
+                       lde_map_del(ln, me, 1);
+
                /* LRl.3: first check if we have a pending withdraw running */
                lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
                if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                        /* LRl.4: delete record of outstanding lbl withdraw */
                        lde_wdraw_del(ln, lw);
-               }
 
-               /* LRl.6: check sent map list and remove it if available */
-               if (me &&
-                   (map->label == NO_LABEL || map->label == me->map.label))
-                       lde_map_del(ln, me, 1);
+                       /* send pending label mapping if any */
+                       pending_map = fec_find(&ln->sent_map_pending, &fn->fec);
+                       if (pending_map) {
+                               lde_send_labelmapping(ln, fn, 1);
+                               lde_map_pending_del(ln, pending_map);
+                       }
+               }
 
                /*
                 * LRl.11 - 13 are unnecessary since we remove the label from