summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfdd_cli.c4
-rw-r--r--bgpd/bgp_fsm.c7
-rw-r--r--bgpd/bgp_route.c13
-rw-r--r--doc/developer/ospf-sr.rst19
-rw-r--r--doc/user/ospfd.rst20
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/northbound.c8
-rw-r--r--lib/northbound.h5
-rw-r--r--lib/yang.c3
-rw-r--r--lib/zclient.c31
-rw-r--r--lib/zclient.h5
-rw-r--r--ospfd/ospf_errors.c6
-rw-r--r--ospfd/ospf_errors.h1
-rw-r--r--ospfd/ospf_ext.c174
-rw-r--r--ospfd/ospf_ext.h1
-rw-r--r--ospfd/ospf_interface.c29
-rw-r--r--ospfd/ospf_ri.c86
-rw-r--r--ospfd/ospf_ri.h10
-rw-r--r--ospfd/ospf_route.c97
-rw-r--r--ospfd/ospf_route.h4
-rw-r--r--ospfd/ospf_spf.c777
-rw-r--r--ospfd/ospf_spf.h20
-rw-r--r--ospfd/ospf_sr.c838
-rw-r--r--ospfd/ospf_sr.h74
-rw-r--r--ospfd/ospf_zebra.c119
-rw-r--r--ospfd/ospf_zebra.h4
-rw-r--r--ospfd/ospfd.h4
-rw-r--r--tests/bgpd/test_peer_attr.c2
-rw-r--r--tests/helpers/c/main.c2
-rw-r--r--tests/lib/cli/common_cli.c2
-rw-r--r--tests/lib/cli/test_commands.c2
-rw-r--r--tests/lib/northbound/test_oper_data.c2
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json28
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/ospfd.conf3
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json37
-rw-r--r--tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json34
-rw-r--r--tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json12
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json16
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/ospfd.conf1
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json8
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json27
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/ospfd.conf1
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json8
44 files changed, 1784 insertions, 764 deletions
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 058ce7d1f2..d115684b1c 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -109,7 +109,7 @@ DEFPY_YANG_NOSH(
VRF_NAME_STR)
{
int ret, slen;
- char source_str[INET6_ADDRSTRLEN];
+ char source_str[INET6_ADDRSTRLEN + 32];
char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
if (multihop)
@@ -168,7 +168,7 @@ DEFPY_YANG(
{
int slen;
char xpath[XPATH_MAXLEN];
- char source_str[INET6_ADDRSTRLEN];
+ char source_str[INET6_ADDRSTRLEN + 32];
if (multihop)
snprintf(source_str, sizeof(source_str), "[source-addr='%s']",
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index ab3b88da7a..c8e5a308ef 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -304,8 +304,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
? "accept"
: ""),
peer->host, peer->fd, from_peer->fd);
- bgp_stop(peer);
- bgp_stop(from_peer);
+ BGP_EVENT_ADD(peer, BGP_Stop);
+ BGP_EVENT_ADD(from_peer, BGP_Stop);
return NULL;
}
if (from_peer->status > Active) {
@@ -1673,9 +1673,6 @@ static int bgp_fsm_open(struct peer *peer)
/* Send keepalive and make keepalive timer */
bgp_keepalive_send(peer);
- /* Reset holdtimer value. */
- BGP_TIMER_OFF(peer->t_holdtime);
-
return 0;
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 3a627b4486..912615a59f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3060,6 +3060,7 @@ static uint32_t bgp_filtered_routes_count(struct peer *peer, afi_t afi,
safi_t safi)
{
uint32_t count = 0;
+ bool filtered = false;
struct bgp_dest *dest;
struct bgp_adj_in *ain;
struct bgp_table *table = peer->bgp->rib[afi][safi];
@@ -3071,7 +3072,19 @@ static uint32_t bgp_filtered_routes_count(struct peer *peer, afi_t afi,
if (bgp_input_filter(peer, rn_p, &attr, afi, safi)
== FILTER_DENY)
+ filtered = true;
+
+ if (bgp_input_modifier(
+ peer, rn_p, &attr, afi, safi,
+ ROUTE_MAP_IN_NAME(&peer->filter[afi][safi]),
+ NULL, 0, NULL)
+ == RMAP_DENY)
+ filtered = true;
+
+ if (filtered)
count++;
+
+ bgp_attr_undup(&attr, ain->attr);
}
}
diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst
index 070465db5b..efe9b1b12f 100644
--- a/doc/developer/ospf-sr.rst
+++ b/doc/developer/ospf-sr.rst
@@ -1,8 +1,7 @@
OSPF Segment Routing
====================
-This is an EXPERIMENTAL support of draft
-`draft-ietf-ospf-segment-routing-extensions-24`.
+This is an EXPERIMENTAL support of `RFC 8665`.
DON'T use it for production network.
Supported Features
@@ -10,12 +9,13 @@ Supported Features
* Automatic computation of Primary and Backup Adjacency SID with
Cisco experimental remote IP address
-* SRGB configuration
+* SRGB & SRLB configuration
* Prefix configuration for Node SID with optional NO-PHP flag (Linux
kernel support both mode)
* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels
could be stack)
* Automatic provisioning of MPLS table
+* Equal Cost Multi-Path (ECMP)
* Static route configuration with label stack up to 32 labels
Interoperability
@@ -243,16 +243,16 @@ Routing.
router ospf
ospf router-id 192.168.1.11
capability opaque
- mpls-te on
- mpls-te router-address 192.168.1.11
- router-info area 0.0.0.0
segment-routing on
segment-routing global-block 10000 19999
+ segment-routing local-block 5000 5999
segment-routing node-msd 8
segment-routing prefix 192.168.1.11/32 index 1100
-The first segment-routing statement enable it. The Second one set the SRGB,
-third line the MSD and finally, set the Prefix SID index for a given prefix.
+The first segment-routing statement enables it. The second and third one set
+the SRGB and SRLB respectively, fourth line the MSD and finally, set the
+Prefix SID index for a given prefix.
+
Note that only prefix of Loopback interface could be configured with a Prefix
SID. It is possible to add `no-php-flag` at the end of the prefix command to
disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
@@ -265,9 +265,6 @@ Known limitations
* Only single Area is supported. ABR is not yet supported
* Only SPF algorithm is supported
* Extended Prefix Range is not supported
-* MPLS table are not flush at startup. Thus, restarting zebra process is
- mandatory to remove old MPLS entries in the data plane after a crash of
- ospfd daemon
* With NO Penultimate Hop Popping, it is not possible to express a Segment
Path with an Adjacency SID due to the impossibility for the Linux Kernel to
perform double POP instruction.
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 9aae89daee..010526b637 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -1082,8 +1082,8 @@ Router Information
Segment Routing
===============
-This is an EXPERIMENTAL support of Segment Routing as per draft
-`draft-ietf-ospf-segment-routing-extensions-24.txt` for MPLS dataplane.
+This is an EXPERIMENTAL support of Segment Routing as per `RFC 8665` for MPLS
+dataplane.
.. index:: [no] segment-routing on
.. clicmd:: [no] segment-routing on
@@ -1096,7 +1096,13 @@ This is an EXPERIMENTAL support of Segment Routing as per draft
.. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)
Fix the Segment Routing Global Block i.e. the label range used by MPLS to
- store label in the MPLS FIB.
+ store label in the MPLS FIB for Prefix SID.
+
+.. index:: [no] segment-routing local-block (0-1048575) (0-1048575)
+.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575)
+
+ Fix the Segment Routing Local Block i.e. the label range used by MPLS to
+ store label in the MPLS FIB for Adjacency SID.
.. index:: [no] segment-routing node-msd (1-16)
.. clicmd:: [no] segment-routing node-msd (1-16)
@@ -1104,13 +1110,15 @@ This is an EXPERIMENTAL support of Segment Routing as per draft
Fix the Maximum Stack Depth supported by the router. The value depend of the
MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32.
-.. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
-.. clicmd:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
+.. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]
+.. clicmd:: [no] segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]
Set the Segment Routing index for the specified prefix. Note that, only
prefix with /32 corresponding to a loopback interface are currently
supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR
- node to request to its neighbor to not pop the label.
+ node to request to its neighbor to not pop the label. The 'explicit-null' means that
+ neighbor nodes must swap the incoming label by the MPLS Explicit Null label
+ before delivering the packet.
.. index:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]
.. clicmd:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index fbb97d2dd5..2066e4c96d 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv)
vty_init(master, true);
lib_cmd_init();
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
vty_stdio(vty_do_exit);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 2597eb61e2..500a02aacd 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -719,7 +719,7 @@ struct thread_master *frr_init(void)
debug_init_cli();
- nb_init(master, di->yang_modules, di->n_yang_modules);
+ nb_init(master, di->yang_modules, di->n_yang_modules, true);
if (nb_db_init() != NB_OK)
flog_warn(EC_LIB_NB_DATABASE,
"%s: failed to initialize northbound database",
diff --git a/lib/northbound.c b/lib/northbound.c
index 29e843a84e..18500a8bd2 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -57,6 +57,8 @@ static struct {
const void *owner_user;
} running_config_mgmt_lock;
+/* Knob to record config transaction */
+static bool nb_db_enabled;
/*
* Global lock used to prevent multiple configuration transactions from
* happening concurrently.
@@ -732,7 +734,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
nb_config_replace(running_config, transaction->config, true);
/* Record transaction. */
- if (save_transaction
+ if (save_transaction && nb_db_enabled
&& nb_db_transaction_save(transaction, transaction_id) != NB_OK)
flog_warn(EC_LIB_NB_TRANSACTION_RECORD_FAILED,
"%s: failed to record transaction", __func__);
@@ -2216,7 +2218,7 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
void nb_init(struct thread_master *tm,
const struct frr_yang_module_info *const modules[],
- size_t nmodules)
+ size_t nmodules, bool db_enabled)
{
unsigned int errors = 0;
@@ -2241,6 +2243,8 @@ void nb_init(struct thread_master *tm,
exit(1);
}
+ nb_db_enabled = db_enabled;
+
/* Create an empty running configuration. */
running_config = nb_config_new(NULL);
running_config_entries = hash_create(running_config_entry_key_make,
diff --git a/lib/northbound.h b/lib/northbound.h
index fa5ac5616c..7b481273cb 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -1239,10 +1239,13 @@ extern const char *nb_client_name(enum nb_client client);
*
* nmodules
* Size of the modules array.
+ *
+ * db_enabled
+ * Set this to record the transactions in the transaction log.
*/
extern void nb_init(struct thread_master *tm,
const struct frr_yang_module_info *const modules[],
- size_t nmodules);
+ size_t nmodules, bool db_enabled);
/*
* Finish the northbound layer gracefully. Should be called only when the daemon
diff --git a/lib/yang.c b/lib/yang.c
index 6ab9492d52..9bfdcb858c 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -84,6 +84,9 @@ static const char *yang_module_imp_clb(const char *mod_name,
static const char *const frr_native_modules[] = {
"frr-interface",
"frr-vrf",
+ "frr-routing",
+ "frr-route-map",
+ "frr-nexthop",
"frr-ripd",
"frr-ripngd",
"frr-isisd",
diff --git a/lib/zclient.c b/lib/zclient.c
index 808aa18bbe..6b5f3e349a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -871,6 +871,37 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1,
break;
}
+ if (next1->srte_color < next2->srte_color)
+ return -1;
+ if (next1->srte_color > next2->srte_color)
+ return 1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) ||
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return -1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 1;
+
+ if (next1->backup_num > 0 || next2->backup_num > 0) {
+
+ if (next1->backup_num < next2->backup_num)
+ return -1;
+
+ if (next1->backup_num > next2->backup_num)
+ return 1;
+
+ ret = memcmp(next1->backup_idx,
+ next2->backup_idx, next1->backup_num);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
return 0;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index dab384d5ec..c6a67790a1 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -391,6 +391,11 @@ struct zmsghdr {
} __attribute__((packed));
#define ZAPI_HEADER_CMD_LOCATION offsetof(struct zmsghdr, command)
+/*
+ * ZAPI nexthop. Note that these are sorted when associated with ZAPI routes,
+ * and that sorting must be aligned with the sorting of nexthops in
+ * lib/nexthop.c. Any new fields must be accounted for in zapi_nexthop_cmp().
+ */
struct zapi_nexthop {
enum nexthop_types_t type;
vrf_id_t vrf_id;
diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c
index a985efc668..2de77a43f6 100644
--- a/ospfd/ospf_errors.c
+++ b/ospfd/ospf_errors.c
@@ -158,6 +158,12 @@ static struct log_ref ferr_ospf_err[] = {
.suggestion = "Restart OSPF instance, If the problem persists, report the problem for troubleshooting"
},
{
+ .code = EC_OSPF_SR_SID_OVERFLOW,
+ .title = "OSPF SR Segment-ID overflow",
+ .description = "OSPF Segment Routing ID index or label exceed Global or Local Block Range",
+ .suggestion = "Restart OSPF instance, If the problem persists, report the problem for troubleshooting"
+ },
+ {
.code = EC_OSPF_INVALID_ALGORITHM,
.title = "OSPF SR Invalid Algorithm",
.description = "OSPF Segment Routing invalid Algorithm",
diff --git a/ospfd/ospf_errors.h b/ospfd/ospf_errors.h
index 726f7d9c8b..df5bdaa491 100644
--- a/ospfd/ospf_errors.h
+++ b/ospfd/ospf_errors.h
@@ -31,6 +31,7 @@ enum ospf_log_refs {
EC_OSPF_SR_INVALID_DB,
EC_OSPF_SR_NODE_CREATE,
EC_OSPF_SR_INVALID_LSA_ID,
+ EC_OSPF_SR_SID_OVERFLOW,
EC_OSPF_INVALID_ALGORITHM,
EC_OSPF_FSM_INVALID_STATE,
EC_OSPF_SET_METRIC_PLUS,
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index 6dd5d78bd0..bc952e4ef9 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -98,6 +98,7 @@ static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op);
static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa);
static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa);
+static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti);
static void del_ext_info(void *val);
/*
@@ -434,6 +435,20 @@ static void set_lan_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
exti->lan_sid[index].neighbor_id = neighbor_id;
}
+static void unset_adjacency_sid(struct ext_itf *exti)
+{
+ /* Reset Adjacency TLV */
+ if (exti->type == ADJ_SID) {
+ TLV_TYPE(exti->adj_sid[0]) = 0;
+ TLV_TYPE(exti->adj_sid[1]) = 0;
+ }
+ /* or Lan-Adjacency TLV */
+ if (exti->type == LAN_ADJ_SID) {
+ TLV_TYPE(exti->lan_sid[0]) = 0;
+ TLV_TYPE(exti->lan_sid[1]) = 0;
+ }
+}
+
/* Experimental SubTLV from Cisco */
static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif)
{
@@ -452,7 +467,7 @@ static void ospf_extended_lsa_delete(struct ext_itf *exti)
return;
osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__,
- exti->stype == PREF_SID ? "Prefix" : "",
+ exti->stype == LOCAL_SID ? "Prefix" : "",
exti->stype == ADJ_SID ? "Adjacency" : "",
exti->stype == LAN_ADJ_SID ? "LAN-Adjacency" : "",
exti->ifp->name);
@@ -465,8 +480,10 @@ static void ospf_extended_lsa_delete(struct ext_itf *exti)
/* De-activate this Extended Prefix/Link and remove corresponding
* Segment-Routing Prefix-SID or (LAN)-ADJ-SID */
- exti->flags = EXT_LPFLG_LSA_INACTIVE;
- ospf_sr_ext_itf_delete(exti);
+ if (exti->stype == ADJ_SID || exti->stype == LAN_ADJ_SID)
+ ospf_ext_link_delete_adj_sid(exti);
+ else
+ ospf_sr_ext_itf_delete(exti);
}
/*
@@ -499,7 +516,6 @@ uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
set_prefix_sid(exti, SR_ALGORITHM_SPF, index, SID_INDEX, flags);
/* Try to Schedule LSA */
- // SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_pref_lsa_schedule(exti,
@@ -512,15 +528,104 @@ uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
osr_debug("EXT (%s): Remove prefix for interface %s", __func__,
ifp->name);
- if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
+ if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_pref_lsa_schedule(exti, FLUSH_THIS_LSA);
- exti->flags = EXT_LPFLG_LSA_INACTIVE;
- }
}
return SET_OPAQUE_LSID(exti->type, exti->instance);
}
+/**
+ * Update Adjacecny-SID for Extended Link LSA
+ *
+ * @param exti Extended Link information
+ */
+static void ospf_ext_link_update_adj_sid(struct ext_itf *exti)
+{
+ mpls_label_t label;
+ mpls_label_t bck_label;
+
+ /* Process only (LAN)Adjacency-SID Type */
+ if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
+ return;
+
+ /* Request Primary & Backup Labels from Label Manager */
+ bck_label = ospf_sr_local_block_request_label();
+ label = ospf_sr_local_block_request_label();
+ if (bck_label == MPLS_INVALID_LABEL || label == MPLS_INVALID_LABEL) {
+ if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+ ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
+ return;
+ }
+
+ /* Set Adjacency-SID, backup first */
+ if (exti->stype == ADJ_SID) {
+ set_adj_sid(exti, true, bck_label, SID_LABEL);
+ set_adj_sid(exti, false, label, SID_LABEL);
+ } else {
+ set_lan_adj_sid(exti, true, bck_label, SID_LABEL,
+ exti->lan_sid[0].neighbor_id);
+ set_lan_adj_sid(exti, false, label, SID_LABEL,
+ exti->lan_sid[1].neighbor_id);
+ }
+
+ /* Finally, add corresponding SR Link in SRDB & MPLS LFIB */
+ SET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
+ ospf_sr_ext_itf_add(exti);
+}
+
+/**
+ * Delete Adjacecny-SID for Extended Link LSA
+ *
+ * @param exti Extended Link information
+ */
+static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti)
+{
+ /* Process only (LAN)Adjacency-SID Type */
+ if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
+ return;
+
+ /* Release Primary & Backup Labels from Label Manager */
+ if (exti->stype == ADJ_SID) {
+ ospf_sr_local_block_release_label(exti->adj_sid[0].value);
+ ospf_sr_local_block_release_label(exti->adj_sid[1].value);
+ } else {
+ ospf_sr_local_block_release_label(exti->adj_sid[0].value);
+ ospf_sr_local_block_release_label(exti->adj_sid[1].value);
+ }
+ /* And reset corresponding TLV */
+ unset_adjacency_sid(exti);
+
+ /* Finally, remove corresponding SR Link in SRDB & MPLS LFIB */
+ UNSET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
+ ospf_sr_ext_itf_delete(exti);
+}
+
+/**
+ * Update Extended Link LSA once Segment Routing Label Block has been changed.
+ */
+void ospf_ext_link_srlb_update(void)
+{
+ struct listnode *node;
+ struct ext_itf *exti;
+
+
+ osr_debug("EXT (%s): Update Extended Links with new SRLB", __func__);
+
+ /* Update all Extended Link Adjaceny-SID */
+ for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
+ /* Skip Extended Prefix */
+ if (exti->stype == PREF_SID || exti->stype == LOCAL_SID)
+ continue;
+
+ /* Skip inactive Extended Link */
+ if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
+ continue;
+
+ ospf_ext_link_update_adj_sid(exti);
+ }
+}
+
/*
* Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
*
@@ -541,10 +646,15 @@ void ospf_ext_update_sr(bool enable)
/* Refresh LSAs if already engaged or originate */
for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
- /* Skip inactive Extended Link */
+ /* Skip Inactive Extended Link */
if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
continue;
+ /* Update Extended Link (LAN)Adj-SID if not set */
+ if (!CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
+ ospf_ext_link_update_adj_sid(exti);
+
+ /* Finally, flood the extended Link */
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_lsa_schedule(exti, REFRESH_THIS_LSA);
else
@@ -684,7 +794,6 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
{
struct ospf_interface *oi = nbr->oi;
struct ext_itf *exti;
- uint32_t label;
/* Process Link only when neighbor old or new state is NSM Full */
if (nbr->state != NSM_Full && old_status != NSM_Full)
@@ -709,7 +818,10 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
/* Remove Extended Link if Neighbor State goes Down or Deleted */
if (nbr->state == NSM_Down || nbr->state == NSM_Deleted) {
- ospf_extended_lsa_delete(exti);
+ ospf_ext_link_delete_adj_sid(exti);
+ if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+ ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
+ exti->flags = EXT_LPFLG_LSA_INACTIVE;
return;
}
@@ -729,11 +841,6 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_POINTOPOINT, nbr->router_id,
oi->address->u.prefix4);
- /* Set Extended Link Adjacency SubTLVs, backup first */
- label = get_ext_link_label_value();
- set_adj_sid(exti, true, label, SID_LABEL);
- label = get_ext_link_label_value();
- set_adj_sid(exti, false, label, SID_LABEL);
/* And Remote Interface address */
set_rmt_itf_addr(exti, nbr->address.u.prefix4);
@@ -747,11 +854,9 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
oi->address->u.prefix4);
- /* Set Extended Link Adjacency SubTLVs, backup first */
- label = get_ext_link_label_value();
- set_lan_adj_sid(exti, true, label, SID_LABEL, nbr->router_id);
- label = get_ext_link_label_value();
- set_lan_adj_sid(exti, false, label, SID_LABEL, nbr->router_id);
+ /* Set Neighbor ID */
+ exti->lan_sid[0].neighbor_id = nbr->router_id;
+ exti->lan_sid[1].neighbor_id = nbr->router_id;
break;
@@ -764,36 +869,33 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
oi->address->u.prefix4);
- /* Set Extended Link Adjacency SubTLVs, backup first */
- label = get_ext_link_label_value();
- set_adj_sid(exti, true, label, SID_LABEL);
- label = get_ext_link_label_value();
- set_adj_sid(exti, false, label, SID_LABEL);
-
break;
default:
+ if (CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
+ ospf_ext_link_delete_adj_sid(exti);
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
exti->flags = EXT_LPFLG_LSA_INACTIVE;
return;
}
- osr_debug("EXT (%s): Complete %sAdjacency SID for interface %s ",
- __func__, exti->stype == ADJ_SID ? "" : "LAN-",
- oi->ifp->name);
-
- /* flood this links params if everything is ok */
SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
+
if (OspfEXT.enabled) {
+ osr_debug("EXT (%s): Set %sAdjacency SID for interface %s ",
+ __func__, exti->stype == ADJ_SID ? "" : "LAN-",
+ oi->ifp->name);
+
+ /* Update (LAN)Adjacency SID */
+ ospf_ext_link_update_adj_sid(exti);
+
+ /* flood this links params if everything is ok */
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_link_lsa_schedule(exti, REFRESH_THIS_LSA);
else
ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA);
}
-
- /* Finally install (LAN)Adjacency-SID in the SRDB */
- ospf_sr_ext_itf_add(exti);
}
/* Callbacks to handle Extended Link Segment Routing LSA information */
@@ -1272,10 +1374,6 @@ static int ospf_ext_link_lsa_originate(void *arg)
|| (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
continue;
- /* Skip Extended Link which are not Active */
- if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
- continue;
-
/* Check if LSA not already engaged */
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
if (CHECK_FLAG(exti->flags,
diff --git a/ospfd/ospf_ext.h b/ospfd/ospf_ext.h
index 0071584e26..b1e4feb6df 100644
--- a/ospfd/ospf_ext.h
+++ b/ospfd/ospf_ext.h
@@ -189,6 +189,7 @@ extern int ospf_ext_init(void);
extern void ospf_ext_term(void);
extern void ospf_ext_finish(void);
extern void ospf_ext_update_sr(bool enable);
+extern void ospf_ext_link_srlb_update(void);
extern uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp,
uint32_t index,
struct prefix_ipv4 *p,
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 7977a2a9f4..af801da8d7 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -995,7 +995,8 @@ void ospf_vl_delete(struct ospf *ospf, struct ospf_vl_data *vl_data)
ospf_vl_data_free(vl_data);
}
-static int ospf_vl_set_params(struct ospf_vl_data *vl_data, struct vertex *v)
+static int ospf_vl_set_params(struct ospf_area *area,
+ struct ospf_vl_data *vl_data, struct vertex *v)
{
int changed = 0;
struct ospf_interface *voi;
@@ -1003,6 +1004,7 @@ static int ospf_vl_set_params(struct ospf_vl_data *vl_data, struct vertex *v)
struct vertex_parent *vp = NULL;
unsigned int i;
struct router_lsa *rl;
+ struct ospf_interface *oi;
voi = vl_data->vl_oi;
@@ -1013,17 +1015,24 @@ static int ospf_vl_set_params(struct ospf_vl_data *vl_data, struct vertex *v)
}
for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
- vl_data->nexthop.oi = vp->nexthop->oi;
+ vl_data->nexthop.lsa_pos = vp->nexthop->lsa_pos;
vl_data->nexthop.router = vp->nexthop->router;
- if (!IPV4_ADDR_SAME(&voi->address->u.prefix4,
- &vl_data->nexthop.oi->address->u.prefix4))
- changed = 1;
+ /*
+ * Only deal with interface data when the local
+ * (calculating) node is the SPF root node
+ */
+ if (!area->spf_dry_run) {
+ oi = ospf_if_lookup_by_lsa_pos(
+ area, vl_data->nexthop.lsa_pos);
- voi->address->u.prefix4 =
- vl_data->nexthop.oi->address->u.prefix4;
- voi->address->prefixlen =
- vl_data->nexthop.oi->address->prefixlen;
+ if (!IPV4_ADDR_SAME(&voi->address->u.prefix4,
+ &oi->address->u.prefix4))
+ changed = 1;
+
+ voi->address->u.prefix4 = oi->address->u.prefix4;
+ voi->address->prefixlen = oi->address->prefixlen;
+ }
break; /* We take the first interface. */
}
@@ -1114,7 +1123,7 @@ void ospf_vl_up_check(struct ospf_area *area, struct in_addr rid,
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceUp);
}
- if (ospf_vl_set_params(vl_data, v)) {
+ if (ospf_vl_set_params(area, vl_data, v)) {
if (IS_DEBUG_OSPF(ism, ISM_EVENTS))
zlog_debug(
"ospf_vl_up_check: VL cost change, scheduling router lsa refresh");
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index ececed0643..8eeaf7be3c 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -442,29 +442,52 @@ static void unset_sr_algorithm(uint8_t algo)
TLV_LEN(OspfRI.sr_info.algo) = htons(0);
}
-/* Segment Routing Global Block SubTLV - section 3.2 */
-static void set_sr_sid_label_range(struct sr_srgb srgb)
+/* Set Segment Routing Global Block SubTLV - section 3.2 */
+static void set_sr_global_label_range(struct sr_block srgb)
{
/* Set Header */
- TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE);
- TLV_LEN(OspfRI.sr_info.range) =
+ TLV_TYPE(OspfRI.sr_info.srgb) = htons(RI_SR_TLV_SRGB_LABEL_RANGE);
+ TLV_LEN(OspfRI.sr_info.srgb) =
htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
/* Set Range Size */
- OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size));
+ OspfRI.sr_info.srgb.size = htonl(SET_RANGE_SIZE(srgb.range_size));
/* Set Lower bound label SubTLV */
- TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL);
- TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH);
- OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound));
+ TLV_TYPE(OspfRI.sr_info.srgb.lower) = htons(SUBTLV_SID_LABEL);
+ TLV_LEN(OspfRI.sr_info.srgb.lower) = htons(SID_RANGE_LABEL_LENGTH);
+ OspfRI.sr_info.srgb.lower.value = htonl(SET_LABEL(srgb.lower_bound));
}
-/* Unset this SRGB SubTLV */
-static void unset_sr_sid_label_range(void)
+/* Unset Segment Routing Global Block SubTLV */
+static void unset_sr_global_label_range(void)
{
+ TLV_TYPE(OspfRI.sr_info.srgb) = htons(0);
+ TLV_LEN(OspfRI.sr_info.srgb) = htons(0);
+ TLV_TYPE(OspfRI.sr_info.srgb.lower) = htons(0);
+ TLV_LEN(OspfRI.sr_info.srgb.lower) = htons(0);
+}
- TLV_TYPE(OspfRI.sr_info.range) = htons(0);
- TLV_LEN(OspfRI.sr_info.range) = htons(0);
- TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0);
- TLV_LEN(OspfRI.sr_info.range.lower) = htons(0);
+/* Set Segment Routing Local Block SubTLV - section 3.2 */
+static void set_sr_local_label_range(struct sr_block srlb)
+{
+ /* Set Header */
+ TLV_TYPE(OspfRI.sr_info.srlb) = htons(RI_SR_TLV_SRLB_LABEL_RANGE);
+ TLV_LEN(OspfRI.sr_info.srlb) =
+ htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
+ /* Set Range Size */
+ OspfRI.sr_info.srlb.size = htonl(SET_RANGE_SIZE(srlb.range_size));
+ /* Set Lower bound label SubTLV */
+ TLV_TYPE(OspfRI.sr_info.srlb.lower) = htons(SUBTLV_SID_LABEL);
+ TLV_LEN(OspfRI.sr_info.srlb.lower) = htons(SID_RANGE_LABEL_LENGTH);
+ OspfRI.sr_info.srlb.lower.value = htonl(SET_LABEL(srlb.lower_bound));
+}
+
+/* Unset Segment Routing Local Block SubTLV */
+static void unset_sr_local_label_range(void)
+{
+ TLV_TYPE(OspfRI.sr_info.srlb) = htons(0);
+ TLV_LEN(OspfRI.sr_info.srlb) = htons(0);
+ TLV_TYPE(OspfRI.sr_info.srlb.lower) = htons(0);
+ TLV_LEN(OspfRI.sr_info.srlb.lower) = htons(0);
}
/* Set Maximum Stack Depth for this router */
@@ -563,7 +586,7 @@ static int is_mandated_params_set(struct ospf_router_info ori)
return rc;
if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0)
- && (ntohs(TLV_TYPE(ori.sr_info.range)) == 0))
+ && (ntohs(TLV_TYPE(ori.sr_info.srgb)) == 0))
return rc;
rc = 1;
@@ -575,13 +598,11 @@ static int is_mandated_params_set(struct ospf_router_info ori)
* Used by Segment Routing to set new TLVs and Sub-TLVs values
*
* @param enable To activate or not Segment Routing router Information flooding
- * @param size Size of Label Range i.e. SRGB size
- * @param lower Lower bound of the Label Range i.e. SRGB first label
- * @param msd Maximum label Stack Depth supported by the router
+ * @param srn Self Segment Routing node
*
* @return none
*/
-void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
+void ospf_router_info_update_sr(bool enable, struct sr_node *srn)
{
struct listnode *node, *nnode;
struct ospf_ri_area_info *ai;
@@ -612,15 +633,17 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
/* Unset or Set SR parameters */
if (!enable) {
unset_sr_algorithm(SR_ALGORITHM_SPF);
- unset_sr_sid_label_range();
+ unset_sr_global_label_range();
+ unset_sr_local_label_range();
unset_sr_node_msd();
OspfRI.sr_info.enabled = false;
} else {
// Only SR_ALGORITHM_SPF is supported
set_sr_algorithm(SR_ALGORITHM_SPF);
- set_sr_sid_label_range(srgb);
- if (msd != 0)
- set_sr_node_msd(msd);
+ set_sr_global_label_range(srn->srgb);
+ set_sr_local_label_range(srn->srlb);
+ if (srn->msd != 0)
+ set_sr_node_msd(srn->msd);
else
unset_sr_node_msd();
OspfRI.sr_info.enabled = true;
@@ -698,7 +721,9 @@ static void ospf_router_info_lsa_body_set(struct stream *s)
/* Build Algorithm TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo));
/* Build SRGB TLV */
- build_tlv(s, &TLV_HDR(OspfRI.sr_info.range));
+ build_tlv(s, &TLV_HDR(OspfRI.sr_info.srgb));
+ /* Build SRLB TLV */
+ build_tlv(s, &TLV_HDR(OspfRI.sr_info.srlb));
/* Build MSD TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd));
}
@@ -1409,16 +1434,22 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
if (vty != NULL) {
vty_out(vty,
- " Segment Routing Range TLV:\n"
+ " Segment Routing %s Range TLV:\n"
" Range Size = %d\n"
" SID Label = %d\n\n",
+ ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
+ ? "Global"
+ : "Local",
GET_RANGE_SIZE(ntohl(range->size)),
GET_LABEL(ntohl(range->lower.value)));
} else {
zlog_debug(
- " Segment Routing Range TLV:\n"
+ " Segment Routing %s Range TLV:\n"
" Range Size = %d\n"
" SID Label = %d\n\n",
+ ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
+ ? "Global"
+ : "Local",
GET_RANGE_SIZE(ntohl(range->size)),
GET_LABEL(ntohl(range->lower.value)));
}
@@ -1469,7 +1500,8 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
case RI_SR_TLV_SR_ALGORITHM:
sum += show_vty_sr_algorithm(vty, tlvh);
break;
- case RI_SR_TLV_SID_LABEL_RANGE:
+ case RI_SR_TLV_SRGB_LABEL_RANGE:
+ case RI_SR_TLV_SRLB_LABEL_RANGE:
sum += show_vty_sr_range(vty, tlvh);
break;
case RI_SR_TLV_NODE_MSD:
diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h
index 84511ac5e7..4729677bca 100644
--- a/ospfd/ospf_ri.h
+++ b/ospfd/ospf_ri.h
@@ -201,7 +201,12 @@ struct ospf_ri_sr_info {
* Segment Routing Global Block i.e. label range
* Only one range supported in this code
*/
- struct ri_sr_tlv_sid_label_range range;
+ struct ri_sr_tlv_sid_label_range srgb;
+ /*
+ * Segment Routing Local Block.
+ * Only one block is authorized - see section 3.3
+ */
+ struct ri_sr_tlv_sid_label_range srlb;
/* Maximum SID Depth supported by the node */
struct ri_sr_tlv_node_msd msd;
};
@@ -242,7 +247,6 @@ extern int ospf_router_info_init(void);
extern void ospf_router_info_term(void);
extern void ospf_router_info_finish(void);
extern int ospf_router_info_enable(void);
-extern void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb,
- uint8_t msd);
+extern void ospf_router_info_update_sr(bool enable, struct sr_node *self);
extern struct scope_info ospf_router_info_get_flooding_scope(void);
#endif /* _ZEBRA_OSPF_ROUTER_INFO_H */
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index 776f50b33a..3b049555ba 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -375,7 +375,7 @@ void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
else
route_unlock_node(rn);
- ospf_route_copy_nexthops_from_vertex(or, v);
+ ospf_route_copy_nexthops_from_vertex(area, or, v);
listnode_add(rn->info, or);
@@ -438,7 +438,7 @@ void ospf_intra_add_transit(struct route_table *rt, struct vertex *v,
or->type = OSPF_DESTINATION_NETWORK;
or->u.std.origin = (struct lsa_header *)lsa;
- ospf_route_copy_nexthops_from_vertex(or, v);
+ ospf_route_copy_nexthops_from_vertex(area, or, v);
rn->info = or ;
}
@@ -453,7 +453,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
struct ospf_route * or ;
struct prefix_ipv4 p;
struct router_lsa *lsa;
- struct ospf_interface *oi;
+ struct ospf_interface *oi = NULL;
struct ospf_path *path;
if (IS_DEBUG_OSPF_EVENT)
@@ -538,7 +538,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
zlog_debug(
"ospf_intra_add_stub(): routes are equal, merge");
- ospf_route_copy_nexthops_from_vertex(cur_or, v);
+ ospf_route_copy_nexthops_from_vertex(area, cur_or, v);
if (IPV4_ADDR_CMP(&cur_or->u.std.origin->id,
&lsa->header.id)
@@ -563,7 +563,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
list_delete_all_node(cur_or->paths);
- ospf_route_copy_nexthops_from_vertex(cur_or, v);
+ ospf_route_copy_nexthops_from_vertex(area, cur_or, v);
cur_or->u.std.origin = (struct lsa_header *)lsa;
return;
@@ -588,24 +588,35 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ospf_intra_add_stub(): this network is on remote router");
- ospf_route_copy_nexthops_from_vertex(or, v);
+ ospf_route_copy_nexthops_from_vertex(area, or, v);
} else {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ospf_intra_add_stub(): this network is on this router");
- if ((oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos))) {
+ /*
+ * Only deal with interface data when we
+ * don't do a dry run
+ */
+ if (!area->spf_dry_run)
+ oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos);
+
+ if (oi || area->spf_dry_run) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
- "ospf_intra_add_stub(): the interface is %s",
- IF_NAME(oi));
+ "ospf_intra_add_stub(): the lsa pos is %d",
+ lsa_pos);
path = ospf_path_new();
path->nexthop.s_addr = INADDR_ANY;
- path->ifindex = oi->ifp->ifindex;
- if (CHECK_FLAG(oi->connected->flags,
- ZEBRA_IFA_UNNUMBERED))
- path->unnumbered = 1;
+
+ if (oi) {
+ path->ifindex = oi->ifp->ifindex;
+ if (CHECK_FLAG(oi->connected->flags,
+ ZEBRA_IFA_UNNUMBERED))
+ path->unnumbered = 1;
+ }
+
listnode_add(or->paths, path);
} else {
if (IS_DEBUG_OSPF_EVENT)
@@ -654,6 +665,37 @@ void ospf_route_table_dump(struct route_table *rt)
zlog_debug("========================================");
}
+void ospf_route_table_print(struct vty *vty, struct route_table *rt)
+{
+ struct route_node *rn;
+ struct ospf_route * or ;
+ struct listnode *pnode;
+ struct ospf_path *path;
+
+ vty_out(vty, "========== OSPF routing table ==========\n");
+ for (rn = route_top(rt); rn; rn = route_next(rn))
+ if ((or = rn->info) != NULL) {
+ if (or->type == OSPF_DESTINATION_NETWORK) {
+ vty_out(vty, "N %-18pFX %-15pI4 %s %d\n",
+ &rn->p, & or->u.std.area_id,
+ ospf_path_type_str[or->path_type],
+ or->cost);
+ for (ALL_LIST_ELEMENTS_RO(or->paths, pnode,
+ path))
+ vty_out(vty, " -> %s\n",
+ path->nexthop.s_addr != 0
+ ? inet_ntoa(
+ path->nexthop)
+ : "directly connected");
+ } else
+ vty_out(vty, "R %-18pI4 %-15pI4 %s %d\n",
+ &rn->p.u.prefix4, & or->u.std.area_id,
+ ospf_path_type_str[or->path_type],
+ or->cost);
+ }
+ vty_out(vty, "========================================\n");
+}
+
/* This is 16.4.1 implementation.
o Intra-area paths using non-backbone areas are always the most preferred.
o The other paths, intra-area backbone paths and inter-area paths,
@@ -734,30 +776,41 @@ static int ospf_path_exist(struct list *plist, struct in_addr nexthop,
return 0;
}
-void ospf_route_copy_nexthops_from_vertex(struct ospf_route *to,
+void ospf_route_copy_nexthops_from_vertex(struct ospf_area *area,
+ struct ospf_route *to,
struct vertex *v)
{
struct listnode *node;
struct ospf_path *path;
struct vertex_nexthop *nexthop;
struct vertex_parent *vp;
+ struct ospf_interface *oi = NULL;
assert(to->paths);
for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
nexthop = vp->nexthop;
- if (nexthop->oi != NULL) {
- if (!ospf_path_exist(to->paths, nexthop->router,
- nexthop->oi)) {
- path = ospf_path_new();
- path->nexthop = nexthop->router;
- path->ifindex = nexthop->oi->ifp->ifindex;
- if (CHECK_FLAG(nexthop->oi->connected->flags,
+ /*
+ * Only deal with interface data when we
+ * don't do a dry run
+ */
+ if (!area->spf_dry_run)
+ oi = ospf_if_lookup_by_lsa_pos(area, nexthop->lsa_pos);
+
+ if ((oi && !ospf_path_exist(to->paths, nexthop->router, oi))
+ || area->spf_dry_run) {
+ path = ospf_path_new();
+ path->nexthop = nexthop->router;
+
+ if (oi) {
+ path->ifindex = oi->ifp->ifindex;
+ if (CHECK_FLAG(oi->connected->flags,
ZEBRA_IFA_UNNUMBERED))
path->unnumbered = 1;
- listnode_add(to->paths, path);
}
+
+ listnode_add(to->paths, path);
}
}
}
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index 20cdc75fe8..c3fa5954d5 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -132,6 +132,7 @@ extern void ospf_route_table_free(struct route_table *);
extern void ospf_route_install(struct ospf *, struct route_table *);
extern void ospf_route_table_dump(struct route_table *);
+extern void ospf_route_table_print(struct vty *vty, struct route_table *rt);
extern void ospf_intra_add_router(struct route_table *, struct vertex *,
struct ospf_area *);
@@ -146,7 +147,8 @@ extern void ospf_intra_add_stub(struct route_table *, struct router_lsa_link *,
extern int ospf_route_cmp(struct ospf *, struct ospf_route *,
struct ospf_route *);
extern void ospf_route_copy_nexthops(struct ospf_route *, struct list *);
-extern void ospf_route_copy_nexthops_from_vertex(struct ospf_route *,
+extern void ospf_route_copy_nexthops_from_vertex(struct ospf_area *area,
+ struct ospf_route *,
struct vertex *);
extern void ospf_route_subst(struct route_node *, struct ospf_route *,
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 91fc20475d..6d09d91c5d 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -68,14 +68,17 @@ static void ospf_spf_set_reason(ospf_spf_reason_t reason)
}
static void ospf_vertex_free(void *);
-/* List of allocated vertices, to simplify cleanup of SPF.
+/*
+ * List of allocated vertices, to simplify cleanup of SPF.
* Not thread-safe obviously. If it ever needs to be, it'd have to be
* dynamically allocated at begin of ospf_spf_calculate
*/
static struct list vertex_list = {.del = ospf_vertex_free};
-/* Heap related functions, for the managment of the candidates, to
- * be used with pqueue. */
+/*
+ * Heap related functions, for the managment of the candidates, to
+ * be used with pqueue.
+ */
static int vertex_cmp(const struct vertex *v1, const struct vertex *v2)
{
if (v1->distance != v2->distance)
@@ -118,7 +121,8 @@ static void vertex_nexthop_free(struct vertex_nexthop *nh)
XFREE(MTYPE_OSPF_NEXTHOP, nh);
}
-/* Free the canonical nexthop objects for an area, ie the nexthop objects
+/*
+ * Free the canonical nexthop objects for an area, ie the nexthop objects
* attached to the first-hop router vertices, and any intervening network
* vertices.
*/
@@ -131,7 +135,8 @@ static void ospf_canonical_nexthops_free(struct vertex *root)
struct listnode *n2, *nn2;
struct vertex_parent *vp;
- /* router vertices through an attached network each
+ /*
+ * router vertices through an attached network each
* have a distinct (canonical / not inherited) nexthop
* which must be freed.
*
@@ -150,7 +155,8 @@ static void ospf_canonical_nexthops_free(struct vertex *root)
}
}
-/* TODO: Parent list should be excised, in favour of maintaining only
+/*
+ * TODO: Parent list should be excised, in favour of maintaining only
* vertex_nexthop, with refcounts.
*/
static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
@@ -163,6 +169,7 @@ static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
new->parent = v;
new->backlink = backlink;
new->nexthop = hop;
+
return new;
}
@@ -202,6 +209,7 @@ static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
new->type == OSPF_VERTEX_ROUTER ? "Router"
: "Network",
inet_ntoa(new->lsa->id));
+
return new;
}
@@ -214,14 +222,6 @@ static void ospf_vertex_free(void *data)
v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
inet_ntoa(v->lsa->id));
- /* There should be no parents potentially holding references to this
- * vertex
- * Children however may still be there, but presumably referenced by
- * other
- * vertices
- */
- // assert (listcount (v->parents) == 0);
-
if (v->children)
list_delete(&v->children);
@@ -252,14 +252,12 @@ static void ospf_vertex_dump(const char *msg, struct vertex *v,
if (vp) {
zlog_debug(
- "parent %s backlink %d nexthop %s interface %s",
+ "parent %s backlink %d nexthop %s lsa pos %d",
inet_ntoa(vp->parent->lsa->id),
vp->backlink,
inet_ntop(AF_INET, &vp->nexthop->router,
buf1, BUFSIZ),
- vp->nexthop->oi
- ? IF_NAME(vp->nexthop->oi)
- : "NULL");
+ vp->nexthop->lsa_pos);
}
}
}
@@ -291,14 +289,17 @@ static void ospf_vertex_add_parent(struct vertex *v)
}
}
-static void ospf_spf_init(struct ospf_area *area)
+static void ospf_spf_init(struct ospf_area *area, struct ospf_lsa *root_lsa,
+ bool is_dry_run, bool is_root_node)
{
struct vertex *v;
/* Create root node. */
- v = ospf_vertex_new(area->router_lsa_self);
+ v = ospf_vertex_new(root_lsa);
area->spf = v;
+ area->spf_dry_run = is_dry_run;
+ area->spf_root_node = is_root_node;
/* Reset ABR and ASBR router counts. */
area->abr_count = 0;
@@ -364,7 +365,8 @@ static int ospf_lsa_has_link(struct lsa_header *w, struct lsa_header *v)
return -1;
}
-/* Find the next link after prev_link from v to w. If prev_link is
+/*
+ * Find the next link after prev_link from v to w. If prev_link is
* NULL, return the first link from v to w. Ignore stub and virtual links;
* these link types will never be returned.
*/
@@ -433,10 +435,11 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
assert(v && w && newhop);
assert(distance);
- /* IFF w has already been assigned a distance, then we shouldn't get
- * here
- * unless callers have determined V(l)->W is shortest / equal-shortest
- * path (0 is a special case distance (no distance yet assigned)).
+ /*
+ * IFF w has already been assigned a distance, then we shouldn't get
+ * here unless callers have determined V(l)->W is shortest /
+ * equal-shortest path (0 is a special case distance (no distance yet
+ * assigned)).
*/
if (w->distance)
assert(distance <= w->distance);
@@ -452,7 +455,8 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
sizeof(buf[1])));
}
- /* Adding parent for a new, better path: flush existing parents from W.
+ /*
+ * Adding parent for a new, better path: flush existing parents from W.
*/
if (distance < w->distance) {
if (IS_DEBUG_OSPF_EVENT)
@@ -463,7 +467,8 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
w->distance = distance;
}
- /* new parent is <= existing parents, add it to parent list (if nexthop
+ /*
+ * new parent is <= existing parents, add it to parent list (if nexthop
* not on parent list)
*/
for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) {
@@ -482,7 +487,43 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
return;
}
-/* 16.1.1. Calculate nexthop from root through V (parent) to
+static int match_stub_prefix(struct lsa_header *lsa, struct in_addr v_link_addr,
+ struct in_addr w_link_addr)
+{
+ uint8_t *p, *lim;
+ struct router_lsa_link *l = NULL;
+ struct in_addr masked_lsa_addr;
+
+ if (lsa->type != OSPF_ROUTER_LSA)
+ return 0;
+
+ p = ((uint8_t *)lsa) + OSPF_LSA_HEADER_SIZE + 4;
+ lim = ((uint8_t *)lsa) + ntohs(lsa->length);
+
+ while (p < lim) {
+ l = (struct router_lsa_link *)p;
+ p += (OSPF_ROUTER_LSA_LINK_SIZE
+ + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
+
+ if (l->m[0].type != LSA_LINK_TYPE_STUB)
+ continue;
+
+ masked_lsa_addr.s_addr =
+ (l->link_id.s_addr & l->link_data.s_addr);
+
+ /* check that both links belong to the same stub subnet */
+ if ((masked_lsa_addr.s_addr
+ == (v_link_addr.s_addr & l->link_data.s_addr))
+ && (masked_lsa_addr.s_addr
+ == (w_link_addr.s_addr & l->link_data.s_addr)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * 16.1.1. Calculate nexthop from root through V (parent) to
* vertex W (destination), with given distance from root->W.
*
* The link must be supplied if V is the root vertex. In all other cases
@@ -501,7 +542,6 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
struct listnode *node, *nnode;
struct vertex_nexthop *nh;
struct vertex_parent *vp;
- struct ospf_interface *oi = NULL;
unsigned int added = 0;
char buf1[BUFSIZ];
char buf2[BUFSIZ];
@@ -514,154 +554,140 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
}
if (v == area->spf) {
- /* 16.1.1 para 4. In the first case, the parent vertex (V) is
- the
- root (the calculating router itself). This means that the
- destination is either a directly connected network or
- directly
- connected router. The outgoing interface in this case is
- simply
- the OSPF interface connecting to the destination
- network/router.
- */
+ /*
+ * 16.1.1 para 4. In the first case, the parent vertex (V) is
+ * the root (the calculating router itself). This means that
+ * the destination is either a directly connected network or
+ * directly connected router. The outgoing interface in this
+ * case is simply the OSPF interface connecting to the
+ * destination network/router.
+ */
/* we *must* be supplied with the link data */
assert(l != NULL);
- oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos);
- if (!oi) {
- zlog_debug(
- "%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s",
- __func__, lsa_pos,
- inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
- inet_ntop(AF_INET, &l->link_data, buf2,
- BUFSIZ));
- return 0;
- }
if (IS_DEBUG_OSPF_EVENT) {
zlog_debug(
- "%s: considering link:%s type:%d link_id:%s link_data:%s",
- __func__, oi->ifp->name, l->m[0].type,
+ "%s: considering link type:%d link_id:%s link_data:%s",
+ __func__, l->m[0].type,
inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
inet_ntop(AF_INET, &l->link_data, buf2,
BUFSIZ));
}
if (w->type == OSPF_VERTEX_ROUTER) {
- /* l is a link from v to w
- * l2 will be link from w to v
+ /*
+ * l is a link from v to w l2 will be link from w to v
*/
struct router_lsa_link *l2 = NULL;
if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) {
- struct in_addr nexthop = {.s_addr = 0};
- /* If the destination is a router which connects
- to
- the calculating router via a
- Point-to-MultiPoint
- network, the destination's next hop IP
- address(es)
- can be determined by examining the
- destination's
- router-LSA: each link pointing back to the
- calculating router and having a Link Data
- field
- belonging to the Point-to-MultiPoint network
- provides an IP address of the next hop
- router.
-
- At this point l is a link from V to W, and V
- is the
- root ("us"). If it is a point-to-multipoint
- interface,
- then look through the links in the opposite
- direction (W to V).
- If any of them have an address that lands
- within the
- subnet declared by the PtMP link, then that
- link
- is a constituent of the PtMP link, and its
- address is
- a nexthop address for V.
- */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
- /* Having nexthop = 0 is tempting, but
- NOT acceptable.
- It breaks AS-External routes with a
- forwarding address,
- since
- ospf_ase_complete_direct_routes()
- will mistakenly
- assume we've reached the last hop and
- should place the
- forwarding address as nexthop.
- Also, users may configure
- multi-access links in p2p mode,
- so we need the IP to ARP the nexthop.
- */
- struct ospf_neighbor *nbr_w;
-
- nbr_w = ospf_nbr_lookup_by_routerid(
- oi->nbrs, &l->link_id);
- if (nbr_w != NULL) {
- added = 1;
- nexthop = nbr_w->src;
- }
- } else if (oi->type
- == OSPF_IFTYPE_POINTOMULTIPOINT) {
- struct prefix_ipv4 la;
+ /*
+ * If the destination is a router which connects
+ * to the calculating router via a
+ * Point-to-MultiPoint network, the
+ * destination's next hop IP address(es) can be
+ * determined by examining the destination's
+ * router-LSA: each link pointing back to the
+ * calculating router and having a Link Data
+ * field belonging to the Point-to-MultiPoint
+ * network provides an IP address of the next
+ * hop router.
+ *
+ * At this point l is a link from V to W, and V
+ * is the root ("us"). If it is a point-to-
+ * multipoint interface, then look through the
+ * links in the opposite direction (W to V).
+ * If any of them have an address that lands
+ * within the subnet declared by the PtMP link,
+ * then that link is a constituent of the PtMP
+ * link, and its address is a nexthop address
+ * for V.
+ *
+ * Note for point-to-point interfaces:
+ *
+ * Having nexthop = 0 (as proposed in the RFC)
+ * is tempting, but NOT acceptable. It breaks
+ * AS-External routes with a forwarding address,
+ * since ospf_ase_complete_direct_routes() will
+ * mistakenly assume we've reached the last hop
+ * and should place the forwarding address as
+ * nexthop. Also, users may configure multi-
+ * access links in p2p mode, so we need the IP
+ * to ARP the nexthop.
+ *
+ * If the calculating router is the SPF root
+ * node and the link is P2P then access the
+ * interface information directly. This can be
+ * crucial when e.g. IP unnumbered is used
+ * where 'correct' nexthop information are not
+ * available via Router LSAs.
+ *
+ * Otherwise handle P2P and P2MP the same way
+ * as described above using a reverse lookup to
+ * figure out the nexthop.
+ */
- la.family = AF_INET;
- la.prefixlen = oi->address->prefixlen;
+ struct in_addr nexthop = {.s_addr = 0};
+ struct ospf_interface *oi = NULL;
+ struct ospf_neighbor *nbr_w = NULL;
+
+ /* Calculating node is root node, link is P2P */
+ if (area->spf_root_node) {
+ oi = ospf_if_lookup_by_lsa_pos(area,
+ lsa_pos);
+ if (oi->type
+ == OSPF_IFTYPE_POINTOPOINT) {
+ nbr_w = ospf_nbr_lookup_by_routerid(
+ oi->nbrs, &l->link_id);
+ if (nbr_w) {
+ added = 1;
+ nexthop = nbr_w->src;
+ }
+ }
+ }
- /* V links to W on PtMP interface
- - find the interface address on W */
+ /* Reverse lookup */
+ if (!added) {
while ((l2 = ospf_get_next_link(w, v,
l2))) {
- la.prefix = l2->link_data;
-
- if (prefix_cmp((struct prefix
- *)&la,
- oi->address)
- != 0)
- continue;
- /* link_data is on our PtMP
- * network */
- added = 1;
- nexthop = l2->link_data;
- break;
+ if (match_stub_prefix(
+ v->lsa,
+ l->link_data,
+ l2->link_data)) {
+ added = 1;
+ nexthop = l2->link_data;
+ break;
+ }
}
}
if (added) {
- /* found all necessary info to build
- * nexthop */
nh = vertex_nexthop_new();
- nh->oi = oi;
nh->router = nexthop;
+ nh->lsa_pos = lsa_pos;
ospf_spf_add_parent(v, w, nh, distance);
return 1;
} else
zlog_info(
- "%s: could not determine nexthop for link %s",
- __func__, oi->ifp->name);
+ "%s: could not determine nexthop for link",
+ __func__);
} /* end point-to-point link from V to W */
else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) {
- struct ospf_vl_data *vl_data;
-
- /* VLink implementation limitations:
- * a) vl_data can only reference one nexthop, so
- * no ECMP
- * to backbone through VLinks. Though
- * transit-area
- * summaries may be considered, and those can
- * be ECMP.
+ /*
+ * VLink implementation limitations:
+ * a) vl_data can only reference one nexthop,
+ * so no ECMP to backbone through VLinks.
+ * Though transit-area summaries may be
+ * considered, and those can be ECMP.
* b) We can only use /one/ VLink, even if
- * multiple ones
- * exist this router through multiple
- * transit-areas.
+ * multiple ones exist this router through
+ * multiple transit-areas.
*/
+
+ struct ospf_vl_data *vl_data;
+
vl_data = ospf_vl_lookup(area->ospf, NULL,
l->link_id);
@@ -669,8 +695,8 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
&& CHECK_FLAG(vl_data->flags,
OSPF_VL_FLAG_APPROVED)) {
nh = vertex_nexthop_new();
- nh->oi = vl_data->nexthop.oi;
nh->router = vl_data->nexthop.router;
+ nh->lsa_pos = vl_data->nexthop.lsa_pos;
ospf_spf_add_parent(v, w, nh, distance);
return 1;
} else
@@ -683,8 +709,8 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
assert(w->type == OSPF_VERTEX_NETWORK);
nh = vertex_nexthop_new();
- nh->oi = oi;
nh->router.s_addr = 0; /* Nexthop not required */
+ nh->lsa_pos = lsa_pos;
ospf_spf_add_parent(v, w, nh, distance);
return 1;
}
@@ -693,82 +719,70 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
else if (v->type == OSPF_VERTEX_NETWORK) {
/* See if any of V's parents are the root. */
for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
- if (vp->parent == area->spf) /* connects to root? */
- {
- /* 16.1.1 para 5. ...the parent vertex is a
- * network that
- * directly connects the calculating router to
- * the destination
- * router. The list of next hops is then
- * determined by
- * examining the destination's router-LSA...
+ if (vp->parent == area->spf) {
+ /*
+ * 16.1.1 para 5. ...the parent vertex is a
+ * network that directly connects the
+ * calculating router to the destination
+ * router. The list of next hops is then
+ * determined by examining the destination's
+ * router-LSA ...
*/
assert(w->type == OSPF_VERTEX_ROUTER);
while ((l = ospf_get_next_link(w, v, l))) {
- /* ...For each link in the router-LSA
- * that points back to the
- * parent network, the link's Link Data
- * field provides the IP
- * address of a next hop router. The
- * outgoing interface to
- * use can then be derived from the next
- * hop IP address (or
- * it can be inherited from the parent
- * network).
+ /*
+ * ... For each link in the router-LSA
+ * that points back to the parent
+ * network, the link's Link Data field
+ * provides the IP address of a next hop
+ * router. The outgoing interface to use
+ * can then be derived from the next
+ * hop IP address (or it can be
+ * inherited from the parent network).
*/
nh = vertex_nexthop_new();
- nh->oi = vp->nexthop->oi;
nh->router = l->link_data;
+ nh->lsa_pos = vp->nexthop->lsa_pos;
added = 1;
ospf_spf_add_parent(v, w, nh, distance);
}
- /* Note lack of return is deliberate. See next
- * comment. */
+ /*
+ * Note lack of return is deliberate. See next
+ * comment.
+ */
}
}
- /* NB: This code is non-trivial.
+ /*
+ * NB: This code is non-trivial.
*
* E.g. it is not enough to know that V connects to the root. It
- * is
- * also important that the while above, looping through all
- * links from
- * W->V found at least one link, so that we know there is
- * bi-directional connectivity between V and W (which need not
- * be the
- * case, e.g. when OSPF has not yet converged fully).
- * Otherwise, if
- * we /always/ return here, without having checked that
- * root->V->-W
- * actually resulted in a valid nexthop being created, then we
- * we will
- * prevent SPF from finding/using higher cost paths.
+ * is also important that the while above, looping through all
+ * links from W->V found at least one link, so that we know
+ * there is bi-directional connectivity between V and W (which
+ * need not be the case, e.g. when OSPF has not yet converged
+ * fully). Otherwise, if we /always/ return here, without having
+ * checked that root->V->-W actually resulted in a valid nexthop
+ * being created, then we we will prevent SPF from finding/using
+ * higher cost paths.
*
* It is important, if root->V->W has not been added, that we
- * continue
- * through to the intervening-router nexthop code below. So as
- * to
- * ensure other paths to V may be used. This avoids unnecessary
- * blackholes while OSPF is convergening.
+ * continue through to the intervening-router nexthop code
+ * below. So as to ensure other paths to V may be used. This
+ * avoids unnecessary blackholes while OSPF is converging.
*
* I.e. we may have arrived at this function, examining V -> W,
- * via
- * workable paths other than root -> V, and it's important to
- * avoid
- * getting "confused" by non-working root->V->W path - it's
- * important
- * to *not* lose the working non-root paths, just because of a
- * non-viable root->V->W.
- *
- * See also bug #330 (required reading!), and:
- *
- * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes
+ * via workable paths other than root -> V, and it's important
+ * to avoid getting "confused" by non-working root->V->W path
+ * - it's important to *not* lose the working non-root paths,
+ * just because of a non-viable root->V->W.
*/
if (added)
return added;
}
- /* 16.1.1 para 4. If there is at least one intervening router in the
+ /*
+ * 16.1.1 para 4. If there is at least one intervening router in the
* current shortest path between the destination and the root, the
* destination simply inherits the set of next hops from the
* parent.
@@ -785,13 +799,13 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
return added;
}
-/* RFC2328 Section 16.1 (2).
- * v is on the SPF tree. Examine the links in v's LSA. Update the list
- * of candidates with any vertices not already on the list. If a lower-cost
- * path is found to a vertex already on the candidate list, store the new cost.
+/*
+ * RFC2328 16.1 (2).
+ * v is on the SPF tree. Examine the links in v's LSA. Update the list of
+ * candidates with any vertices not already on the list. If a lower-cost path
+ * is found to a vertex already on the candidate list, store the new cost.
*/
-static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
- struct ospf_area *area,
+static void ospf_spf_next(struct vertex *v, struct ospf_area *area,
struct vertex_pqueue_head *candidate)
{
struct ospf_lsa *w_lsa = NULL;
@@ -801,8 +815,10 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
struct in_addr *r;
int type = 0, lsa_pos = -1, lsa_pos_next = 0;
- /* If this is a router-LSA, and bit V of the router-LSA (see Section
- A.4.2:RFC2328) is set, set Area A's TransitCapability to true. */
+ /*
+ * If this is a router-LSA, and bit V of the router-LSA (see Section
+ * A.4.2:RFC2328) is set, set Area A's TransitCapability to true.
+ */
if (v->type == OSPF_VERTEX_ROUTER) {
if (IS_ROUTER_LSA_VIRTUAL((struct router_lsa *)v->lsa))
area->transit = OSPF_TRANSIT_TRUE;
@@ -826,40 +842,39 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
lsa_pos = lsa_pos_next; /* LSA link position */
lsa_pos_next++;
+
p += (OSPF_ROUTER_LSA_LINK_SIZE
+ (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
- /* (a) If this is a link to a stub network, examine the
- next
- link in V's LSA. Links to stub networks will be
- considered in the second stage of the shortest path
- calculation. */
+ /*
+ * (a) If this is a link to a stub network, examine the
+ * next link in V's LSA. Links to stub networks will
+ * be considered in the second stage of the shortest
+ * path calculation.
+ */
if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
continue;
- /* (b) Otherwise, W is a transit vertex (router or
- transit
- network). Look up the vertex W's LSA (router-LSA or
- network-LSA) in Area A's link state database. */
+ /*
+ * (b) Otherwise, W is a transit vertex (router or
+ * transit network). Look up the vertex W's LSA
+ * (router-LSA or network-LSA) in Area A's link state
+ * database.
+ */
switch (type) {
case LSA_LINK_TYPE_POINTOPOINT:
case LSA_LINK_TYPE_VIRTUALLINK:
- if (type == LSA_LINK_TYPE_VIRTUALLINK) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "looking up LSA through VL: %s",
- inet_ntoa(l->link_id));
- }
-
- w_lsa = ospf_lsa_lookup(ospf, area,
+ if (type == LSA_LINK_TYPE_VIRTUALLINK
+ && IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "looking up LSA through VL: %s",
+ inet_ntoa(l->link_id));
+ w_lsa = ospf_lsa_lookup(area->ospf, area,
OSPF_ROUTER_LSA,
l->link_id, l->link_id);
- if (w_lsa) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "found Router LSA %s",
- inet_ntoa(l->link_id));
- }
+ if (w_lsa && IS_DEBUG_OSPF_EVENT)
+ zlog_debug("found Router LSA %s",
+ inet_ntoa(l->link_id));
break;
case LSA_LINK_TYPE_TRANSIT:
if (IS_DEBUG_OSPF_EVENT)
@@ -868,9 +883,8 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
inet_ntoa(l->link_id));
w_lsa = ospf_lsa_lookup_by_id(
area, OSPF_NETWORK_LSA, l->link_id);
- if (w_lsa)
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("found the LSA");
+ if (w_lsa && IS_DEBUG_OSPF_EVENT)
+ zlog_debug("found the LSA");
break;
default:
flog_warn(EC_OSPF_LSA,
@@ -888,19 +902,19 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
/* Lookup the vertex W's LSA. */
w_lsa = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
*r);
- if (w_lsa) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("found Router LSA %s",
- inet_ntoa(w_lsa->data->id));
- }
+ if (w_lsa && IS_DEBUG_OSPF_EVENT)
+ zlog_debug("found Router LSA %s",
+ inet_ntoa(w_lsa->data->id));
/* step (d) below */
distance = v->distance;
}
- /* (b cont.) If the LSA does not exist, or its LS age is equal
- to MaxAge, or it does not have a link back to vertex V,
- examine the next link in V's LSA.[23] */
+ /*
+ * (b cont.) If the LSA does not exist, or its LS age is equal
+ * to MaxAge, or it does not have a link back to vertex V,
+ * examine the next link in V's LSA.[23]
+ */
if (w_lsa == NULL) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("No LSA found");
@@ -919,19 +933,23 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
continue;
}
- /* (c) If vertex W is already on the shortest-path tree, examine
- the next link in the LSA. */
+ /*
+ * (c) If vertex W is already on the shortest-path tree, examine
+ * the next link in the LSA.
+ */
if (w_lsa->stat == LSA_SPF_IN_SPFTREE) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("The LSA is already in SPF");
continue;
}
- /* (d) Calculate the link state cost D of the resulting path
- from the root to vertex W. D is equal to the sum of the link
- state cost of the (already calculated) shortest path to
- vertex V and the advertised cost of the link between vertices
- V and W. If D is: */
+ /*
+ * (d) Calculate the link state cost D of the resulting path
+ * from the root to vertex W. D is equal to the sum of the link
+ * state cost of the (already calculated) shortest path to
+ * vertex V and the advertised cost of the link between vertices
+ * V and W. If D is:
+ */
/* calculate link cost D -- moved above */
@@ -948,29 +966,28 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
zlog_debug("Nexthop Calc failed");
} else if (w_lsa->stat != LSA_SPF_IN_SPFTREE) {
w = w_lsa->stat;
- /* if D is greater than. */
if (w->distance < distance) {
continue;
}
- /* equal to. */
else if (w->distance == distance) {
- /* Found an equal-cost path to W.
- * Calculate nexthop of to W from V. */
+ /*
+ * Found an equal-cost path to W.
+ * Calculate nexthop of to W from V.
+ */
ospf_nexthop_calculation(area, v, w, l,
distance, lsa_pos);
}
- /* less than. */
else {
- /* Found a lower-cost path to W.
+ /*
+ * Found a lower-cost path to W.
* nexthop_calculation is conditional, if it
- * finds
- * valid nexthop it will call spf_add_parents,
- * which
- * will flush the old parents
+ * finds valid nexthop it will call
+ * spf_add_parents, which will flush the old
+ * parents.
*/
vertex_pqueue_del(candidate, w);
ospf_nexthop_calculation(area, v, w, l,
- distance, lsa_pos);
+ distance, lsa_pos);
vertex_pqueue_add(candidate, w);
}
} /* end W is already on the candidate list */
@@ -997,11 +1014,9 @@ static void ospf_spf_dump(struct vertex *v, int i)
if (IS_DEBUG_OSPF_EVENT)
for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) {
- zlog_debug(" nexthop %p %s %s", (void *)parent->nexthop,
+ zlog_debug(" nexthop %p %s %d", (void *)parent->nexthop,
inet_ntoa(parent->nexthop->router),
- parent->nexthop->oi
- ? IF_NAME(parent->nexthop->oi)
- : "NULL");
+ parent->nexthop->lsa_pos);
}
i++;
@@ -1010,6 +1025,33 @@ static void ospf_spf_dump(struct vertex *v, int i)
ospf_spf_dump(v, i);
}
+void ospf_spf_print(struct vty *vty, struct vertex *v, int i)
+{
+ struct listnode *cnode;
+ struct listnode *nnode;
+ struct vertex_parent *parent;
+
+ if (v->type == OSPF_VERTEX_ROUTER) {
+ vty_out(vty, "SPF Result: depth %d [R] %s\n", i,
+ inet_ntoa(v->lsa->id));
+ } else {
+ struct network_lsa *lsa = (struct network_lsa *)v->lsa;
+ vty_out(vty, "SPF Result: depth %d [N] %s/%d\n", i,
+ inet_ntoa(v->lsa->id), ip_masklen(lsa->mask));
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) {
+ vty_out(vty, " nexthop %s lsa pos %d\n",
+ inet_ntoa(parent->nexthop->router),
+ parent->nexthop->lsa_pos);
+ }
+
+ i++;
+
+ for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v))
+ ospf_spf_print(vty, v, i);
+}
+
/* Second stage of SPF calculation. */
static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
struct route_table *rt, int parent_is_root)
@@ -1020,24 +1062,26 @@ static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("ospf_process_stub():processing stubs for area %s",
inet_ntoa(area->area_id));
+
if (v->type == OSPF_VERTEX_ROUTER) {
uint8_t *p;
uint8_t *lim;
struct router_lsa_link *l;
- struct router_lsa *rlsa;
+ struct router_lsa *router_lsa;
int lsa_pos = 0;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ospf_process_stubs():processing router LSA, id: %s",
inet_ntoa(v->lsa->id));
- rlsa = (struct router_lsa *)v->lsa;
+ router_lsa = (struct router_lsa *)v->lsa;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ospf_process_stubs(): we have %d links to process",
- ntohs(rlsa->links));
+ ntohs(router_lsa->links));
+
p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
@@ -1061,7 +1105,8 @@ static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
if (CHECK_FLAG(child->flags, OSPF_VERTEX_PROCESSED))
continue;
- /* the first level of routers connected to the root
+ /*
+ * The first level of routers connected to the root
* should have 'parent_is_root' set, including those
* connected via a network vertex.
*/
@@ -1097,6 +1142,7 @@ void ospf_rtrs_free(struct route_table *rtrs)
rn->info = NULL;
route_unlock_node(rn);
}
+
route_table_finish(rtrs);
}
@@ -1162,10 +1208,11 @@ ospf_rtrs_print (struct route_table *rtrs)
}
#endif
-/* Calculating the shortest-path tree for an area. */
-static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
- struct route_table *new_table,
- struct route_table *new_rtrs)
+/* Calculating the shortest-path tree for an area, see RFC2328 16.1. */
+void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
+ struct route_table *new_table,
+ struct route_table *new_rtrs, bool is_dry_run,
+ bool is_root_node)
{
struct vertex_pqueue_head candidate;
struct vertex *v;
@@ -1176,55 +1223,57 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
inet_ntoa(area->area_id));
}
- /* Check router-lsa-self. If self-router-lsa is not yet allocated,
- return this area's calculation. */
- if (!area->router_lsa_self) {
+ /*
+ * If the router LSA of the root is not yet allocated, return this
+ * area's calculation. In the 'usual' case the root_lsa is the
+ * self-originated router LSA of the node itself.
+ */
+ if (!root_lsa) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
- "ospf_spf_calculate: Skip area %s's calculation due to empty router_lsa_self",
+ "ospf_spf_calculate: Skip area %s's calculation due to empty root LSA",
inet_ntoa(area->area_id));
return;
}
- /* RFC2328 16.1. (1). */
- /* Initialize the algorithm's data structures. */
+ /* Initialize the algorithm's data structures, see RFC2328 16.1. (1). */
- /* This function scans all the LSA database and set the stat field to
- * LSA_SPF_NOT_EXPLORED. */
+ /*
+ * This function scans all the LSA database and set the stat field to
+ * LSA_SPF_NOT_EXPLORED.
+ */
lsdb_clean_stat(area->lsdb);
+
/* Create a new heap for the candidates. */
vertex_pqueue_init(&candidate);
- /* Initialize the shortest-path tree to only the root (which is the
- router doing the calculation). */
- ospf_spf_init(area);
- v = area->spf;
- /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of
- * the
- * spanning tree. */
- v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
+ /*
+ * Initialize the shortest-path tree to only the root (which is usually
+ * the router doing the calculation).
+ */
+ ospf_spf_init(area, root_lsa, is_dry_run, is_root_node);
/* Set Area A's TransitCapability to false. */
area->transit = OSPF_TRANSIT_FALSE;
area->shortcut_capability = 1;
+ /*
+ * Use the root vertex for the start of the SPF algorithm and make it
+ * part of the tree.
+ */
+ v = area->spf;
+ v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
+
for (;;) {
/* RFC2328 16.1. (2). */
- ospf_spf_next(v, ospf, area, &candidate);
+ ospf_spf_next(v, area, &candidate);
/* RFC2328 16.1. (3). */
- /* If at this step the candidate list is empty, the shortest-
- path tree (of transit vertices) has been completely built and
- this stage of the procedure terminates. */
- /* Otherwise, choose the vertex belonging to the candidate list
- that is closest to the root, and add it to the shortest-path
- tree (removing it from the candidate list in the
- process). */
- /* Extract from the candidates the node with the lower key. */
v = vertex_pqueue_pop(&candidate);
if (!v)
+ /* No more vertices left. */
break;
- /* Update stat field in vertex. */
+
v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
ospf_vertex_add_parent(v);
@@ -1235,28 +1284,21 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
else
ospf_intra_add_transit(new_table, v, area);
- /* RFC2328 16.1. (5). */
- /* Iterate the algorithm by returning to Step 2. */
-
- } /* end loop until no more candidate vertices */
+ /* Iterate back to (2), see RFC2328 16.1. (5). */
+ }
if (IS_DEBUG_OSPF_EVENT) {
ospf_spf_dump(area->spf, 0);
ospf_route_table_dump(new_table);
}
- /* Second stage of SPF calculation procedure's */
+ /*
+ * Second stage of SPF calculation procedure's, add leaves to the tree
+ * for stub networks.
+ */
ospf_spf_process_stubs(area, area->spf, new_table, 0);
- /* Free candidate queue. */
- //vertex_pqueue_fini(&candidate);
-
ospf_vertex_dump(__func__, area->spf, 0, 1);
- /* Free nexthop information, canonical versions of which are attached
- * the first level of router vertices attached to the root vertex, see
- * ospf_nexthop_calculation.
- */
- ospf_canonical_nexthops_free(area->spf);
/* Increment SPF Calculation Counter. */
area->spf_calculation++;
@@ -1268,75 +1310,101 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
zlog_debug("ospf_spf_calculate: Stop. %zd vertices",
mtype_stats_alloc(MTYPE_OSPF_VERTEX));
- /* Free SPF vertices, but not the list. List has ospf_vertex_free
- * as deconstructor.
- */
- list_delete_all_node(&vertex_list);
+ /* If this is a dry run then keep the SPF data in place */
+ if (!area->spf_dry_run) {
+ /*
+ * Free nexthop information, canonical versions of which are
+ * attached the first level of router vertices attached to the
+ * root vertex, see ospf_nexthop_calculation.
+ */
+ ospf_canonical_nexthops_free(area->spf);
+
+ /*
+ * Free SPF vertices, but not the list. List has
+ * ospf_vertex_free as deconstructor.
+ */
+ list_delete_all_node(&vertex_list);
+ }
}
-/* Timer for SPF calculation. */
-static int ospf_spf_calculate_timer(struct thread *thread)
+int ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
+ struct route_table *new_rtrs, bool is_dry_run,
+ bool is_root_node)
{
- struct ospf *ospf = THREAD_ARG(thread);
- struct route_table *new_table, *new_rtrs;
struct ospf_area *area;
struct listnode *node, *nnode;
- struct timeval start_time, spf_start_time;
int areas_processed = 0;
- unsigned long ia_time, prune_time, rt_time;
- unsigned long abr_time, total_spf_time, spf_time;
- char rbuf[32]; /* reason_buf */
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("SPF: Timer (SPF calculation expire)");
-
- ospf->t_spf_calc = NULL;
-
- monotime(&spf_start_time);
- /* Allocate new table tree. */
- new_table = route_table_init();
- new_rtrs = route_table_init();
-
- ospf_vl_unapprove(ospf);
/* Calculate SPF for each area. */
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
/* Do backbone last, so as to first discover intra-area paths
- * for any back-bone virtual-links
- */
+ * for any back-bone virtual-links */
if (ospf->backbone && ospf->backbone == area)
continue;
- ospf_spf_calculate(ospf, area, new_table, new_rtrs);
+ ospf_spf_calculate(area, area->router_lsa_self, new_table,
+ new_rtrs, is_dry_run, is_root_node);
areas_processed++;
}
/* SPF for backbone, if required */
if (ospf->backbone) {
- ospf_spf_calculate(ospf, ospf->backbone, new_table, new_rtrs);
+ area = ospf->backbone;
+ ospf_spf_calculate(area, area->router_lsa_self, new_table,
+ new_rtrs, is_dry_run, is_root_node);
areas_processed++;
}
+ return areas_processed;
+}
+
+/* Worker for SPF calculation scheduler. */
+static int ospf_spf_calculate_schedule_worker(struct thread *thread)
+{
+ struct ospf *ospf = THREAD_ARG(thread);
+ struct route_table *new_table, *new_rtrs;
+ struct timeval start_time, spf_start_time;
+ int areas_processed;
+ unsigned long ia_time, prune_time, rt_time;
+ unsigned long abr_time, total_spf_time, spf_time;
+ char rbuf[32]; /* reason_buf */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("SPF: Timer (SPF calculation expire)");
+
+ ospf->t_spf_calc = NULL;
+
+ ospf_vl_unapprove(ospf);
+
+ /* Execute SPF for each area including backbone, see RFC 2328 16.1. */
+ monotime(&spf_start_time);
+ new_table = route_table_init(); /* routing table */
+ new_rtrs = route_table_init(); /* ABR/ASBR routing table */
+ areas_processed = ospf_spf_calculate_areas(ospf, new_table, new_rtrs,
+ false, true);
spf_time = monotime_since(&spf_start_time, NULL);
ospf_vl_shut_unapproved(ospf);
+ /* Calculate inter-area routes, see RFC 2328 16.2. */
monotime(&start_time);
ospf_ia_routing(ospf, new_table, new_rtrs);
ia_time = monotime_since(&start_time, NULL);
+ /* Get rid of transit networks and routers we cannot reach anyway. */
monotime(&start_time);
ospf_prune_unreachable_networks(new_table);
ospf_prune_unreachable_routers(new_rtrs);
prune_time = monotime_since(&start_time, NULL);
- /* AS-external-LSA calculation should not be performed here. */
-
- /* If new Router Route is installed,
- then schedule re-calculate External routes. */
- if (1)
- ospf_ase_calculate_schedule(ospf);
+ /* Note: RFC 2328 16.3. is apparently missing. */
+ /*
+ * Calculate AS external routes, see RFC 2328 16.4.
+ * There is a dedicated routing table for external routes which is not
+ * handled here directly
+ */
+ ospf_ase_calculate_schedule(ospf);
ospf_ase_calculate_timer_add(ospf);
if (IS_DEBUG_OSPF_EVENT)
@@ -1344,22 +1412,22 @@ static int ospf_spf_calculate_timer(struct thread *thread)
"%s: ospf install new route, vrf %s id %u new_table count %lu",
__func__, ospf_vrf_id_to_name(ospf->vrf_id),
ospf->vrf_id, new_table->count);
+
/* Update routing table. */
monotime(&start_time);
ospf_route_install(ospf, new_table);
rt_time = monotime_since(&start_time, NULL);
- /* Update ABR/ASBR routing table */
- if (ospf->old_rtrs) {
- /* old_rtrs's node holds linked list of ospf_route. --kunihiro.
- */
+ /* Free old ABR/ASBR routing table */
+ if (ospf->old_rtrs)
/* ospf_route_delete (ospf->old_rtrs); */
ospf_rtrs_free(ospf->old_rtrs);
- }
+ /* Update ABR/ASBR routing table */
ospf->old_rtrs = ospf->new_rtrs;
ospf->new_rtrs = new_rtrs;
+ /* ABRs may require additional changes, see RFC 2328 16.7. */
monotime(&start_time);
if (IS_OSPF_ABR(ospf))
ospf_abr_task(ospf);
@@ -1413,8 +1481,10 @@ static int ospf_spf_calculate_timer(struct thread *thread)
return 0;
}
-/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
- set timer for SPF calc. */
+/*
+ * Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
+ * for SPF calc.
+ */
void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
{
unsigned long delay, elapsed, ht;
@@ -1446,9 +1516,10 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
/* Get SPF calculation delay time. */
if (elapsed < ht) {
- /* Got an event within the hold time of last SPF. We need to
+ /*
+ * Got an event within the hold time of last SPF. We need to
* increase the hold_multiplier, if it's not already at/past
- * maximum value, and wasn't already increased..
+ * maximum value, and wasn't already increased.
*/
if (ht < ospf->spf_max_holdtime)
ospf->spf_hold_multiplier++;
@@ -1468,6 +1539,6 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
zlog_debug("SPF: calculation timer delay = %ld msec", delay);
ospf->t_spf_calc = NULL;
- thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay,
- &ospf->t_spf_calc);
+ thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
+ delay, &ospf->t_spf_calc);
}
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
index 09a0b6f1b7..0371146420 100644
--- a/ospfd/ospf_spf.h
+++ b/ospfd/ospf_spf.h
@@ -49,15 +49,14 @@ struct vertex {
/* A nexthop taken on the root node to get to this (parent) vertex */
struct vertex_nexthop {
- struct ospf_interface *oi; /* output intf on root node */
struct in_addr router; /* router address to send to */
+ int lsa_pos; /* LSA position for resolving the interface */
};
struct vertex_parent {
- struct vertex_nexthop
- *nexthop; /* link to nexthop info for this parent */
- struct vertex *parent; /* parent vertex */
- int backlink; /* index back to parent for router-lsa's */
+ struct vertex_nexthop *nexthop; /* nexthop address for this parent */
+ struct vertex *parent; /* parent vertex */
+ int backlink; /* index back to parent for router-lsa's */
};
/* What triggered the SPF ? */
@@ -73,7 +72,18 @@ typedef enum {
} ospf_spf_reason_t;
extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
+extern void ospf_spf_calculate(struct ospf_area *area,
+ struct ospf_lsa *root_lsa,
+ struct route_table *new_table,
+ struct route_table *new_rtrs, bool is_dry_run,
+ bool is_root_node);
+extern int ospf_spf_calculate_areas(struct ospf *ospf,
+ struct route_table *new_table,
+ struct route_table *new_rtrs,
+ bool is_dry_run, bool is_root_node);
extern void ospf_rtrs_free(struct route_table *);
+extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i);
+
/* void ospf_spf_calculate_timer_add (); */
#endif /* _QUAGGA_OSPF_SPF_H */
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
index f2330d6bdd..f6a190db80 100644
--- a/ospfd/ospf_sr.c
+++ b/ospfd/ospf_sr.c
@@ -1,13 +1,14 @@
/*
* This is an implementation of Segment Routing
- * as per draft draft-ietf-ospf-segment-routing-extensions-24
+ * as per RFC 8665 - OSPF Extensions for Segment Routing
+ * and RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
*
* Module name: Segment Routing
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
*
- * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ * Copyright (C) 2016 - 2020 Orange Labs http://www.orange.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -82,6 +83,7 @@
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
@@ -218,9 +220,205 @@ static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf,
}
/*
+ * Segment Routing Local Block management functions
+ */
+
+/**
+ * It is necessary to known which label is already allocated to manage the range
+ * of SRLB. This is particular useful when an interface flap (goes up / down
+ * frequently). Here, SR will release and then allocate label for the Adjacency
+ * for each concerned interface. If we don't care, there is a risk to run out of
+ * label.
+ *
+ * For that purpose, a similar principle as already provided to manage chunk of
+ * label is proposed. But, here, the label chunk has not a fix range of 64
+ * labels that could be easily manage with a single variable of 64 bits size.
+ * So, used_mark is used as a bit wise to mark label reserved (bit set) or not
+ * (bit unset). Its size is equal to the number of label of the SRLB range round
+ * up to 64 bits.
+ *
+ * - sr__local_block_init() computes the number of 64 bits variables that are
+ * needed to manage the SRLB range and allocates this number.
+ * - ospf_sr_local_block_request_label() pick up the first available label and
+ * set corresponding bit
+ * - ospf_sr_local_block_release_label() release label by reseting the
+ * corresponding bit and set the next label to the first free position
+ */
+
+/**
+ * Initialize Segment Routing Local Block from SRDB configuration and reserve
+ * block of bits to manage label allocation.
+ *
+ * @param lower_bound The lower bound of the SRLB range
+ * @param upper_bound The upper bound of the SRLB range
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int sr_local_block_init(uint32_t lower_bound, uint32_t upper_bound)
+{
+ struct sr_local_block *srlb = &OspfSR.srlb;
+ uint32_t size;
+
+ /* Check if SRLB is not already configured */
+ if (srlb->reserved)
+ 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.
+ */
+ size = upper_bound - lower_bound + 1;
+ if (ospf_zebra_request_label_range(lower_bound, size)) {
+ srlb->reserved = false;
+ return -1;
+ }
+
+ osr_debug("SR (%s): Got new SRLB [%u/%u]", __func__, lower_bound,
+ upper_bound);
+
+ /* Initialize the SRLB */
+ srlb->start = lower_bound;
+ srlb->end = upper_bound;
+ srlb->current = 0;
+ /* Compute the needed Used Mark number and allocate them */
+ srlb->max_block = size / SRLB_BLOCK_SIZE;
+ if ((size % SRLB_BLOCK_SIZE) != 0)
+ srlb->max_block++;
+ srlb->used_mark = XCALLOC(MTYPE_OSPF_SR_PARAMS,
+ srlb->max_block * SRLB_BLOCK_SIZE);
+ srlb->reserved = true;
+
+ return 0;
+}
+
+/**
+ * Remove Segment Routing Local Block.
+ *
+ */
+static void sr_local_block_delete()
+{
+ struct sr_local_block *srlb = &OspfSR.srlb;
+
+ /* Check if SRLB is not already delete */
+ if (!srlb->reserved)
+ return;
+
+ osr_debug("SR (%s): Remove SRLB [%u/%u]", __func__, srlb->start,
+ srlb->end);
+
+ /* First release the label block */
+ ospf_zebra_release_label_range(srlb->start, srlb->end);
+
+ /* Then reset SRLB structure */
+ if (srlb->used_mark != NULL)
+ XFREE(MTYPE_OSPF_SR_PARAMS, srlb->used_mark);
+ srlb->reserved = false;
+}
+
+/**
+ * Request a label from the Segment Routing Local Block.
+ *
+ * @return First available label on success or MPLS_INVALID_LABEL if the
+ * block of labels is full
+ */
+mpls_label_t ospf_sr_local_block_request_label(void)
+{
+ struct sr_local_block *srlb = &OspfSR.srlb;
+ mpls_label_t label;
+ uint32_t index;
+ uint32_t pos;
+
+ /* Check if we ran out of available labels */
+ if (srlb->current >= srlb->end)
+ return MPLS_INVALID_LABEL;
+
+ /* Get first available label and mark it used */
+ label = srlb->current + srlb->start;
+ index = srlb->current / SRLB_BLOCK_SIZE;
+ pos = 1ULL << (srlb->current % SRLB_BLOCK_SIZE);
+ srlb->used_mark[index] |= pos;
+
+ /* Jump to the next free position */
+ srlb->current++;
+ pos = srlb->current % SRLB_BLOCK_SIZE;
+ while (srlb->current < srlb->end) {
+ if (pos == 0)
+ index++;
+ if (!((1ULL << pos) & srlb->used_mark[index]))
+ break;
+ else {
+ srlb->current++;
+ pos = srlb->current % SRLB_BLOCK_SIZE;
+ }
+ }
+
+ return label;
+}
+
+/**
+ * Release label in the Segment Routing Local Block.
+ *
+ * @param label Label to be release
+ *
+ * @return 0 on success or -1 if label falls outside SRLB
+ */
+int ospf_sr_local_block_release_label(mpls_label_t label)
+{
+ struct sr_local_block *srlb = &OspfSR.srlb;
+ uint32_t index;
+ uint32_t pos;
+
+ /* Check that label falls inside the SRLB */
+ if ((label < srlb->start) || (label > srlb->end)) {
+ flog_warn(EC_OSPF_SR_SID_OVERFLOW,
+ "%s: Returning label %u is outside SRLB [%u/%u]",
+ __func__, label, srlb->start, srlb->end);
+ return -1;
+ }
+
+ index = (label - srlb->start) / SRLB_BLOCK_SIZE;
+ pos = 1ULL << ((label - srlb->start) % SRLB_BLOCK_SIZE);
+ srlb->used_mark[index] &= ~pos;
+ /* Reset current to the first available position */
+ for (index = 0; index < srlb->max_block; index++) {
+ if (srlb->used_mark[index] != 0xFFFFFFFFFFFFFFFF) {
+ for (pos = 0; pos < SRLB_BLOCK_SIZE; pos++)
+ if (!((1ULL << pos) & srlb->used_mark[index])) {
+ srlb->current =
+ index * SRLB_BLOCK_SIZE + pos;
+ break;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
* 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)
{
@@ -231,16 +429,59 @@ 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.size;
+ srn->srgb.lower_bound = OspfSR.srgb.start;
+ srn->srlb.lower_bound = OspfSR.srlb.start;
+ srn->srlb.range_size = OspfSR.srlb.end - OspfSR.srlb.start + 1;
+ 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 SRLB & SGRB to the label manager if not already reserved.
+ * If the allocation fails, return an error to disable SR until a new
+ * SRLB and/or SRGB are successfully allocated.
+ */
+ sr_local_block_init(OspfSR.srlb.start, OspfSR.srlb.end);
+ if (!OspfSR.srgb.reserved) {
+ if (ospf_zebra_request_label_range(OspfSR.srgb.start,
+ OspfSR.srgb.size)
+ < 0) {
+ OspfSR.srgb.reserved = false;
+ return -1;
+ } else
+ OspfSR.srgb.reserved = true;
+ }
+
+ /* 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.self);
- /* 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;
+ /* 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__);
@@ -277,13 +518,33 @@ static void ospf_sr_stop(void)
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 & SRLB if active. */
+ if (OspfSR.srgb.reserved)
+ ospf_zebra_release_label_range(
+ OspfSR.srgb.start,
+ OspfSR.srgb.start + OspfSR.srgb.size - 1);
+ sr_local_block_delete();
+
+ /* Revert SRGB, SRLB and MSD to default values */
+ OspfSR.srgb.size = DEFAULT_SRGB_SIZE;
+ OspfSR.srgb.start = DEFAULT_SRGB_LABEL;
+ OspfSR.srgb.reserved = false;
+
+ OspfSR.srlb.start = DEFAULT_SRLB_LABEL;
+ OspfSR.srlb.end = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
+ OspfSR.srlb.reserved = false;
+ OspfSR.msd = 0;
+
/*
* 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;
}
/*
@@ -300,18 +561,23 @@ int ospf_sr_init(void)
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;
- /* Initialize SRGB, Algorithms and MSD TLVs */
+ /* Initialize Algorithms, SRGB, SRLB and MSD TLVs */
/* Only Algorithm SPF is supported */
OspfSR.algo[0] = SR_ALGORITHM_SPF;
for (int i = 1; i < ALGORITHM_COUNT; i++)
OspfSR.algo[i] = SR_ALGORITHM_UNSET;
- OspfSR.srgb.range_size = MPLS_DEFAULT_MAX_SRGB_SIZE;
- OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
+ OspfSR.srgb.size = DEFAULT_SRGB_SIZE;
+ OspfSR.srgb.start = DEFAULT_SRGB_LABEL;
+ OspfSR.srgb.reserved = false;
+
+ OspfSR.srlb.start = DEFAULT_SRLB_LABEL;
+ OspfSR.srlb.end = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
+ OspfSR.srlb.reserved = false;
OspfSR.msd = 0;
/* Initialize Hash table for neighbor SR nodes */
@@ -370,14 +636,17 @@ void ospf_sr_finish(void)
*/
/* Compute label from index */
-static mpls_label_t index2label(uint32_t index, struct sr_srgb srgb)
+static mpls_label_t index2label(uint32_t index, struct sr_block srgb)
{
mpls_label_t label;
label = srgb.lower_bound + index;
- if (label > (srgb.lower_bound + srgb.range_size))
+ if (label > (srgb.lower_bound + srgb.range_size)) {
+ flog_warn(EC_OSPF_SR_SID_OVERFLOW,
+ "%s: SID index %u falls outside SRGB range",
+ __func__, index);
return MPLS_INVALID_LABEL;
- else
+ } else
return label;
}
@@ -484,6 +753,45 @@ static int compute_link_nhlfe(struct sr_link *srl)
return rc;
}
+/**
+ * Compute output label for the given Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ * @param srnext Segment Routing nexthop node
+ *
+ * @return MPLS label or MPLS_INVALID_LABEL in case of error
+ */
+static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
+ const struct sr_node *srnext)
+{
+ /* Check if the nexthop SR Node is the last hop? */
+ if (srnext == srp->srn) {
+ /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
+ if (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
+ return MPLS_LABEL_IMPLICIT_NULL;
+
+ /* SR-Node requests Explicit NULL Label */
+ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
+ return MPLS_LABEL_IPV4_EXPLICIT_NULL;
+ /* Fallthrough */
+ }
+
+ /* Return SID value as MPLS label if it is an Absolute SID */
+ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG
+ | EXT_SUBTLV_PREFIX_SID_LFLG)) {
+ /*
+ * V/L SIDs have local significance, so only adjacent routers
+ * can use them (RFC8665 section #5)
+ */
+ if (srp->srn != srnext)
+ return MPLS_INVALID_LABEL;
+ return srp->sid;
+ }
+
+ /* Return MPLS label as SRGB lower bound + SID index as per RFC 8665 */
+ return (index2label(srp->sid, srnext->srgb));
+}
+
/*
* Compute NHLFE entry for Extended Prefix
*
@@ -515,7 +823,7 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
return rc;
/* Compute Input Label with self SRGB */
- srp->label_in = index2label(srp->sid, OspfSR.srgb);
+ srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
rc = 0;
for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
@@ -534,10 +842,7 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
/* And store this information for later update */
srnext->neighbor = OspfSR.self;
- if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router))
- path->srni.nexthop = NULL;
- else
- path->srni.nexthop = srnext;
+ path->srni.nexthop = srnext;
/*
* SR Node could be known, but SRGB could be not initialize
@@ -552,18 +857,8 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
srnext->srgb.range_size, srnext->srgb.lower_bound,
&srnext->adv_router);
- /*
- * Compute Output Label with Nexthop SR Node SRGB or Implicit
- * Null label if next hop is the destination and request PHP
- */
- if ((path->srni.nexthop == NULL)
- && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
- path->srni.label_out = MPLS_LABEL_IMPLICIT_NULL;
- else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
- path->srni.label_out = srp->sid;
- else
- path->srni.label_out =
- index2label(srp->sid, srnext->srgb);
+ /* Compute Output Label with Nexthop SR Node SRGB */
+ path->srni.label_out = sr_prefix_out_label(srp, srnext);
osr_debug(" |- Computed new labels in: %u out: %u",
srp->label_in, path->srni.label_out);
@@ -900,9 +1195,11 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args)
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
continue;
- /* OK. Compute new input label ... */
- srp->label_in = index2label(srp->sid, OspfSR.srgb);
- /* ... and update MPLS LFIB */
+ /* First, remove old MPLS table entries ... */
+ ospf_zebra_delete_prefix_sid(srp);
+ /* ... then compute new input label ... */
+ srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
+ /* ... and install new MPLS LFIB */
ospf_zebra_update_prefix_sid(srp);
}
}
@@ -926,7 +1223,7 @@ static void update_out_nhlfe(struct hash_bucket *bucket, void *args)
for (ALL_LIST_ELEMENTS_RO(srp->route->paths, pnode, path)) {
/* Process only SID Index for next hop without PHP */
- if ((path->srni.nexthop == NULL)
+ if ((path->srni.nexthop == srp->srn)
&& (!CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_NPFLG)))
continue;
@@ -951,8 +1248,9 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
struct tlv_header *tlvh;
struct lsa_header *lsah = lsa->data;
struct ri_sr_tlv_sid_label_range *ri_srgb = NULL;
+ struct ri_sr_tlv_sid_label_range *ri_srlb = NULL;
struct ri_sr_tlv_sr_algorithm *algo = NULL;
- struct sr_srgb srgb;
+ struct sr_block srgb;
uint16_t length = 0, sum = 0;
uint8_t msd = 0;
@@ -988,10 +1286,14 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
sum += TLV_SIZE(tlvh);
break;
- case RI_SR_TLV_SID_LABEL_RANGE:
+ case RI_SR_TLV_SRGB_LABEL_RANGE:
ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
sum += TLV_SIZE(tlvh);
break;
+ case RI_SR_TLV_SRLB_LABEL_RANGE:
+ ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh;
+ sum += TLV_SIZE(tlvh);
+ break;
case RI_SR_TLV_NODE_MSD:
msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
sum += TLV_SIZE(tlvh);
@@ -1048,9 +1350,12 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
}
/* update LSA ID */
srn->instance = ntohl(lsah->id.s_addr);
+ /* Copy SRGB */
+ srn->srgb.range_size = srgb.range_size;
+ srn->srgb.lower_bound = srgb.lower_bound;
}
- /* Set Algorithm */
+ /* Update Algorithm, SRLB and MSD if present */
if (algo != NULL) {
int i;
for (i = 0; i < ntohs(algo->header.length); i++)
@@ -1060,8 +1365,21 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
} else {
srn->algo[0] = SR_ALGORITHM_SPF;
}
-
srn->msd = msd;
+ if (ri_srlb != NULL) {
+ srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size));
+ srn->srlb.lower_bound = GET_LABEL(ntohl(ri_srlb->lower.value));
+ }
+
+ osr_debug(" |- Update SR-Node[%pI4], SRGB[%u/%u], SRLB[%u/%u], Algo[%u], MSD[%u]",
+ &srn->adv_router, srn->srgb.lower_bound, srn->srgb.range_size,
+ srn->srlb.lower_bound, srn->srlb.range_size, srn->algo[0],
+ srn->msd);
+
+ /* Check if SRGB has changed */
+ if ((srn->srgb.range_size == srgb.range_size)
+ && (srn->srgb.lower_bound == srgb.lower_bound))
+ return;
/* Copy SRGB */
srn->srgb.range_size = srgb.range_size;
@@ -1453,18 +1771,6 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
}
}
-/* Get Label for Extended Link SID */
-/* TODO: To be replace by Zebra Label Manager */
-uint32_t get_ext_link_label_value(void)
-{
- static uint32_t label = ADJ_SID_MIN - 1;
-
- if (label < ADJ_SID_MAX)
- label += 1;
-
- return label;
-}
-
/*
* Update Prefix SID. Call by ospf_ext_pref_ism_change to
* complete initial CLI command at startup.
@@ -1507,9 +1813,10 @@ void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p)
" |- Update Node SID %pFX - %u for self SR Node",
(struct prefix *)&srp->prefv4, srp->sid);
- /* Install NHLFE if NO-PHP is requested */
- if (CHECK_FLAG(srp->flags,
- EXT_SUBTLV_PREFIX_SID_NPFLG)) {
+ /* Install SID if NO-PHP is set and not EXPLICIT-NULL */
+ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
+ && !CHECK_FLAG(srp->flags,
+ EXT_SUBTLV_PREFIX_SID_EFLG)) {
srp->label_in = index2label(srp->sid,
OspfSR.self->srgb);
srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
@@ -1611,17 +1918,23 @@ void ospf_sr_config_write_router(struct vty *vty)
{
struct listnode *node;
struct sr_prefix *srp;
+ uint32_t upper;
- if (OspfSR.enabled) {
+ if (OspfSR.status == SR_UP) {
vty_out(vty, " segment-routing on\n");
- if ((OspfSR.srgb.lower_bound != MPLS_DEFAULT_MIN_SRGB_LABEL)
- || (OspfSR.srgb.range_size != MPLS_DEFAULT_MAX_SRGB_SIZE)) {
+ upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
+ if ((OspfSR.srgb.start != DEFAULT_SRGB_LABEL)
+ || (OspfSR.srgb.size != DEFAULT_SRGB_SIZE))
vty_out(vty, " segment-routing global-block %u %u\n",
- OspfSR.srgb.lower_bound,
- OspfSR.srgb.lower_bound + OspfSR.srgb.range_size
- - 1);
- }
+ OspfSR.srgb.start, upper);
+
+ upper = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
+ if ((OspfSR.srlb.start != DEFAULT_SRLB_LABEL)
+ || (OspfSR.srlb.end != upper))
+ vty_out(vty, " segment-routing local-block %u %u\n",
+ OspfSR.srlb.start, OspfSR.srlb.end);
+
if (OspfSR.msd != 0)
vty_out(vty, " segment-routing node-msd %u\n",
OspfSR.msd);
@@ -1630,13 +1943,19 @@ void ospf_sr_config_write_router(struct vty *vty)
for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node,
srp)) {
vty_out(vty,
- " segment-routing prefix %s/%u index %u%s\n",
+ " segment-routing prefix %s/%u "
+ "index %u",
inet_ntoa(srp->prefv4.prefix),
- srp->prefv4.prefixlen, srp->sid,
- CHECK_FLAG(srp->flags,
- EXT_SUBTLV_PREFIX_SID_NPFLG)
- ? " no-php-flag"
- : "");
+ srp->prefv4.prefixlen, srp->sid);
+ if (CHECK_FLAG(srp->flags,
+ EXT_SUBTLV_PREFIX_SID_EFLG))
+ vty_out(vty, " explicit-null\n");
+ else if (CHECK_FLAG(
+ srp->flags,
+ EXT_SUBTLV_PREFIX_SID_NPFLG))
+ vty_out(vty, " no-php-flag\n");
+ else
+ vty_out(vty, "\n");
}
}
}
@@ -1651,7 +1970,7 @@ DEFUN(ospf_sr_enable,
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
- if (OspfSR.enabled)
+ if (OspfSR.status != SR_OFF)
return CMD_SUCCESS;
if (ospf->vrf_id != VRF_DEFAULT) {
@@ -1663,19 +1982,9 @@ DEFUN(ospf_sr_enable,
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;
}
@@ -1687,7 +1996,7 @@ DEFUN (no_ospf_sr_enable,
"Disable Segment Routing\n")
{
- if (!OspfSR.enabled)
+ if (OspfSR.status == SR_OFF)
return CMD_SUCCESS;
osr_debug("SR: Segment Routing: ON -> OFF");
@@ -1696,7 +2005,7 @@ DEFUN (no_ospf_sr_enable,
ospf_ext_update_sr(false);
/* then, disable Router Information SR parameters */
- ospf_router_info_update_sr(false, OspfSR.srgb, OspfSR.msd);
+ ospf_router_info_update_sr(false, OspfSR.self);
/* Finally, stop Segment Routing */
ospf_sr_stop();
@@ -1706,7 +2015,7 @@ DEFUN (no_ospf_sr_enable,
static int ospf_sr_enabled(struct vty *vty)
{
- if (OspfSR.enabled)
+ if (OspfSR.status != SR_OFF)
return 1;
if (vty)
@@ -1715,13 +2024,74 @@ static int ospf_sr_enabled(struct vty *vty)
return 0;
}
-DEFUN (sr_sid_label_range,
- sr_sid_label_range_cmd,
- "segment-routing global-block (0-1048575) (0-1048575)",
+/**
+ * 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.size == size) && (OspfSR.srgb.start == lower))
+ return 0;
+
+ /* Release old SRGB if active. */
+ if (OspfSR.srgb.reserved) {
+ ospf_zebra_release_label_range(
+ OspfSR.srgb.start,
+ OspfSR.srgb.start + OspfSR.srgb.size - 1);
+ OspfSR.srgb.reserved = false;
+ }
+
+ /* Set new SRGB values */
+ OspfSR.srgb.size = size;
+ OspfSR.srgb.start = 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.start,
+ OspfSR.srgb.size) < 0) {
+ OspfSR.srgb.reserved = false;
+ ospf_sr_stop();
+ return -1;
+ } else
+ OspfSR.srgb.reserved = true;
+
+ osr_debug("SR(%s): Got new SRGB [%u/%u]", __func__, OspfSR.srgb.start,
+ OspfSR.srgb.start + OspfSR.srgb.size - 1);
+
+ /* SRGB is reserved, set Router Information parameters */
+ ospf_router_info_update_sr(true, OspfSR.self);
+
+ /* and update NHLFE entries */
+ hash_iterate(OspfSR.neighbors,
+ (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
+ NULL);
+
+ return 0;
+}
+
+DEFUN (sr_global_label_range,
+ sr_global_label_range_cmd,
+ "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;
@@ -1737,77 +2107,154 @@ DEFUN (sr_sid_label_range,
upper = strtoul(argv[idx_up]->arg, NULL, 10);
size = upper - lower + 1;
- if (size > MPLS_DEFAULT_MAX_SRGB_SIZE || size <= 0) {
+ /* Validate SRGB against SRLB */
+ if (!((upper < OspfSR.srlb.start) || (lower > OspfSR.srlb.end))) {
vty_out(vty,
- "Range size cannot be less than 0 or more than %u\n",
- MPLS_DEFAULT_MAX_SRGB_SIZE);
+ "New SR Global Block (%u/%u) conflict with Local Block (%u/%u)\n",
+ lower, upper, OspfSR.srlb.end, OspfSR.srlb.start);
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;
- }
+ else
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_sr_global_label_range,
+ no_sr_global_label_range_cmd,
+ "no segment-routing global-block [(16-1048575) (16-1048575)]",
+ NO_STR
+ SR_STR
+ "Segment Routing Global Block label range\n"
+ "Lower-bound range in decimal (16-1048575)\n"
+ "Upper-bound range in decimal (16-1048575)\n")
+{
- if (upper < MPLS_DEFAULT_MIN_SRGB_LABEL) {
- vty_out(vty, "Upper-bound cannot be lower than %u\n",
- MPLS_DEFAULT_MIN_SRGB_LABEL);
+ if (!ospf_sr_enabled(vty))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Validate SRGB against SRLB */
+ uint32_t upper = DEFAULT_SRGB_LABEL + DEFAULT_SRGB_SIZE - 1;
+ if (!((upper < OspfSR.srlb.start)
+ || (DEFAULT_SRGB_LABEL > OspfSR.srlb.end))) {
+ vty_out(vty,
+ "New SR Global Block (%u/%u) conflict with Local Block (%u/%u)\n",
+ DEFAULT_SRGB_LABEL, upper, OspfSR.srlb.end,
+ OspfSR.srlb.start);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (update_srgb(DEFAULT_SRGB_LABEL, DEFAULT_SRGB_SIZE) < 0)
+ return CMD_WARNING_CONFIG_FAILED;
+ else
+ return CMD_SUCCESS;
+}
+
+DEFUN (sr_local_label_range,
+ sr_local_label_range_cmd,
+ "segment-routing local-block (16-1048575) (16-1048575)",
+ SR_STR
+ "Segment Routing Local Block label range\n"
+ "Lower-bound range in decimal (16-1048575)\n"
+ "Upper-bound range in decimal (16-1048575)\n")
+{
+ uint32_t upper;
+ uint32_t lower;
+ uint32_t srgb_upper;
+ int idx_low = 2;
+ int idx_up = 3;
+
+ if (!ospf_sr_enabled(vty))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /* Get lower and upper bound */
+ lower = strtoul(argv[idx_low]->arg, NULL, 10);
+ upper = strtoul(argv[idx_up]->arg, NULL, 10);
+
/* Check if values have changed */
- if ((OspfSR.srgb.range_size == size)
- && (OspfSR.srgb.lower_bound == lower))
+ if ((OspfSR.srlb.start == lower)
+ && (OspfSR.srlb.end == upper))
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;
+ /* Validate SRLB against SRGB */
+ srgb_upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
+ if (!((upper < OspfSR.srgb.start) || (lower > srgb_upper))) {
+ vty_out(vty,
+ "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n",
+ lower, upper, OspfSR.srgb.start, srgb_upper);
+ return CMD_WARNING_CONFIG_FAILED;
}
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+ /* Remove old SRLB */
+ sr_local_block_delete();
- /* Update NHLFE entries */
- hash_iterate(OspfSR.neighbors,
- (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
- NULL);
+ /* Try to reserve the new block from the Label Manger. If the allocation
+ * fails, disable SR until a new SRLB is successfully allocated.
+ */
+ if (sr_local_block_init(lower, upper) != 0) {
+ ospf_sr_stop();
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* SRLB is reserved, Update Self SR-Node and Router Information LSA */
+ OspfSR.self->srlb.lower_bound = lower;
+ OspfSR.self->srlb.range_size = upper - lower + 1;
+ ospf_router_info_update_sr(true, OspfSR.self);
+
+ /* and update (LAN)-Adjacency SID */
+ ospf_ext_link_srlb_update();
return CMD_SUCCESS;
}
-DEFUN (no_sr_sid_label_range,
- no_sr_sid_label_range_cmd,
- "no segment-routing global-block [(0-1048575) (0-1048575)]",
+DEFUN (no_sr_local_label_range,
+ no_sr_local_label_range_cmd,
+ "no segment-routing local-block [(16-1048575) (16-1048575)]",
NO_STR
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")
+ "Segment Routing Local Block label range\n"
+ "Lower-bound range in decimal (16-1048575)\n"
+ "Upper-bound range in decimal (16-1048575)\n")
{
+ uint32_t upper;
+ uint32_t srgb_end;
+
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;
+ /* First, remove old SRLB */
+ sr_local_block_delete();
+
+ /* Validate SRLB against SRGB */
+ srgb_end = OspfSR.srgb.start + OspfSR.srgb.size - 1;
+ upper = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
+ if (!((upper < OspfSR.srgb.start) || (DEFAULT_SRLB_LABEL > srgb_end))) {
+ vty_out(vty,
+ "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n",
+ DEFAULT_SRLB_LABEL, upper, OspfSR.srgb.start, srgb_end);
+ return CMD_WARNING_CONFIG_FAILED;
}
- /* Set Router Information SR parameters */
- ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+ /* Then, initialize SRLB with default value and try to reserve the new
+ * block from the Label Manger. If the allocation fails, disable SR
+ * until a new SRLB is successfully allocated.
+ */
+ if (sr_local_block_init(DEFAULT_SRLB_LABEL, upper) != 0) {
+ ospf_sr_stop();
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- /* Update NHLFE entries */
- hash_iterate(OspfSR.neighbors,
- (void (*)(struct hash_bucket *, void *))update_in_nhlfe,
- NULL);
+ /* SRLB is reserved, Update Self SR-Node and Router Information LSA */
+ if (OspfSR.self != NULL) {
+ OspfSR.self->srlb.lower_bound = DEFAULT_SRLB_LABEL;
+ OspfSR.self->srlb.range_size = DEFAULT_SRLB_SIZE;
+ }
+ ospf_router_info_update_sr(true, OspfSR.self);
+
+ /* and update (LAN)-Adjacency SID */
+ ospf_ext_link_srlb_update();
return CMD_SUCCESS;
}
@@ -1843,8 +2290,9 @@ 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.self);
return CMD_SUCCESS;
}
@@ -1866,27 +2314,29 @@ DEFUN (no_sr_node_msd,
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.self);
return CMD_SUCCESS;
}
DEFUN (sr_prefix_sid,
sr_prefix_sid_cmd,
- "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]",
+ "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
SR_STR
"Prefix SID\n"
"IPv4 Prefix as A.B.C.D/M\n"
"SID index for this prefix in decimal (0-65535)\n"
"Index value inside SRGB (lower_bound < index < upper_bound)\n"
- "Don't request Penultimate Hop Popping (PHP)\n")
+ "Don't request Penultimate Hop Popping (PHP)\n"
+ "Upstream neighbor must replace prefix-sid with explicit null label\n")
{
int idx = 0;
struct prefix p;
uint32_t index;
struct listnode *node;
- struct sr_prefix *srp, *new;
+ struct sr_prefix *srp, *new = NULL;
struct interface *ifp;
if (!ospf_sr_enabled(vty))
@@ -1902,33 +2352,48 @@ DEFUN (sr_prefix_sid,
/* Get & verify index value */
argv_find(argv, argc, "(0-65535)", &idx);
index = strtoul(argv[idx]->arg, NULL, 10);
- if (index > OspfSR.srgb.range_size - 1) {
+ if (index > OspfSR.srgb.size - 1) {
vty_out(vty, "Index %u must be lower than range size %u\n",
- index, OspfSR.srgb.range_size);
+ index, OspfSR.srgb.size);
return CMD_WARNING_CONFIG_FAILED;
}
- /* check that the index is not already used */
+ /* Search for an existing Prefix-SID */
for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
if (srp->sid == index) {
- vty_out(vty, "Index %u is already used\n", index);
- return CMD_WARNING_CONFIG_FAILED;
+ if (prefix_same((struct prefix *)&srp->prefv4, &p)) {
+ new = srp;
+ break;
+ } else {
+ vty_out(vty, "Index %u is already used\n",
+ index);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
}
/* Create new Extended Prefix to SRDB if not found */
- new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
- IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4);
- new->prefv4.prefixlen = p.prefixlen;
- new->prefv4.family = p.family;
- new->sid = index;
- new->type = LOCAL_SID;
+ if (new == NULL) {
+ new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
+ IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4);
+ new->prefv4.prefixlen = p.prefixlen;
+ new->prefv4.family = p.family;
+ new->sid = index;
+ new->type = LOCAL_SID;
+ }
+
/* Set NO PHP flag if present and compute NHLFE */
if (argv_find(argv, argc, "no-php-flag", &idx)) {
SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
+ UNSET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG);
new->label_in = index2label(new->sid, OspfSR.self->srgb);
new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
}
+ /* Set EXPLICIT NULL flag is present */
+ if (argv_find(argv, argc, "explicit-null", &idx)) {
+ SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
+ SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG);
+ }
osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
(struct prefix *)&new->prefv4);
@@ -1956,25 +2421,19 @@ DEFUN (sr_prefix_sid,
}
new->nhlfe.ifindex = ifp->ifindex;
- /* Search if this prefix already exist */
- for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
- if ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
- && srp->prefv4.prefixlen == p.prefixlen))
- break;
- else
- srp = NULL;
- }
-
- /* Update or Add this new SR Prefix */
- if (srp) {
- listnode_delete(OspfSR.self->ext_prefix, srp);
- listnode_add(OspfSR.self->ext_prefix, new);
- } else {
+ /* Add this new SR Prefix if not already found */
+ if (srp != new)
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 and a valid input label set */
+ if (OspfSR.status == SR_UP) {
+ if (CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
+ && !CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
+ 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) {
@@ -1988,14 +2447,15 @@ DEFUN (sr_prefix_sid,
DEFUN (no_sr_prefix_sid,
no_sr_prefix_sid_cmd,
- "no segment-routing prefix A.B.C.D/M [index (0-65535) no-php-flag]",
+ "no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
NO_STR
SR_STR
"Prefix SID\n"
"IPv4 Prefix as A.B.C.D/M\n"
"SID index for this prefix in decimal (0-65535)\n"
"Index value inside SRGB (lower_bound < index < upper_bound)\n"
- "Don't request Penultimate Hop Popping (PHP)\n")
+ "Don't request Penultimate Hop Popping (PHP)\n"
+ "Upstream neighbor must replace prefix-sid with explicit null label\n")
{
int idx = 0;
struct prefix p;
@@ -2008,6 +2468,9 @@ DEFUN (no_sr_prefix_sid,
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);
@@ -2047,8 +2510,9 @@ DEFUN (no_sr_prefix_sid,
osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
(struct prefix *)&srp->prefv4, srp->sid);
- /* Delete NHLFE if NO-PHP is set */
- if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
+ /* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
+ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
+ && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
ospf_zebra_delete_prefix_sid(srp);
/* OK, all is clean, remove SRP from SRDB */
@@ -2070,7 +2534,10 @@ static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
snprintf(buf, size, "Pop(%u)", label_in);
break;
case MPLS_LABEL_IPV4_EXPLICIT_NULL:
- snprintf(buf, size, "Swap(%u, null)", label_in);
+ if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
+ snprintf(buf, size, "no-op.");
+ else
+ snprintf(buf, size, "Swap(%u, null)", label_in);
break;
case MPLS_INVALID_LABEL:
snprintf(buf, size, "no-op.");
@@ -2181,6 +2648,7 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
char pref[19];
char sid[22];
char op[32];
+ uint32_t upper;
json_object *json_node = NULL, *json_algo, *json_obj;
json_object *json_prefix = NULL, *json_link = NULL;
@@ -2198,6 +2666,10 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
srn->srgb.range_size);
json_object_int_add(json_node, "srgbLabel",
srn->srgb.lower_bound);
+ json_object_int_add(json_node, "srlbSize",
+ srn->srlb.range_size);
+ json_object_int_add(json_node, "srlbLabel",
+ srn->srlb.lower_bound);
json_algo = json_object_new_array();
json_object_object_add(json_node, "algorithms", json_algo);
for (int i = 0; i < ALGORITHM_COUNT; i++) {
@@ -2217,9 +2689,13 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
json_object_int_add(json_node, "nodeMsd", srn->msd);
} else {
sbuf_push(&sbuf, 0, "SR-Node: %s", inet_ntoa(srn->adv_router));
- sbuf_push(&sbuf, 0, "\tSRGB (Size/Label): %u/%u",
- srn->srgb.range_size, srn->srgb.lower_bound);
- sbuf_push(&sbuf, 0, "\tAlgorithm(s): %s",
+ upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
+ sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
+ srn->srgb.lower_bound, upper);
+ upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
+ sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
+ srn->srlb.lower_bound, upper);
+ sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
for (int i = 1; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET)
@@ -2352,7 +2828,7 @@ DEFUN (show_ip_opsf_srdb,
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;
}
@@ -2423,8 +2899,10 @@ void ospf_sr_register_vty(void)
install_element(OSPF_NODE, &ospf_sr_enable_cmd);
install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
- install_element(OSPF_NODE, &sr_sid_label_range_cmd);
- install_element(OSPF_NODE, &no_sr_sid_label_range_cmd);
+ install_element(OSPF_NODE, &sr_global_label_range_cmd);
+ install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
+ install_element(OSPF_NODE, &sr_local_label_range_cmd);
+ install_element(OSPF_NODE, &no_sr_local_label_range_cmd);
install_element(OSPF_NODE, &sr_node_msd_cmd);
install_element(OSPF_NODE, &no_sr_node_msd_cmd);
install_element(OSPF_NODE, &sr_prefix_sid_cmd);
diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h
index 3621ea53de..c54d2dcc3c 100644
--- a/ospfd/ospf_sr.h
+++ b/ospfd/ospf_sr.h
@@ -1,13 +1,14 @@
/*
* This is an implementation of Segment Routing
- * as per draft draft-ietf-ospf-segment-routing-extensions-24
+ * as per RFC 8665 - OSPF Extensions for Segment Routing
+ * and RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
*
* Module name: Segment Routing header definitions
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
*
- * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ * Copyright (C) 2016 - 2020 Orange Labs http://www.orange.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -37,13 +38,9 @@
#define SET_LABEL(label) ((label << 8) & SET_LABEL_MASK)
#define GET_LABEL(label) ((label >> 8) & GET_LABEL_MASK)
-/* Label range for Adj-SID attribution purpose. Start just right after SRGB */
-#define ADJ_SID_MIN MPLS_DEFAULT_MAX_SRGB_LABEL
-#define ADJ_SID_MAX (MPLS_DEFAULT_MAX_SRGB_LABEL + 1000)
-
#define OSPF_SR_DEFAULT_METRIC 1
-/* Segment Routing TLVs as per draft-ietf-ospf-segment-routing-extensions-19 */
+/* Segment Routing TLVs as per RFC 8665 */
/* Segment ID could be a Label (3 bytes) or an Index (4 bytes) */
#define SID_LABEL 3
@@ -88,8 +85,9 @@ struct ri_sr_tlv_sr_algorithm {
uint8_t value[ALGORITHM_COUNT];
};
-/* RI SID/Label Range TLV - section 3.2 */
-#define RI_SR_TLV_SID_LABEL_RANGE 9
+/* RI SID/Label Range TLV used for SRGB & SRLB - section 3.2 & 3.3 */
+#define RI_SR_TLV_SRGB_LABEL_RANGE 9
+#define RI_SR_TLV_SRLB_LABEL_RANGE 14
struct ri_sr_tlv_sid_label_range {
struct tlv_header header;
/* Only 24 upper most bits are significant */
@@ -99,7 +97,7 @@ struct ri_sr_tlv_sid_label_range {
struct subtlv_sid_label lower;
};
-/* RI Node/MSD TLV as per draft-ietf-ospf-segment-routing-msd-05 */
+/* RI Node/MSD TLV as per RFC 8476 */
#define RI_SR_TLV_NODE_MSD 12
struct ri_sr_tlv_node_msd {
struct tlv_header header;
@@ -183,20 +181,48 @@ struct ext_subtlv_lan_adj_sid {
* Following section define structure used to manage Segment Routing
* information and TLVs / SubTLVs
*/
+/* Default min and size of SR Global Block label range */
+#define DEFAULT_SRGB_LABEL 16000
+#define DEFAULT_SRGB_SIZE 8000
+
+/* Default min and size of SR Local Block label range */
+#define DEFAULT_SRLB_LABEL 15000
+#define DEFAULT_SRLB_SIZE 1000
-/* Structure aggregating SRGB info retrieved from an lsa */
-struct sr_srgb {
+/* Structure aggregating SR Range Block info retrieved from an lsa */
+struct sr_block {
uint32_t range_size;
uint32_t lower_bound;
};
+/* Segment Routing Global Block allocation */
+struct sr_global_block {
+ bool reserved;
+ uint32_t start;
+ uint32_t size;
+};
+
+/* Segment Routing Local Block allocation */
+struct sr_local_block {
+ bool reserved;
+ uint32_t start;
+ uint32_t end;
+ uint32_t current;
+ uint32_t max_block;
+ uint64_t *used_mark;
+};
+#define SRLB_BLOCK_SIZE 64
+
/* SID type to make difference between loopback interfaces and others */
enum sid_type { PREF_SID, LOCAL_SID, ADJ_SID, LAN_ADJ_SID };
+/* Status of Segment Routing: Off (Disable), On (Enable), (Up) Started */
+enum sr_status { SR_OFF, SR_ON, SR_UP, SR_DOWN };
+
/* Structure aggregating all OSPF Segment Routing information for the node */
struct ospf_sr_db {
- /* Status of Segment Routing: enable or disable */
- bool enabled;
+ /* Status of Segment Routing */
+ enum sr_status status;
/* Flooding Scope: Area = 10 or AS = 11 */
uint8_t scope;
@@ -218,9 +244,16 @@ struct ospf_sr_db {
* Segment Routing Global Block i.e. label range
* Only one range supported in this code
*/
- struct sr_srgb srgb;
+ struct sr_global_block srgb;
+
+ /* Segment Routing Local Block */
+ struct sr_local_block srlb;
+
/* Maximum SID Depth supported by the node */
uint8_t msd;
+
+ /* Thread timer to start Label Manager */
+ struct thread *t_start_lm;
};
/* Structure aggregating all received SR info from LSAs by node */
@@ -230,9 +263,9 @@ struct sr_node {
uint32_t instance;
uint8_t algo[ALGORITHM_COUNT]; /* Algorithms supported by the node */
- /* Segment Routing Global Block i.e. label range */
- struct sr_srgb srgb;
- uint8_t msd; /* Maximum SID Depth */
+ struct sr_block srgb; /* Segment Routing Global Block */
+ struct sr_block srlb; /* Segment Routing Local Block */
+ uint8_t msd; /* Maximum SID Depth */
/* List of Prefix & Link advertise by this node */
struct list *ext_prefix; /* For Node SID */
@@ -242,7 +275,6 @@ struct sr_node {
struct sr_node *neighbor;
};
-
/* Segment Routing - NHLFE info: support IPv4 Only */
struct sr_nhlfe {
struct in_addr nexthop;
@@ -309,6 +341,9 @@ struct sr_prefix {
extern int ospf_sr_init(void);
extern void ospf_sr_term(void);
extern void ospf_sr_finish(void);
+/* Segment Routing label allocation functions */
+extern mpls_label_t ospf_sr_local_block_request_label(void);
+extern int ospf_sr_local_block_release_label(mpls_label_t label);
/* Segment Routing LSA update & delete functions */
extern void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa);
extern void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa);
@@ -321,7 +356,6 @@ struct ext_itf;
extern void ospf_sr_ext_itf_add(struct ext_itf *exti);
extern void ospf_sr_ext_itf_delete(struct ext_itf *exti);
/* Segment Routing configuration functions */
-extern uint32_t get_ext_link_label_value(void);
extern void ospf_sr_config_write_router(struct vty *vty);
extern void ospf_sr_update_local_prefix(struct interface *ifp,
struct prefix *p);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 2b8769a4a8..eb125394b8 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -59,6 +59,8 @@ DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments")
/* 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;
@@ -1713,6 +1715,109 @@ void ospf_zebra_vrf_deregister(struct ospf *ospf)
}
}
+/* 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 */
@@ -1736,6 +1841,20 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
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);
diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h
index 6a79f39fa4..bdc8af0402 100644
--- a/ospfd/ospf_zebra.h
+++ b/ospfd/ospf_zebra.h
@@ -102,4 +102,8 @@ int ospf_external_info_apply_default_routemap(struct ospf *ospf,
extern void ospf_zebra_send_arp(const struct interface *ifp,
const struct prefix *p);
+bool ospf_zebra_label_manager_ready(void);
+int ospf_zebra_label_manager_connect(void);
+int ospf_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
+int ospf_zebra_release_label_range(uint32_t start, uint32_t end);
#endif /* _ZEBRA_OSPF_ZEBRA_H */
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 230c10e44f..8a1469469f 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -414,6 +414,10 @@ struct ospf_area {
/* Shortest Path Tree. */
struct vertex *spf;
+ bool spf_dry_run; /* flag for checking if the SPF calculation is
+ intended for the local RIB */
+ bool spf_root_node; /* flag for checking if the calculating node is the
+ root node of the SPF tree */
/* Threads. */
struct thread *t_stub_router; /* Stub-router timer */
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index f6a892df42..0979622eb3 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -1387,7 +1387,7 @@ static void bgp_startup(void)
master = thread_master_create(NULL);
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
bgp_option_set(BGP_OPT_NO_LISTEN);
vrf_init(NULL, NULL, NULL, NULL, NULL);
diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c
index 68ed16d513..7f15996daa 100644
--- a/tests/helpers/c/main.c
+++ b/tests/helpers/c/main.c
@@ -156,7 +156,7 @@ int main(int argc, char **argv)
vty_init(master, false);
lib_cmd_init();
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
/* OSPF vty inits. */
test_vty_init();
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index 3cade4a2c9..44cc6efe84 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -80,7 +80,7 @@ int main(int argc, char **argv)
vty_init(master, false);
lib_cmd_init();
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
test_init(argc, argv);
diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c
index 2b345c91e8..cb512211a4 100644
--- a/tests/lib/cli/test_commands.c
+++ b/tests/lib/cli/test_commands.c
@@ -209,7 +209,7 @@ static void test_init(void)
cmd_init(1);
yang_init(true);
- nb_init(master, NULL, 0);
+ nb_init(master, NULL, 0, false);
install_node(&bgp_node);
install_node(&rip_node);
diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c
index 202a321e1a..b5f257fa2f 100644
--- a/tests/lib/northbound/test_oper_data.c
+++ b/tests/lib/northbound/test_oper_data.c
@@ -400,7 +400,7 @@ int main(int argc, char **argv)
vty_init(master, false);
lib_cmd_init();
yang_init(true);
- nb_init(master, modules, array_size(modules));
+ nb_init(master, modules, array_size(modules), false);
/* Create artificial data. */
create_data(num_vrfs, num_interfaces, num_routes);
diff --git a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
index 0416bd6ce2..952a26ed10 100644
--- a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
@@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
- "srgbSize":20000,
- "srgbLabel":8000,
+ "srgbSize":8000,
+ "srgbLabel":16000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@@ -34,6 +36,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@@ -47,12 +51,12 @@
"inputLabel":20400,
"prefixRoute":[
{
- "outputLabel":8400,
+ "outputLabel":16400,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
- "outputLabel":8400,
+ "outputLabel":16400,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
}
@@ -64,8 +68,14 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
@@ -73,12 +83,12 @@
"inputLabel":20300,
"prefixRoute":[
{
- "outputLabel":8300,
+ "outputLabel":16300,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
- "outputLabel":8300,
+ "outputLabel":16300,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
}
@@ -90,6 +100,8 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@@ -100,10 +112,10 @@
{
"prefix":"10.0.255.1\/32",
"sid":100,
- "inputLabel":20100,
+ "inputLabel":0,
"prefixRoute":[
{
- "outputLabel":3,
+ "outputLabel":0,
"interface":"lo",
"nexthop":"10.0.255.1"
}
diff --git a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
index 292d4e6367..73a272786c 100644
--- a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
@@ -1,3 +1,4 @@
+debug ospf sr
!
interface lo
ip ospf area 0.0.0.0
@@ -17,6 +18,6 @@ router ospf
segment-routing on
segment-routing node-msd 16
segment-routing global-block 20000 29999
- segment-routing prefix 10.0.255.1/32 index 100 no-php-flag
+ segment-routing prefix 10.0.255.1/32 index 100 explicit-null
!
diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
index dd42e326ce..6c87596acb 100644
--- a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
@@ -1,20 +1,5 @@
[
{
- "inLabel":20100,
- "installed":true,
- "nexthops":[
- {
- "type":"SR (OSPF)",
- "outLabel":3,
- "outLabelStack":[
- 3
- ],
- "distance":150,
- "installed":true
- }
- ]
- },
- {
"inLabel":20200,
"installed":true,
"nexthops":[
@@ -43,20 +28,13 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8300,
+ "outLabel":16300,
"outLabelStack":[
- 8300
+ 16300
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
- },
- {
- "type":"SR (OSPF)",
- "outLabel":8300,
- "distance":150,
- "installed":true,
- "nexthop":"10.0.0.2"
}
]
},
@@ -66,20 +44,13 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8400,
+ "outLabel":16400,
"outLabelStack":[
- 8400
+ 16400
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
- },
- {
- "type":"SR (OSPF)",
- "outLabel":8400,
- "distance":150,
- "installed":true,
- "nexthop":"10.0.0.2"
}
]
},
diff --git a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
index eb202b82cd..1de780d84e 100644
--- a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
@@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
- "srgbSize":20000,
- "srgbLabel":8000,
+ "srgbSize":8000,
+ "srgbLabel":16000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@@ -95,13 +97,19 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
- "inputLabel":8400,
+ "inputLabel":16400,
"prefixRoute":[
{
"outputLabel":10400,
@@ -116,13 +124,19 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
- "inputLabel":8300,
+ "inputLabel":16300,
"prefixRoute":[
{
"outputLabel":3,
@@ -137,21 +151,27 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
- "inputLabel":8100,
+ "inputLabel":16100,
"prefixRoute":[
{
- "outputLabel":20100,
+ "outputLabel":0,
"interface":"r2-eth0",
"nexthop":"10.0.0.1"
},
{
- "outputLabel":20100,
+ "outputLabel":0,
"interface":"r2-eth1",
"nexthop":"10.0.1.1"
}
diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
index f3462e239e..a885e88fc5 100644
--- a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
@@ -1,13 +1,13 @@
[
{
- "inLabel":8100,
+ "inLabel":16100,
"installed":true,
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":20100,
+ "outLabel":0,
"outLabelStack":[
- 20100
+ 0
],
"distance":150,
"installed":true,
@@ -15,7 +15,7 @@
},
{
"type":"SR (OSPF)",
- "outLabel":20100,
+ "outLabel":0,
"distance":150,
"installed":true,
"nexthop":"10.0.0.1"
@@ -23,7 +23,7 @@
]
},
{
- "inLabel":8300,
+ "inLabel":16300,
"installed":true,
"nexthops":[
{
@@ -39,7 +39,7 @@
]
},
{
- "inLabel":8400,
+ "inLabel":16400,
"installed":true,
"nexthops":[
{
diff --git a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
index b36fe674ad..e7371ff593 100644
--- a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
@@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
- "srgbSize":20000,
- "srgbLabel":8000,
+ "srgbSize":8000,
+ "srgbLabel":16000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@@ -29,6 +31,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@@ -42,7 +46,7 @@
"inputLabel":10400,
"prefixRoute":[
{
- "outputLabel":8400,
+ "outputLabel":16400,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
@@ -54,6 +58,8 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@@ -97,6 +103,8 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@@ -110,7 +118,7 @@
"inputLabel":10100,
"prefixRoute":[
{
- "outputLabel":8100,
+ "outputLabel":16100,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
diff --git a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
index cf274bed2e..38d525f34f 100644
--- a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
@@ -11,6 +11,7 @@ router ospf
capability opaque
router-info area 0.0.0.0
segment-routing on
+ segment-routing local-block 5000 5999
segment-routing global-block 10000 19999
segment-routing node-msd 8
segment-routing prefix 10.0.255.3/32 index 300
diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
index 3d036801d5..1b98ff4756 100644
--- a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
@@ -5,9 +5,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8100,
+ "outLabel":16100,
"outLabelStack":[
- 8100
+ 16100
],
"distance":150,
"installed":true,
@@ -37,9 +37,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8400,
+ "outLabel":16400,
"outLabelStack":[
- 8400
+ 16400
],
"distance":150,
"installed":true,
diff --git a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
index d92ec91c72..a241b32607 100644
--- a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
@@ -3,9 +3,14 @@
"srNodes":[
{
"routerID":"10.0.255.2",
- "srgbSize":20000,
- "srgbLabel":8000,
+ "srgbSize":8000,
+ "srgbLabel":16000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
"extendedPrefix":[
{
@@ -26,6 +31,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@@ -69,8 +76,14 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
+ "srlbSize":1000,
+ "srlbLabel":5000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
@@ -78,7 +91,7 @@
"inputLabel":10300,
"prefixRoute":[
{
- "outputLabel":8300,
+ "outputLabel":16300,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
@@ -90,8 +103,14 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
+ "srlbSize":1000,
+ "srlbLabel":15000,
"algorithms":[
+ {
+ "0":"SPF"
+ }
],
+ "nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
@@ -99,7 +118,7 @@
"inputLabel":10100,
"prefixRoute":[
{
- "outputLabel":8100,
+ "outputLabel":16100,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
diff --git a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
index 65fdce69f7..9d0d148812 100644
--- a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
@@ -12,6 +12,7 @@ router ospf
capability opaque
router-info area 0.0.0.0
segment-routing on
+ segment-routing local-block 5000 5999
segment-routing global-block 10000 19999
segment-routing node-msd 12
segment-routing prefix 10.0.255.4/32 index 400 no-php-flag
diff --git a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
index 86ad8721f8..b5758f29a0 100644
--- a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
@@ -5,9 +5,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8100,
+ "outLabel":16100,
"outLabelStack":[
- 8100
+ 16100
],
"distance":150,
"installed":true,
@@ -37,9 +37,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
- "outLabel":8300,
+ "outLabel":16300,
"outLabelStack":[
- 8300
+ 16300
],
"distance":150,
"installed":true,