static struct ospf_sr_db OspfSR;
static void ospf_sr_register_vty(void);
static inline void del_adj_sid(struct sr_nhlfe nhlfe);
+static int ospf_sr_start(struct ospf *ospf);
/*
* Segment Routing Data Base functions
* Segment Routing Initialization functions
*/
+/**
+ * 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 ospf *ospf;
+
+ ospf = THREAD_ARG(start);
+
+ /* re-attempt to start SR & Label Manager connection */
+ ospf_sr_start(ospf);
+
+ return 1;
+}
+
/* Segment Routing starter function */
static int ospf_sr_start(struct ospf *ospf)
{
osr_debug("SR (%s): Start Segment Routing", __func__);
- /* Initialize self SR Node */
- srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id),
- (void *)sr_node_new);
+ /* Initialize self SR Node if not already done */
+ if (OspfSR.self == NULL) {
+ srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id),
+ (void *)sr_node_new);
+
+ /* Complete & Store self SR Node */
+ srn->srgb.range_size = OspfSR.srgb.range_size;
+ srn->srgb.lower_bound = OspfSR.srgb.lower_bound;
+ srn->algo[0] = OspfSR.algo[0];
+ srn->msd = OspfSR.msd;
+ OspfSR.self = srn;
+ }
+
+ /* Then, start Label Manager if not ready */
+ if (!ospf_zebra_label_manager_ready())
+ if (ospf_zebra_label_manager_connect() < 0) {
+ /* Re-attempt to connect to Label Manager in 1 sec. */
+ thread_add_timer(master, sr_start_label_manager, ospf,
+ 1, &OspfSR.t_start_lm);
+ osr_debug(" |- Failed to start the Label Manager");
+ return -1;
+ }
+
+ /*
+ * 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 (!OspfSR.srgb_reserved) {
+ if (ospf_zebra_request_label_range(OspfSR.srgb.lower_bound,
+ OspfSR.srgb.range_size)
+ < 0) {
+ OspfSR.srgb_reserved = false;
+ return -1;
+ } else
+ OspfSR.srgb_reserved = true;
+ }
- /* Complete & Store self SR Node */
- srn->srgb.range_size = OspfSR.srgb.range_size;
- srn->srgb.lower_bound = OspfSR.srgb.lower_bound;
- srn->algo[0] = OspfSR.algo[0];
- srn->msd = OspfSR.msd;
- OspfSR.self = srn;
+ /* SR is UP and ready to flood LSA */
+ OspfSR.status = SR_UP;
+
+ /* Set Router Information SR parameters */
+ osr_debug("SR: Activate SR for Router Information LSA");
+
+ ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+ /* Update Ext LSA */
+ osr_debug("SR: Activate SR for Extended Link/Prefix LSA");
+
+ ospf_ext_update_sr(true);
osr_debug("SR (%s): Update SR-DB from LSDB", __func__);
osr_debug("SR (%s): Stop Segment Routing", __func__);
+ /* Disable any re-attempt to connect to Label Manager */
+ THREAD_TIMER_OFF(OspfSR.t_start_lm);
+
+ /* Release SRGB if active. */
+ if (OspfSR.srgb_reserved) {
+ ospf_zebra_release_label_range(
+ OspfSR.srgb.lower_bound,
+ OspfSR.srgb.lower_bound + OspfSR.srgb.range_size - 1);
+ OspfSR.srgb_reserved = false;
+ }
+
/*
* Remove all SR Nodes from the Hash table. Prefix and Link SID will
* be remove though list_delete() call. See sr_node_del()
*/
hash_clean(OspfSR.neighbors, (void *)sr_node_del);
OspfSR.self = NULL;
- OspfSR.enabled = false;
+ OspfSR.status = SR_OFF;
}
/*
osr_debug("SR (%s): Initialize SR Data Base", __func__);
memset(&OspfSR, 0, sizeof(struct ospf_sr_db));
- OspfSR.enabled = false;
+ OspfSR.status = SR_OFF;
/* Only AREA flooding is supported in this release */
OspfSR.scope = OSPF_OPAQUE_AREA_LSA;
OspfSR.srgb.range_size = MPLS_DEFAULT_MAX_SRGB_SIZE;
OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
+ OspfSR.srgb_reserved = false;
OspfSR.msd = 0;
/* Initialize Hash table for neighbor SR nodes */
struct listnode *node;
struct sr_prefix *srp;
- if (OspfSR.enabled) {
+ if (OspfSR.status != SR_OFF) {
vty_out(vty, " segment-routing on\n");
if ((OspfSR.srgb.lower_bound != MPLS_DEFAULT_MIN_SRGB_LABEL)
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
- if (OspfSR.enabled)
+ if (OspfSR.status != SR_OFF)
return CMD_SUCCESS;
if (ospf->vrf_id != VRF_DEFAULT) {
osr_debug("SR: Segment Routing: OFF -> ON");
/* Start Segment Routing */
- OspfSR.enabled = true;
+ OspfSR.status = SR_ON;
ospf_sr_start(ospf);
- /* Set Router Information SR parameters */
- osr_debug("SR: Activate SR for Router Information LSA");
-
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
-
- /* Update Ext LSA */
- osr_debug("SR: Activate SR for Extended Link/Prefix LSA");
-
- ospf_ext_update_sr(true);
-
return CMD_SUCCESS;
}
"Disable Segment Routing\n")
{
- if (!OspfSR.enabled)
+ if (OspfSR.status == SR_OFF)
return CMD_SUCCESS;
osr_debug("SR: Segment Routing: ON -> OFF");
static int ospf_sr_enabled(struct vty *vty)
{
- if (OspfSR.enabled)
+ if (OspfSR.status != SR_OFF)
return 1;
if (vty)
return 0;
}
+/**
+ * Update SRGB following new CLI value.
+ *
+ * @param lower Lower bound of the SRGB
+ * @param size Size of the SRGB
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int update_srgb(uint32_t lower, uint32_t size)
+{
+
+ /* Check if values have changed */
+ if ((OspfSR.srgb.range_size == size)
+ && (OspfSR.srgb.lower_bound == lower))
+ return 0;
+
+ /* Release old SRGB if active. */
+ if (OspfSR.srgb_reserved) {
+ ospf_zebra_release_label_range(
+ OspfSR.srgb.lower_bound,
+ OspfSR.srgb.lower_bound + OspfSR.srgb.range_size - 1);
+ OspfSR.srgb_reserved = false;
+ }
+
+ /* Set new SRGB values */
+ OspfSR.srgb.range_size = size;
+ OspfSR.srgb.lower_bound = lower;
+ if (OspfSR.self != NULL) {
+ OspfSR.self->srgb.range_size = size;
+ OspfSR.self->srgb.lower_bound = lower;
+ }
+
+ /* Check if SR is correctly started i.e. Label Manager connected */
+ if (OspfSR.status != SR_UP)
+ return 0;
+
+ /*
+ * Try to reserve the new block from the Label Manger. If the allocation
+ * fails, disable SR until a new SRGB is successfully allocated.
+ */
+ if (ospf_zebra_request_label_range(OspfSR.srgb.lower_bound,
+ OspfSR.srgb.range_size) < 0) {
+ OspfSR.srgb_reserved = false;
+ ospf_sr_stop();
+ return -1;
+ }
+
+ /* SRGB is reserved, set Router Information parameters */
+ ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+ /* and update NHLFE entries */
+ hash_iterate(OspfSR.neighbors,
+ (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
+ NULL);
+
+ return 0;
+}
+
DEFUN (sr_sid_label_range,
sr_sid_label_range_cmd,
- "segment-routing global-block (0-1048575) (0-1048575)",
+ "segment-routing global-block (16-1048575) (16-1048575)",
SR_STR
"Segment Routing Global Block label range\n"
- "Lower-bound range in decimal (0-1048575)\n"
- "Upper-bound range in decimal (0-1048575)\n")
+ "Lower-bound range in decimal (16-1048575)\n"
+ "Upper-bound range in decimal (16-1048575)\n")
{
uint32_t upper;
uint32_t lower;
upper = strtoul(argv[idx_up]->arg, NULL, 10);
size = upper - lower + 1;
- if (size > MPLS_DEFAULT_MAX_SRGB_SIZE || size <= 0) {
- vty_out(vty,
- "Range size cannot be less than 0 or more than %u\n",
- MPLS_DEFAULT_MAX_SRGB_SIZE);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (upper > MPLS_DEFAULT_MAX_SRGB_LABEL) {
- vty_out(vty, "Upper-bound cannot exceed %u\n",
- MPLS_DEFAULT_MAX_SRGB_LABEL);
+ if (update_srgb(lower, size) < 0)
return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (upper < MPLS_DEFAULT_MIN_SRGB_LABEL) {
- vty_out(vty, "Upper-bound cannot be lower than %u\n",
- MPLS_DEFAULT_MIN_SRGB_LABEL);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Check if values have changed */
- if ((OspfSR.srgb.range_size == size)
- && (OspfSR.srgb.lower_bound == lower))
+ else
return CMD_SUCCESS;
-
- /* Set SID/Label range SRGB */
- OspfSR.srgb.range_size = size;
- OspfSR.srgb.lower_bound = lower;
- if (OspfSR.self != NULL) {
- OspfSR.self->srgb.range_size = size;
- OspfSR.self->srgb.lower_bound = lower;
- }
-
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
-
- /* Update NHLFE entries */
- hash_iterate(OspfSR.neighbors,
- (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
- NULL);
-
- return CMD_SUCCESS;
}
DEFUN (no_sr_sid_label_range,
if (!ospf_sr_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
- /* Revert to default SRGB value */
- OspfSR.srgb.range_size = MPLS_DEFAULT_MIN_SRGB_SIZE;
- OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
- if (OspfSR.self != NULL) {
- OspfSR.self->srgb.range_size = OspfSR.srgb.range_size;
- OspfSR.self->srgb.lower_bound = OspfSR.srgb.lower_bound;
- }
-
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
-
- /* Update NHLFE entries */
- hash_iterate(OspfSR.neighbors,
- (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
- NULL);
-
- return CMD_SUCCESS;
+ if (update_srgb(MPLS_DEFAULT_MIN_SRGB_SIZE,
+ MPLS_DEFAULT_MIN_SRGB_LABEL) < 0)
+ return CMD_WARNING_CONFIG_FAILED;
+ else
+ return CMD_SUCCESS;
}
DEFUN (sr_node_msd,
if (OspfSR.self != NULL)
OspfSR.self->msd = msd;
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+ /* Set Router Information parameters if SR is UP */
+ if (OspfSR.status == SR_UP)
+ ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
return CMD_SUCCESS;
}
if (OspfSR.self != NULL)
OspfSR.self->msd = 0;
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, 0);
+ /* Set Router Information parameters if SR is UP */
+ if (OspfSR.status == SR_UP)
+ ospf_router_info_update_sr(true, OspfSR.srgb, 0);
return CMD_SUCCESS;
}
} else {
listnode_add(OspfSR.self->ext_prefix, new);
}
- ospf_zebra_update_prefix_sid(new);
- /* Finally, update Extended Prefix LSA */
+ /* Install Prefix SID if SR is UP */
+ if (OspfSR.status == SR_UP)
+ ospf_zebra_update_prefix_sid(new);
+ else
+ return CMD_SUCCESS;
+
+ /* Finally, update Extended Prefix LSA id SR is UP */
new->instance = ospf_ext_schedule_prefix_index(
ifp, new->sid, &new->prefv4, new->flags);
if (new->instance == 0) {
if (!ospf_sr_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
+ if (OspfSR.status != SR_UP)
+ return CMD_SUCCESS;
+
/* Get network prefix */
argv_find(argv, argc, "A.B.C.D/M", &idx);
rc = str2prefix(argv[idx]->arg, &p);
bool uj = use_json(argc, argv);
json_object *json = NULL, *json_node_array = NULL;
- if (!OspfSR.enabled) {
+ if (OspfSR.status == SR_OFF) {
vty_out(vty, "Segment Routing is disabled on this router\n");
return CMD_WARNING;
}
/* Zebra structure to hold current status. */
struct zclient *zclient = NULL;
+/* and for the Synchronous connection to the Label Manager */
+static struct zclient *zclient_sync;
/* For registering threads. */
extern struct thread_master *master;
}
}
+/* Label Manager Functions */
+
+/**
+ * Check if Label Manager is Ready or not.
+ *
+ * @return True if Label Manager is ready, False otherwise
+ */
+bool ospf_zebra_label_manager_ready(void)
+{
+ return (zclient_sync->sock > 0);
+}
+
+/**
+ * Request Label Range to the Label Manager.
+ *
+ * @param base base label of the label range to request
+ * @param chunk_size size of the label range to request
+ *
+ * @return 0 on success, -1 on failure
+ */
+int ospf_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
+{
+ int ret;
+ uint32_t start, end;
+
+ if (zclient_sync->sock < 0)
+ return -1;
+
+ ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
+ &end);
+ if (ret < 0) {
+ zlog_warn("%s: error getting label range!", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Release Label Range to the Label Manager.
+ *
+ * @param start start of label range to release
+ * @param end end of label range to release
+ *
+ * @return 0 on success, -1 otherwise
+ */
+int ospf_zebra_release_label_range(uint32_t start, uint32_t end)
+{
+ int ret;
+
+ if (zclient_sync->sock < 0)
+ return -1;
+
+ ret = lm_release_label_chunk(zclient_sync, start, end);
+ 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
+ */
+int ospf_zebra_label_manager_connect(void)
+{
+ /* Connect to label manager. */
+ if (zclient_socket_connect(zclient_sync) < 0) {
+ zlog_warn("%s: failed connecting synchronous zclient!",
+ __func__);
+ return -1;
+ }
+ /* make socket non-blocking */
+ set_nonblocking(zclient_sync->sock);
+
+ /* Send hello to notify zebra this is a synchronous client */
+ 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 */
+ 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;
+ }
+
+ osr_debug("SR (%s): Successfully connected to the Label Manager",
+ __func__);
+
+ return 0;
+}
+
static void ospf_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
zclient->redistribute_route_add = ospf_zebra_read_route;
zclient->redistribute_route_del = ospf_zebra_read_route;
+ /* Initialize special zclient for synchronous message exchanges. */
+ struct zclient_options options = zclient_options_default;
+ options.synchronous = true;
+ zclient_sync = zclient_new(master, &options);
+ zclient_sync->sock = -1;
+ zclient_sync->redist_default = ZEBRA_ROUTE_OSPF;
+ zclient_sync->instance = instance;
+ /*
+ * session_id must be different from default value (0) to distinguish
+ * the asynchronous socket from the synchronous one
+ */
+ zclient_sync->session_id = 1;
+ zclient_sync->privs = &ospfd_privs;
+
access_list_add_hook(ospf_filter_update);
access_list_delete_hook(ospf_filter_update);
prefix_list_add_hook(ospf_prefix_list_update);