]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: Start Label Manager safer
authorOlivier Dugeon <olivier.dugeon@orange.com>
Thu, 4 Jun 2020 16:03:04 +0000 (18:03 +0200)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Tue, 23 Jun 2020 14:36:56 +0000 (16:36 +0200)
Initial attempt to connect to the Label Manager used an infinite loop with
a sleep statement which block isisd until Label Manager connection fire up.

This commit changes the way Label Manager connection is established and uses
a `thread_add_timer()` call to re-attempt to establish the connection in case
of failure (zebra or label manager not ready).

New variables are added to the SRDB in order to control the request of SRGB
and SRLB to the Label Manager to start Segment Routing in a safe way.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
isisd/isis_nb_config.c
isisd/isis_sr.c
isisd/isis_sr.h
isisd/isis_zebra.c
isisd/isis_zebra.h

index fafa22b4927c0a57aa652a0447b8f48a203823d1..8a37035c9b40e0aadda81e7796aadd8588f9c634 100644 (file)
@@ -1433,14 +1433,12 @@ int isis_instance_segment_routing_enabled_modify(
                if (IS_DEBUG_ISIS(DEBUG_EVENTS))
                        zlog_debug("SR: Segment Routing: OFF -> ON");
 
-               if (isis_sr_start(area) == 0)
-                       area->srdb.enabled = true;
+               isis_sr_start(area);
        } else {
                if (IS_DEBUG_ISIS(DEBUG_EVENTS))
                        zlog_debug("SR: Segment Routing: ON -> OFF");
 
                isis_sr_stop(area);
-               area->srdb.enabled = false;
        }
 
        return NB_OK;
@@ -1486,21 +1484,12 @@ void isis_instance_segment_routing_srgb_apply_finish(
 {
        struct isis_area *area;
        uint32_t lower_bound, upper_bound;
-       int ret;
 
        area = nb_running_get_entry(args->dnode, NULL, true);
        lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound");
        upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound");
 
-       ret = isis_sr_cfg_srgb_update(area, lower_bound, upper_bound);
-       if (area->srdb.config.enabled) {
-               if (ret == 0)
-                       area->srdb.enabled = true;
-               else {
-                       isis_sr_stop(area);
-                       area->srdb.enabled = false;
-               }
-       }
+       isis_sr_cfg_srgb_update(area, lower_bound, upper_bound);
 }
 
 /*
index 32de71cca61cd74650895e0bbf51caad0d17e0be..f27aca991ff7780012278363577f0393e1e395f8 100644 (file)
@@ -142,10 +142,20 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
        sr_debug("ISIS-Sr (%s): Update SRGB with new range [%u/%u]",
                 area->area_tag, lower_bound, upper_bound);
 
-       /* First release the old SRGB. */
-       if (srdb->config.enabled)
-               isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
+       /* Just store new SRGB values if Label Manager is not available.
+        * SRGB will be configured later when SR start */
+       if (!isis_zebra_label_manager_ready()) {
+               srdb->config.srgb_lower_bound = lower_bound;
+               srdb->config.srgb_upper_bound = upper_bound;
+               return 0;
+       }
+
+       /* Label Manager is ready, start by releasing the old SRGB. */
+       if (srdb->srgb_active) {
+               isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
                                               srdb->config.srgb_upper_bound);
+               srdb->srgb_active = false;
+       }
 
        srdb->config.srgb_lower_bound = lower_bound;
        srdb->config.srgb_upper_bound = upper_bound;
@@ -157,8 +167,12 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
                if (isis_zebra_request_label_range(
                            srdb->config.srgb_lower_bound,
                            srdb->config.srgb_upper_bound
-                                   - srdb->config.srgb_lower_bound + 1))
+                                   - srdb->config.srgb_lower_bound + 1) < 0) {
+                       srdb->srgb_active = false;
                        return -1;
+               } else
+                       srdb->srgb_active = true;
+
 
                sr_debug("  |- Got new SRGB [%u/%u]",
                         srdb->config.srgb_lower_bound,
@@ -175,8 +189,7 @@ int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
                lsp_regenerate_schedule(area, area->is_type, 0);
        } else if (srdb->config.enabled) {
                /* Try to enable SR again using the new SRGB. */
-               if (isis_sr_start(area) == 0)
-                       area->srdb.enabled = true;
+               isis_sr_start(area);
        }
 
        return 0;
@@ -199,33 +212,39 @@ int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound,
        struct isis_sr_db *srdb = &area->srdb;
        struct listnode *node, *nnode;
        struct sr_adjacency *sra;
-       int rc;
 
        sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]",
                 area->area_tag, lower_bound, upper_bound);
 
-       /* First Delete SRLB */
+       /* Just store new SRLB values if Label Manager is not available.
+        * SRLB will be configured later when SR start */
+       if (!isis_zebra_label_manager_ready()) {
+               srdb->config.srlb_lower_bound = lower_bound;
+               srdb->config.srlb_upper_bound = upper_bound;
+               return 0;
+       }
+
+       /* LM is ready, start by deleting the old SRLB */
        sr_local_block_delete(area);
 
        srdb->config.srlb_lower_bound = lower_bound;
        srdb->config.srlb_upper_bound = upper_bound;
 
-       if (!srdb->enabled)
-               return 0;
-
-       /* Initialize new SRLB */
-       rc = sr_local_block_init(area);
-       if (rc !=0)
-               return rc;
-
-       /* Reinstall local Adjacency-SIDs with new labels. */
-       for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
-               sr_adj_sid_update(sra, &srdb->srlb);
+       if (srdb->enabled) {
+               /* Initialize new SRLB */
+               if (sr_local_block_init(area) != 0)
+                       return -1;
 
-       /* Update Router Capability */
+               /* Reinstall local Adjacency-SIDs with new labels. */
+               for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
+                       sr_adj_sid_update(sra, &srdb->srlb);
 
-       /* Update and Flood LSP */
-       lsp_regenerate_schedule(area, area->is_type, 0);
+               /* Update and Flood LSP */
+               lsp_regenerate_schedule(area, area->is_type, 0);
+       } else if (srdb->config.enabled) {
+               /* Try to enable SR again using the new SRLB. */
+               isis_sr_start(area);
+       }
 
        return 0;
 }
@@ -1326,11 +1345,15 @@ static int sr_route_update(struct isis_area *area, struct prefix *prefix,
  *
  * @param area IS-IS area
  */
-static void sr_local_block_init(struct isis_area *area)
+static int sr_local_block_init(struct isis_area *area)
 {
        struct isis_sr_db *srdb = &area->srdb;
        struct sr_local_block *srlb = &srdb->srlb;
 
+       /* Check if SRLB is not already configured */
+       if (srlb->active)
+               return 0;
+
        /*
         * Request SRLB to the label manager. If the allocation fails, return
         * an error to disable SR until a new SRLB is successfully allocated.
@@ -1338,8 +1361,10 @@ static void sr_local_block_init(struct isis_area *area)
        if (isis_zebra_request_label_range(
                    srdb->config.srlb_lower_bound,
                    srdb->config.srlb_upper_bound
-                           - srdb->config.srlb_lower_bound + 1))
-               return;
+                           - srdb->config.srlb_lower_bound + 1)) {
+               srlb->active = false;
+               return -1;
+       }
 
        sr_debug("ISIS-Sr (%s): Got new SRLB [%u/%u]", area->area_tag,
                 srdb->config.srlb_lower_bound, srdb->config.srlb_upper_bound);
@@ -1354,6 +1379,9 @@ static void sr_local_block_init(struct isis_area *area)
                srlb->max_block++;
        srlb->used_mark = XCALLOC(MTYPE_ISIS_SR_INFO,
                                  srlb->max_block * SRLB_BLOCK_SIZE);
+       srlb->active = true;
+
+       return 0;
 }
 
 /**
@@ -1366,6 +1394,10 @@ static void sr_local_block_delete(struct isis_area *area)
        struct isis_sr_db *srdb = &area->srdb;
        struct sr_local_block *srlb = &srdb->srlb;
 
+       /* Check if SRLB is not already delete */
+       if (!srlb->active)
+               return;
+
        sr_debug("ISIS-Sr (%s): Remove SRLB [%u/%u]", area->area_tag,
                 srlb->start, srlb->end);
 
@@ -1376,7 +1408,7 @@ static void sr_local_block_delete(struct isis_area *area)
        /* Then reset SRLB structure */
        if (srlb->used_mark != NULL)
                XFREE(MTYPE_ISIS_SR_INFO, srlb->used_mark);
-       memset(srlb, 0, sizeof(struct sr_local_block));
+       srlb->active = false;
 }
 
 /**
@@ -2041,6 +2073,26 @@ DEFUN(show_sr_node, show_sr_node_cmd,
 
 /* --- IS-IS Segment Routing Management function ---------------------------- */
 
+/**
+ * Thread function to re-attempt connection to the Label Manager and thus be
+ * able to start Segment Routing.
+ *
+ * @param start                Thread structure that contains area as argument
+ *
+ * @return             1 on success
+ */
+static int sr_start_label_manager(struct thread *start)
+{
+       struct isis_area *area;
+
+       area = THREAD_ARG(start);
+
+       /* re-attempt to start SR & Label Manager connection */
+       isis_sr_start(area);
+
+       return 1;
+}
+
 /**
  * Enable SR on the given IS-IS area.
  *
@@ -2054,19 +2106,35 @@ int isis_sr_start(struct isis_area *area)
        struct isis_circuit *circuit;
        struct listnode *node;
 
-       /* Initialize the SRLB */
-       if (sr_local_block_init(area) != 0)
+       /* First start Label Manager if not ready */
+       if (!isis_zebra_label_manager_ready())
+               if (isis_zebra_label_manager_connect() < 0) {
+                       /* Re-attempt to connect to Label Manager in 1 sec. */
+                       thread_add_timer(master, sr_start_label_manager, area,
+                                        1, &srdb->t_start_lm);
+                       return -1;
+               }
+
+       /* Label Manager is ready, initialize the SRLB */
+       if (sr_local_block_init(area) < 0)
                return -1;
 
        /*
-        * Request SGRB to the label manager. If the allocation fails, return
-        * an error to disable SR until a new SRGB is successfully allocated.
+        * Request SGRB to the label manager if not already active. If the
+        * allocation fails, return an error to disable SR until a new SRGB
+        * is successfully allocated.
         */
-       if (isis_zebra_request_label_range(
-                   srdb->config.srgb_lower_bound,
-                   srdb->config.srgb_upper_bound
-                           - srdb->config.srgb_lower_bound + 1))
-               return -1;
+       if (!srdb->srgb_active) {
+               if (isis_zebra_request_label_range(
+                           srdb->config.srgb_lower_bound,
+                           srdb->config.srgb_upper_bound
+                                   - srdb->config.srgb_lower_bound + 1)
+                   < 0) {
+                       srdb->srgb_active = false;
+                       return -1;
+               } else
+                       srdb->srgb_active = true;
+       }
 
        sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
                 area->area_tag);
@@ -2102,6 +2170,8 @@ int isis_sr_start(struct isis_area *area)
                }
        }
 
+       area->srdb.enabled = true;
+
        /* Regenerate LSPs to advertise Segment Routing capabilities. */
        lsp_regenerate_schedule(area, area->is_type, 0);
 
@@ -2122,6 +2192,9 @@ void isis_sr_stop(struct isis_area *area)
        sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
                 area->area_tag);
 
+       /* Disable any re-attempt to connect to Label Manager */
+       THREAD_TIMER_OFF(srdb->t_start_lm);
+
        /* Uninstall all local Adjacency-SIDs. */
        for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
                sr_adj_sid_del(sra);
@@ -2136,13 +2209,18 @@ void isis_sr_stop(struct isis_area *area)
                }
        }
 
-       /* Release SRGB. */
-       isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
-                                      srdb->config.srgb_upper_bound);
+       /* Release SRGB if active. */
+       if (srdb->srgb_active) {
+               isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
+                                              srdb->config.srgb_upper_bound);
+               srdb->srgb_active = false;
+       }
 
        /* Delete SRLB */
        sr_local_block_delete(area);
 
+       area->srdb.enabled = false;
+
        /* Regenerate LSPs to advertise that the Node is no more SR enable. */
        lsp_regenerate_schedule(area, area->is_type, 0);
 }
@@ -2161,7 +2239,6 @@ void isis_sr_area_init(struct isis_area *area)
 
        /* Initialize Segment Routing Data Base */
        memset(srdb, 0, sizeof(*srdb));
-       srdb->enabled = false;
        srdb->adj_sids = list_new();
 
        for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
index 45728f1eb15424f83a2468342a8098aa2e0fdd57..4379a1dcba611700c61a37571184f9a7866f37c1 100644 (file)
@@ -64,6 +64,7 @@ PREDECL_RBTREE_UNIQ(srdb_prefix_cfg)
 
 /* Segment Routing Local Block allocation */
 struct sr_local_block {
+       bool active;
        uint32_t start;
        uint32_t end;
        uint32_t current;
@@ -223,6 +224,9 @@ struct isis_sr_db {
        /* Global Operational status of Segment Routing. */
        bool enabled;
 
+       /* Thread timer to start Label Manager */
+       struct thread *t_start_lm;
+
        /* List of local Adjacency-SIDs. */
        struct list *adj_sids;
 
@@ -232,8 +236,9 @@ struct isis_sr_db {
        /* Segment Routing Prefix-SIDs per IS-IS level. */
        struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS];
 
-       /* Management of SRLB allocation */
+       /* Management of SRLB & SRGB allocation */
        struct sr_local_block srlb;
+       bool srgb_active;
 
        /* Area Segment Routing configuration. */
        struct {
index fa108c3637b57864797407fd65378a2a32f6f293..db0efcaf5a081eb3e1b3c055dd33ff6164c3ac85 100644 (file)
@@ -56,8 +56,6 @@
 struct zclient *zclient;
 static struct zclient *zclient_sync;
 
-static void isis_zebra_label_manager_connect(void);
-
 /* Router-id update message from zebra. */
 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 {
@@ -463,6 +461,16 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
 
 /* Label Manager Functions */
 
+/**
+ * Check if Label Manager is Ready or not.
+ *
+ * @return     True if Label Manager is ready, False otherwise
+ */
+bool isis_zebra_label_manager_ready(void)
+{
+       return (zclient_sync->sock > 0);
+}
+
 /**
  * Request Label Range to the Label Manager.
  *
@@ -476,8 +484,8 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
        int ret;
        uint32_t start, end;
 
-       if (zclient_sync->sock == -1)
-               isis_zebra_label_manager_connect();
+       if (zclient_sync->sock < 0)
+               return -1;
 
        ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
                                 &end);
@@ -494,47 +502,63 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
  *
  * @param start                start of label range to release
  * @param end          end of label range to release
+ *
+ * @return             0 on success, -1 otherwise
  */
-void isis_zebra_release_label_range(uint32_t start, uint32_t end)
+int isis_zebra_release_label_range(uint32_t start, uint32_t end)
 {
        int ret;
 
-       if (zclient_sync->sock == -1)
-               isis_zebra_label_manager_connect();
+       if (zclient_sync->sock < 0)
+               return -1;
 
        ret = lm_release_label_chunk(zclient_sync, start, end);
-       if (ret < 0)
+       if (ret < 0) {
                zlog_warn("%s: error releasing label range!", __func__);
+               return -1;
+       }
+
+       return 0;
 }
 
 /**
  * Connect to the Label Manager.
+ *
+ * @return     0 on success, -1 otherwise
  */
-static void isis_zebra_label_manager_connect(void)
+int isis_zebra_label_manager_connect(void)
 {
        /* Connect to label manager. */
-       while (zclient_socket_connect(zclient_sync) < 0) {
-               zlog_warn("%s: re-attempt connecting synchronous zclient!",
+       if (zclient_socket_connect(zclient_sync) < 0) {
+               zlog_warn("%s: failed connecting synchronous zclient!",
                          __func__);
-               sleep(1);
+               return -1;
        }
        /* make socket non-blocking */
        set_nonblocking(zclient_sync->sock);
 
        /* Send hello to notify zebra this is a synchronous client */
-       while (zclient_send_hello(zclient_sync) < 0) {
-               zlog_warn(
-                       "%s: re-attempt sending hello for synchronous zclient!",
-                       __func__);
-               sleep(1);
+       if (zclient_send_hello(zclient_sync) < 0) {
+               zlog_warn("%s: failed sending hello for synchronous zclient!",
+                         __func__);
+               close(zclient_sync->sock);
+               zclient_sync->sock = -1;
+               return -1;
        }
 
        /* Connect to label manager */
-       while (lm_label_manager_connect(zclient_sync, 0) != 0) {
-               zlog_warn("%s: re-attempt connecting to label manager!",
-                         __func__);
-               sleep(1);
+       if (lm_label_manager_connect(zclient_sync, 0) != 0) {
+               zlog_warn("%s: failed connecting to label manager!", __func__);
+               if (zclient_sync->sock > 0) {
+                       close(zclient_sync->sock);
+                       zclient_sync->sock = -1;
+               }
+               return -1;
        }
+
+       sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
+
+       return 0;
 }
 
 static void isis_zebra_connected(struct zclient *zclient)
@@ -572,6 +596,8 @@ void isis_zebra_init(struct thread_master *master, int instance)
 
 void isis_zebra_stop(void)
 {
+       zclient_stop(zclient_sync);
+       zclient_free(zclient_sync);
        zclient_stop(zclient);
        zclient_free(zclient);
        frr_fini();
index e853ce34d9c801b8423d75de7f05bd6b06a7473f..fd1c1df6100552d0290d1f837abbf26e46589669 100644 (file)
@@ -49,7 +49,9 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
 int isis_distribute_list_update(int routetype);
 void isis_zebra_redistribute_set(afi_t afi, int type);
 void isis_zebra_redistribute_unset(afi_t afi, int type);
+bool isis_zebra_label_manager_ready(void);
+int isis_zebra_label_manager_connect(void);
 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
-void isis_zebra_release_label_range(uint32_t start, uint32_t end);
+int isis_zebra_release_label_range(uint32_t start, uint32_t end);
 
 #endif /* _ZEBRA_ISIS_ZEBRA_H */