2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* IS-IS Rout(e)ing protocol - isis_lsp.c
|
|
|
|
* LSP processing
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001,2002 Sampo Saaristo
|
|
|
|
* Tampere University of Technology
|
|
|
|
* Institute of Communications Engineering
|
2015-11-12 14:24:22 +01:00
|
|
|
* Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2005-05-03 11:27:23 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "linklist.h"
|
2023-03-07 20:22:48 +01:00
|
|
|
#include "frrevent.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "vty.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "command.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "if.h"
|
2008-08-13 20:09:10 +02:00
|
|
|
#include "checksum.h"
|
2012-03-24 16:35:20 +01:00
|
|
|
#include "md5.h"
|
2015-11-12 14:24:22 +01:00
|
|
|
#include "table.h"
|
2018-07-22 21:49:02 +02:00
|
|
|
#include "srcdest_table.h"
|
2018-06-18 20:27:21 +02:00
|
|
|
#include "lib_errors.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
#include "isisd/isis_constants.h"
|
|
|
|
#include "isisd/isis_common.h"
|
2012-03-24 16:35:20 +01:00
|
|
|
#include "isisd/isis_flags.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "isisd/isis_circuit.h"
|
|
|
|
#include "isisd/isisd.h"
|
|
|
|
#include "isisd/isis_lsp.h"
|
|
|
|
#include "isisd/isis_pdu.h"
|
|
|
|
#include "isisd/isis_dynhn.h"
|
|
|
|
#include "isisd/isis_misc.h"
|
|
|
|
#include "isisd/isis_csm.h"
|
|
|
|
#include "isisd/isis_adjacency.h"
|
|
|
|
#include "isisd/isis_spf.h"
|
2017-04-27 13:56:38 +02:00
|
|
|
#include "isisd/isis_mt.h"
|
2017-07-23 15:06:09 +02:00
|
|
|
#include "isisd/isis_tlvs.h"
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
#include "isisd/isis_te.h"
|
2019-08-04 03:02:37 +02:00
|
|
|
#include "isisd/isis_sr.h"
|
fabricd: adjacency formation optimization as per section 2.4
OpenFabric changes IS-IS's initial database synchronization. While
regular IS-IS will simultaneuously exchange LSPs with all neighboring
routers during startup, this is considered too much churn for a densely
connected fabric.
To mitigate this, OpenFabric prescribes that a router should only
bring up an adjacency with a single neighbor and perform a full
synchronization with that neighbor, before bringing up further
adjacencies.
This is implemented by having a field `initial_sync_state` in the
fabricd datastructure which tracks whether an initial sync is still
pending, currently in progress, or complete.
When an initial sync is pending, the state will transition to the
in-progress state when the first IIH is received.
During this state, all IIHs from other routers are ignored. Any
IIHs transmitted on any link other than the one to the router with
which we are performing the initial sync will always report the far
end as DOWN in their threeway handshake state, avoiding the formation of
additional adjacencies.
The state will be left if all the SRM and SSN flags on the
initial-sync circuit are cleared (meaning that initial sync has
completed). This is checked in `lsp_tick`. When this condition occurrs,
we progress to the initial-sync-complete state, allowing other
adjacencies to form.
The state can also be left if the initial synchronization is taking too
long to succeed, for whatever reason. In that case, we fall back to the
initial-sync-pending state and will reattempt initial synchronization
with a different neighbor.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-04-02 17:55:26 +02:00
|
|
|
#include "isisd/fabricd.h"
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
#include "isisd/isis_tx_queue.h"
|
2019-10-17 20:33:53 +02:00
|
|
|
#include "isisd/isis_nb.h"
|
2022-01-04 02:31:45 +01:00
|
|
|
#include "isisd/isis_flex_algo.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2021-03-22 18:27:58 +01:00
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
|
|
|
|
|
2022-03-01 22:18:12 +01:00
|
|
|
static void lsp_refresh(struct event *thread);
|
|
|
|
static void lsp_l1_refresh_pseudo(struct event *thread);
|
|
|
|
static void lsp_l2_refresh_pseudo(struct event *thread);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
static void lsp_destroy(struct isis_lsp *lsp);
|
|
|
|
|
2022-09-27 20:09:21 +02:00
|
|
|
static bool device_startup;
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
|
|
|
|
}
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
return memcmp(a->hdr.lsp_id, b->hdr.lsp_id, sizeof(a->hdr.lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
void lsp_db_init(struct lspdb_head *head)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
lspdb_init(head);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
void lsp_db_fini(struct lspdb_head *head)
|
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
while ((lsp = lspdb_pop(head)))
|
|
|
|
lsp_destroy(lsp);
|
|
|
|
lspdb_fini(head);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
struct isis_lsp *lsp_search(struct lspdb_head *head, const uint8_t *id)
|
|
|
|
{
|
|
|
|
struct isis_lsp searchfor;
|
|
|
|
memcpy(searchfor.hdr.lsp_id, id, sizeof(searchfor.hdr.lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
return lspdb_find(head, &searchfor);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void lsp_clear_data(struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
if (!lsp)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_free_tlvs(lsp->tlvs);
|
|
|
|
lsp->tlvs = NULL;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
static void lsp_remove_frags(struct lspdb_head *head, struct list *frags);
|
2018-10-16 17:36:45 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
static void lsp_destroy(struct isis_lsp *lsp)
|
|
|
|
{
|
2017-10-03 01:42:22 +02:00
|
|
|
struct listnode *cnode;
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_circuit *circuit;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (!lsp)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-03 01:42:22 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
isis_tx_queue_del(circuit->tx_queue, lsp);
|
2017-10-03 01:42:22 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
isis_te_lsp_event(lsp, LSP_DEL);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_clear_data(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-16 17:36:45 +02:00
|
|
|
if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
|
|
|
|
if (lsp->lspu.frags) {
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_remove_frags(&lsp->area->lspdb[lsp->level - 1],
|
|
|
|
lsp->lspu.frags);
|
2018-10-16 17:36:45 +02:00
|
|
|
list_delete(&lsp->lspu.frags);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (lsp->lspu.zero_lsp
|
|
|
|
&& lsp->lspu.zero_lsp->lspu.frags) {
|
|
|
|
listnode_delete(lsp->lspu.zero_lsp->lspu.frags, lsp);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_spf_schedule(lsp->area, lsp->level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (lsp->pdu)
|
|
|
|
stream_free(lsp->pdu);
|
2018-11-23 03:13:56 +01:00
|
|
|
|
|
|
|
fabricd_lsp_free(lsp);
|
2003-12-23 09:09:43 +01:00
|
|
|
XFREE(MTYPE_ISIS_LSP, lsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove all the frags belonging to the given lsp
|
|
|
|
*/
|
2019-02-04 01:22:03 +01:00
|
|
|
static void lsp_remove_frags(struct lspdb_head *head, struct list *frags)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
struct listnode *lnode, *lnnode;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(head, lsp->hdr.lsp_id);
|
|
|
|
lspdb_del(head, lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_destroy(lsp);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
void lsp_search_and_destroy(struct lspdb_head *head, const uint8_t *id)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(head, id);
|
|
|
|
if (lsp) {
|
|
|
|
lspdb_del(head, lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
/*
|
|
|
|
* If this is a zero lsp, remove all the frags now
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->lspu.frags)
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_remove_frags(head, lsp->lspu.frags);
|
2004-09-10 22:48:21 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* else just remove this frag, from the zero lsps' frag
|
|
|
|
* list
|
|
|
|
*/
|
|
|
|
if (lsp->lspu.zero_lsp
|
|
|
|
&& lsp->lspu.zero_lsp->lspu.frags)
|
|
|
|
listnode_delete(lsp->lspu.zero_lsp->lspu.frags,
|
|
|
|
lsp);
|
|
|
|
}
|
|
|
|
lsp_destroy(lsp);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compares a LSP to given values
|
|
|
|
* Params are given in net order
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
|
|
|
|
uint16_t checksum, uint16_t rem_lifetime)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp->hdr.seqno == seqno && lsp->hdr.checksum == checksum
|
|
|
|
&& ((lsp->hdr.rem_lifetime == 0 && rem_lifetime == 0)
|
|
|
|
|| (lsp->hdr.rem_lifetime != 0 && rem_lifetime != 0))) {
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SNP_PACKETS) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Snp (%s): Compare LSP %pLS seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
|
|
|
areatag, lsp->hdr.lsp_id, lsp->hdr.seqno,
|
|
|
|
lsp->hdr.checksum, lsp->hdr.rem_lifetime);
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:51:47 +01:00
|
|
|
"ISIS-Snp (%s): is equal to ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
2017-07-05 18:37:36 +02:00
|
|
|
areatag, seqno, checksum, rem_lifetime);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
return LSP_EQUAL;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:33:15 +01:00
|
|
|
/*
|
|
|
|
* LSPs with identical checksums should only be treated as newer if:
|
|
|
|
* a) The current LSP has a remaining lifetime != 0 and the other LSP
|
|
|
|
* has a
|
|
|
|
* remaining lifetime == 0. In this case, we should participate in
|
|
|
|
* the purge
|
|
|
|
* and should not treat the current LSP with remaining lifetime == 0
|
|
|
|
* as older.
|
|
|
|
* b) The LSP has an incorrect checksum. In this case, we need to react
|
|
|
|
* as given
|
|
|
|
* in 7.3.16.2.
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
if (seqno > lsp->hdr.seqno
|
|
|
|
|| (seqno == lsp->hdr.seqno
|
|
|
|
&& ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
|
2018-11-14 18:54:59 +01:00
|
|
|
|| (lsp->hdr.checksum != checksum
|
|
|
|
&& lsp->hdr.rem_lifetime)))) {
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SNP_PACKETS) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Snp (%s): Compare LSP %pLS seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
|
|
|
areatag, lsp->hdr.lsp_id, seqno, checksum,
|
|
|
|
rem_lifetime);
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:51:47 +01:00
|
|
|
"ISIS-Snp (%s): is newer than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
2017-07-05 18:37:36 +02:00
|
|
|
areatag, lsp->hdr.seqno, lsp->hdr.checksum,
|
|
|
|
lsp->hdr.rem_lifetime);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
return LSP_NEWER;
|
|
|
|
}
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SNP_PACKETS) {
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Snp (%s): Compare LSP %pLS seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
|
|
|
areatag, lsp->hdr.lsp_id, seqno, checksum,
|
|
|
|
rem_lifetime);
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:51:47 +01:00
|
|
|
"ISIS-Snp (%s): is older than ours seq 0x%08x, cksum 0x%04hx, lifetime %hus",
|
2017-07-05 18:37:36 +02:00
|
|
|
areatag, lsp->hdr.seqno, lsp->hdr.checksum,
|
|
|
|
lsp->hdr.rem_lifetime);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return LSP_OLDER;
|
|
|
|
}
|
|
|
|
|
2017-08-29 00:14:43 +02:00
|
|
|
static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
uint8_t pdu_type =
|
|
|
|
(lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
|
|
|
|
struct isis_lsp_hdr *hdr = &lsp->hdr;
|
|
|
|
struct stream *stream = lsp->pdu;
|
2018-02-02 18:10:09 +01:00
|
|
|
size_t orig_getp = 0, orig_endp = 0;
|
2017-08-29 00:14:43 +02:00
|
|
|
|
|
|
|
if (keep) {
|
|
|
|
orig_getp = stream_get_getp(lsp->pdu);
|
|
|
|
orig_endp = stream_get_endp(lsp->pdu);
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_set_getp(lsp->pdu, 0);
|
|
|
|
stream_set_endp(lsp->pdu, 0);
|
2017-07-05 18:37:36 +02:00
|
|
|
|
|
|
|
fill_fixed_hdr(pdu_type, stream);
|
|
|
|
|
|
|
|
if (len_pointer)
|
|
|
|
*len_pointer = stream_get_endp(stream);
|
|
|
|
stream_putw(stream, hdr->pdu_len);
|
|
|
|
stream_putw(stream, hdr->rem_lifetime);
|
|
|
|
stream_put(stream, hdr->lsp_id, sizeof(hdr->lsp_id));
|
|
|
|
stream_putl(stream, hdr->seqno);
|
|
|
|
stream_putw(stream, hdr->checksum);
|
|
|
|
stream_putc(stream, hdr->lsp_bits);
|
2017-08-29 00:14:43 +02:00
|
|
|
|
|
|
|
if (keep) {
|
|
|
|
stream_set_endp(lsp->pdu, orig_endp);
|
|
|
|
stream_set_getp(lsp->pdu, orig_getp);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
static void lsp_add_auth(struct isis_lsp *lsp)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
struct isis_passwd *passwd;
|
2017-07-05 18:37:36 +02:00
|
|
|
passwd = (lsp->level == IS_LEVEL_1) ? &lsp->area->area_passwd
|
|
|
|
: &lsp->area->domain_passwd;
|
|
|
|
isis_tlvs_add_auth(lsp->tlvs, passwd);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
static void lsp_pack_pdu(struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
if (!lsp->tlvs)
|
|
|
|
lsp->tlvs = isis_alloc_tlvs();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_add_auth(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
size_t len_pointer;
|
2017-08-29 00:14:43 +02:00
|
|
|
put_lsp_hdr(lsp, &len_pointer, false);
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true);
|
|
|
|
|
|
|
|
lsp->hdr.pdu_len = stream_get_endp(lsp->pdu);
|
|
|
|
lsp->hdr.checksum =
|
|
|
|
ntohs(fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
|
|
|
|
stream_get_endp(lsp->pdu) - 12, 12));
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
uint32_t newseq;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (seqno == 0 || lsp->hdr.seqno > seqno)
|
|
|
|
newseq = lsp->hdr.seqno + 1;
|
2003-12-23 09:09:43 +01:00
|
|
|
else
|
2017-07-05 18:37:36 +02:00
|
|
|
newseq = seqno + 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-11-14 15:08:26 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
/* check for overflow */
|
|
|
|
if (newseq < lsp->hdr.seqno) {
|
|
|
|
/* send northbound notification */
|
2020-09-15 22:46:15 +02:00
|
|
|
lsp->area->lsp_exceeded_max_counter++;
|
|
|
|
isis_notif_lsp_exceed_max(lsp->area, lsp->hdr.lsp_id);
|
2018-11-14 15:08:26 +01:00
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.seqno = newseq;
|
|
|
|
|
|
|
|
lsp_pack_pdu(lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_spf_schedule(lsp->area, lsp->level);
|
2021-06-22 19:59:02 +02:00
|
|
|
isis_te_lsp_event(lsp, LSP_INC);
|
2017-07-05 18:37:36 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
static void lsp_purge_add_poi(struct isis_lsp *lsp,
|
|
|
|
const uint8_t *sender)
|
|
|
|
{
|
2020-07-13 14:37:59 +02:00
|
|
|
if (lsp->area == NULL)
|
|
|
|
return;
|
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
if (!lsp->area->purge_originator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* add purge originator identification */
|
|
|
|
if (!lsp->tlvs)
|
|
|
|
lsp->tlvs = isis_alloc_tlvs();
|
2020-07-13 14:37:59 +02:00
|
|
|
isis_tlvs_set_purge_originator(lsp->tlvs, lsp->area->isis->sysid,
|
|
|
|
sender);
|
2018-05-31 15:14:26 +02:00
|
|
|
isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lsp_purge(struct isis_lsp *lsp, int level,
|
|
|
|
const uint8_t *sender)
|
2017-07-05 18:37:36 +02:00
|
|
|
{
|
|
|
|
/* reset stream */
|
|
|
|
lsp_clear_data(lsp);
|
|
|
|
stream_reset(lsp->pdu);
|
|
|
|
|
|
|
|
/* update header */
|
|
|
|
lsp->hdr.checksum = 0;
|
|
|
|
lsp->hdr.rem_lifetime = 0;
|
|
|
|
lsp->level = level;
|
|
|
|
lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
|
2018-11-24 00:36:37 +01:00
|
|
|
lsp->area->lsp_purge_count[level - 1]++;
|
2017-07-05 18:37:36 +02:00
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
lsp_purge_add_poi(lsp, sender);
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_pack_pdu(lsp);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(lsp, NULL);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-07-05 18:37:36 +02:00
|
|
|
* Generates checksum for LSP and its frags
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
static void lsp_seqno_update(struct isis_lsp *lsp0)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *node;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_inc_seqno(lsp0, 0);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
if (!lsp0->lspu.frags)
|
|
|
|
return;
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
|
|
|
|
if (lsp->tlvs)
|
|
|
|
lsp_inc_seqno(lsp, 0);
|
2018-11-09 16:38:38 +01:00
|
|
|
else if (lsp->hdr.rem_lifetime) {
|
|
|
|
/* Purge should only be applied when the fragment has
|
|
|
|
* non-zero remaining lifetime.
|
|
|
|
*/
|
2018-05-31 15:14:26 +02:00
|
|
|
lsp_purge(lsp, lsp0->level, NULL);
|
2018-11-09 16:38:38 +01:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-12 22:56:04 +02:00
|
|
|
bool isis_level2_adj_up(struct isis_area *area)
|
2020-12-24 19:29:42 +01:00
|
|
|
{
|
|
|
|
struct listnode *node, *cnode;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
struct list *adjdb;
|
|
|
|
struct isis_adjacency *adj;
|
2021-07-12 22:51:27 +02:00
|
|
|
|
2021-07-12 22:56:04 +02:00
|
|
|
if (area->is_type == IS_LEVEL_1)
|
|
|
|
return false;
|
|
|
|
|
2021-07-12 22:51:27 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
|
|
|
|
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
|
|
|
|
adjdb = circuit->u.bc.adjdb[1];
|
|
|
|
if (!adjdb || !adjdb->count)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
|
2021-01-30 01:36:22 +01:00
|
|
|
if (adj->level != ISIS_ADJ_LEVEL1
|
2020-12-24 19:29:42 +01:00
|
|
|
&& adj->adj_state == ISIS_ADJ_UP)
|
|
|
|
return true;
|
|
|
|
}
|
2021-07-12 22:51:27 +02:00
|
|
|
} else if (circuit->circ_type == CIRCUIT_T_P2P
|
|
|
|
&& circuit->u.p2p.neighbor) {
|
|
|
|
adj = circuit->u.p2p.neighbor;
|
|
|
|
if (adj->level != ISIS_ADJ_LEVEL1
|
|
|
|
&& adj->adj_state == ISIS_ADJ_UP)
|
|
|
|
return true;
|
2020-12-24 19:29:42 +01:00
|
|
|
}
|
|
|
|
}
|
2021-07-12 22:51:27 +02:00
|
|
|
|
2020-12-24 19:29:42 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 20:09:21 +02:00
|
|
|
/*
|
|
|
|
* Unset the overload bit after the timer expires
|
|
|
|
*/
|
2022-03-01 22:18:12 +01:00
|
|
|
void set_overload_on_start_timer(struct event *thread)
|
2022-09-27 20:09:21 +02:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct isis_area *area = EVENT_ARG(thread);
|
2022-09-27 20:09:21 +02:00
|
|
|
assert(area);
|
|
|
|
|
|
|
|
area->t_overload_on_startup_timer = NULL;
|
2022-10-12 19:52:27 +02:00
|
|
|
|
|
|
|
/* Check if set-overload-bit is not currently configured */
|
|
|
|
if (!area->overload_configured)
|
|
|
|
isis_area_overload_bit_set(area, false);
|
2022-09-27 20:09:21 +02:00
|
|
|
}
|
|
|
|
|
2021-07-12 22:51:27 +02:00
|
|
|
static void isis_reset_attach_bit(struct isis_adjacency *adj)
|
2021-01-30 01:36:22 +01:00
|
|
|
{
|
2021-07-12 22:51:27 +02:00
|
|
|
struct isis_area *area = adj->circuit->area;
|
2021-01-30 01:36:22 +01:00
|
|
|
struct lspdb_head *head;
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
|
2021-07-12 22:51:27 +02:00
|
|
|
/*
|
|
|
|
* If an L2 adjacency changed its state in L-1-2 area, we have to:
|
|
|
|
* - set the attached bit in L1 LSPs if it's the first L2 adjacency
|
|
|
|
* - remove the attached bit in L1 LSPs if it's the last L2 adjacency
|
2021-01-30 01:36:22 +01:00
|
|
|
*/
|
2021-07-12 22:51:27 +02:00
|
|
|
|
|
|
|
if (area->is_type != IS_LEVEL_1_AND_2 || adj->level == ISIS_ADJ_LEVEL1)
|
2021-01-30 01:36:22 +01:00
|
|
|
return;
|
|
|
|
|
2021-07-12 22:51:27 +02:00
|
|
|
if (!area->attached_bit_send)
|
|
|
|
return;
|
|
|
|
|
|
|
|
head = &area->lspdb[IS_LEVEL_1 - 1];
|
|
|
|
memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
|
|
|
|
memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
|
|
|
|
lsp = lsp_search(head, lspid);
|
|
|
|
if (!lsp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (adj->adj_state == ISIS_ADJ_UP
|
|
|
|
&& !(lsp->hdr.lsp_bits & LSPBIT_ATT)) {
|
|
|
|
sched_debug("ISIS (%s): adj going up regenerate lsp-bits",
|
|
|
|
area->area_tag);
|
|
|
|
lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
|
|
|
|
} else if (adj->adj_state == ISIS_ADJ_DOWN
|
|
|
|
&& (lsp->hdr.lsp_bits & LSPBIT_ATT)
|
|
|
|
&& !isis_level2_adj_up(area)) {
|
|
|
|
sched_debug("ISIS (%s): adj going down regenerate lsp-bits",
|
|
|
|
area->area_tag);
|
|
|
|
lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
|
2021-01-30 01:36:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 19:29:42 +01:00
|
|
|
static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
|
|
|
|
struct isis_area *area)
|
2012-03-28 08:48:05 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lsp_bits = 0;
|
2021-07-12 22:56:50 +02:00
|
|
|
if (area->is_type == IS_LEVEL_1)
|
2012-03-28 08:48:05 +02:00
|
|
|
lsp_bits = IS_LEVEL_1;
|
|
|
|
else
|
|
|
|
lsp_bits = IS_LEVEL_1_AND_2;
|
|
|
|
if (overload_bit)
|
|
|
|
lsp_bits |= overload_bit;
|
2020-12-24 19:29:42 +01:00
|
|
|
|
|
|
|
/* only set the attach bit if we are a level-1-2 router and this is
|
|
|
|
* a level-1 LSP and we have a level-2 adjacency up from another area
|
|
|
|
*/
|
|
|
|
if (area->is_type == IS_LEVEL_1_AND_2 && level == IS_LEVEL_1
|
|
|
|
&& attached_bit && isis_level2_adj_up(area))
|
|
|
|
lsp_bits |= LSPBIT_ATT;
|
2012-03-28 08:48:05 +02:00
|
|
|
return lsp_bits;
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
|
|
|
|
struct isis_tlvs *tlvs, struct stream *stream,
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
/* free the old lsp data */
|
|
|
|
lsp_clear_data(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* copying only the relevant part of our stream */
|
2012-03-24 16:35:20 +01:00
|
|
|
if (lsp->pdu != NULL)
|
|
|
|
stream_free(lsp->pdu);
|
2005-05-03 11:27:23 +02:00
|
|
|
lsp->pdu = stream_dup(stream);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->area = area;
|
|
|
|
lsp->level = level;
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->age_out = ZERO_AGE_LIFETIME;
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->installed = time(NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->tlvs = tlvs;
|
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
if (area->dynhostname && lsp->tlvs->hostname
|
|
|
|
&& lsp->hdr.rem_lifetime) {
|
2021-06-11 17:27:46 +02:00
|
|
|
isis_dynhn_insert(
|
|
|
|
area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
|
|
|
|
(lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
|
|
|
|
? IS_LEVEL_2
|
|
|
|
: IS_LEVEL_1);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2017-09-23 20:01:43 +02:00
|
|
|
static void lsp_link_fragment(struct isis_lsp *lsp, struct isis_lsp *lsp0)
|
|
|
|
{
|
|
|
|
if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
|
|
|
|
/* zero lsp -> create list to store fragments */
|
|
|
|
lsp->lspu.frags = list_new();
|
|
|
|
} else {
|
|
|
|
/* fragment -> set backpointer and add to zero lsps list */
|
|
|
|
assert(lsp0);
|
|
|
|
lsp->lspu.zero_lsp = lsp0;
|
|
|
|
listnode_add(lsp0->lspu.frags, lsp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
|
|
|
|
struct isis_tlvs *tlvs, struct stream *stream,
|
2017-07-30 19:49:19 +02:00
|
|
|
struct isis_area *area, int level, bool confusion)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-01-06 20:19:40 +01:00
|
|
|
if (lsp->own_lsp) {
|
2018-08-03 20:03:29 +02:00
|
|
|
flog_err(
|
2018-09-13 21:34:28 +02:00
|
|
|
EC_LIB_DEVELOPMENT,
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Upd (%s): BUG updating LSP %pLS still marked as own LSP",
|
|
|
|
area->area_tag, lsp->hdr.lsp_id);
|
2017-01-06 20:19:40 +01:00
|
|
|
lsp_clear_data(lsp);
|
|
|
|
lsp->own_lsp = 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-30 19:49:19 +02:00
|
|
|
if (confusion) {
|
2018-05-31 15:14:26 +02:00
|
|
|
lsp_purge(lsp, level, NULL);
|
|
|
|
} else {
|
|
|
|
lsp_update_data(lsp, hdr, tlvs, stream, area, level);
|
2017-07-30 19:49:19 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-23 20:01:43 +02:00
|
|
|
if (LSP_FRAGMENT(lsp->hdr.lsp_id) && !lsp->lspu.zero_lsp) {
|
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
struct isis_lsp *lsp0;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2017-09-23 20:01:43 +02:00
|
|
|
memcpy(lspid, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
|
|
|
|
LSP_FRAGMENT(lspid) = 0;
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp0 = lsp_search(&area->lspdb[level - 1], lspid);
|
2017-09-23 20:01:43 +02:00
|
|
|
if (lsp0)
|
|
|
|
lsp_link_fragment(lsp, lsp0);
|
2017-08-11 15:28:58 +02:00
|
|
|
}
|
2017-09-23 20:01:43 +02:00
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
if (lsp->hdr.seqno) {
|
2017-10-05 17:47:12 +02:00
|
|
|
isis_spf_schedule(lsp->area, lsp->level);
|
2021-06-22 19:59:02 +02:00
|
|
|
isis_te_lsp_event(lsp, LSP_UPD);
|
|
|
|
}
|
2017-08-11 15:28:58 +02:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* creation of LSP directly from what we received */
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
|
|
|
|
struct isis_tlvs *tlvs,
|
|
|
|
struct stream *stream, struct isis_lsp *lsp0,
|
|
|
|
struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-01 19:52:33 +02:00
|
|
|
lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_update_data(lsp, hdr, tlvs, stream, area, level);
|
2017-08-11 15:28:58 +02:00
|
|
|
lsp_link_fragment(lsp, lsp0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
2018-10-16 19:17:10 +02:00
|
|
|
static void lsp_adjust_stream(struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
if (lsp->pdu) {
|
|
|
|
if (STREAM_SIZE(lsp->pdu) == LLC_LEN + lsp->area->lsp_mtu)
|
|
|
|
return;
|
|
|
|
stream_free(lsp->pdu);
|
|
|
|
}
|
|
|
|
|
|
|
|
lsp->pdu = stream_new(LLC_LEN + lsp->area->lsp_mtu);
|
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
|
2017-07-05 18:37:36 +02:00
|
|
|
uint16_t rem_lifetime, uint32_t seqno,
|
2017-08-11 15:28:58 +02:00
|
|
|
uint8_t lsp_bits, uint16_t checksum,
|
|
|
|
struct isis_lsp *lsp0, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-01 19:52:33 +02:00
|
|
|
lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp->area = area;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-16 19:17:10 +02:00
|
|
|
lsp_adjust_stream(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Minimal LSP PDU size */
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN;
|
|
|
|
memcpy(lsp->hdr.lsp_id, lsp_id, sizeof(lsp->hdr.lsp_id));
|
|
|
|
lsp->hdr.checksum = checksum;
|
|
|
|
lsp->hdr.seqno = seqno;
|
|
|
|
lsp->hdr.rem_lifetime = rem_lifetime;
|
|
|
|
lsp->hdr.lsp_bits = lsp_bits;
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->level = level;
|
|
|
|
lsp->age_out = ZERO_AGE_LIFETIME;
|
2017-08-11 15:28:58 +02:00
|
|
|
lsp_link_fragment(lsp, lsp0);
|
2017-08-29 00:14:43 +02:00
|
|
|
put_lsp_hdr(lsp, NULL, false);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_EVENTS)
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug("New LSP with ID %pLS len %d seqnum %08x", lsp_id,
|
|
|
|
lsp->hdr.pdu_len, lsp->hdr.seqno);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
lspdb_add(head, lsp);
|
2021-06-22 19:59:02 +02:00
|
|
|
if (lsp->hdr.seqno) {
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_spf_schedule(lsp->area, lsp->level);
|
2021-06-22 19:59:02 +02:00
|
|
|
isis_te_lsp_event(lsp, LSP_ADD);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-05-27 09:34:37 +02:00
|
|
|
* Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2019-02-04 01:22:03 +01:00
|
|
|
void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
|
|
|
|
const uint8_t *stop_id, struct list *list)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
struct isis_lsp searchfor;
|
|
|
|
struct isis_lsp *lsp, *start;
|
|
|
|
|
|
|
|
memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
start = lspdb_find_gteq(head, &searchfor);
|
2019-05-20 23:52:16 +02:00
|
|
|
frr_each_from (lspdb, head, lsp, start) {
|
2018-11-10 16:14:40 +01:00
|
|
|
if (memcmp(lsp->hdr.lsp_id, stop_id,
|
|
|
|
ISIS_SYS_ID_LEN + 2) > 0)
|
2004-09-10 22:48:21 +02:00
|
|
|
break;
|
|
|
|
|
2021-05-27 09:34:37 +02:00
|
|
|
if (lsp->hdr.rem_lifetime && lsp->hdr.seqno)
|
2018-11-10 16:14:40 +01:00
|
|
|
listnode_add(list, lsp);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void lsp_set_time(struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
assert(lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp->hdr.rem_lifetime == 0) {
|
2012-03-24 16:35:20 +01:00
|
|
|
if (lsp->age_out > 0)
|
|
|
|
lsp->age_out--;
|
2004-09-10 22:48:21 +02:00
|
|
|
return;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.rem_lifetime--;
|
|
|
|
if (lsp->pdu && stream_get_endp(lsp->pdu) >= 12)
|
|
|
|
stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-08 04:39:42 +01:00
|
|
|
void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
|
|
|
|
char frag, struct isis *isis)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_dynhn *dyn = NULL;
|
2020-04-20 20:12:38 +02:00
|
|
|
char id[SYSID_STRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (dynhost)
|
2021-06-11 17:27:46 +02:00
|
|
|
dyn = dynhn_find_by_id(isis, lsp_id);
|
2003-12-23 09:09:43 +01:00
|
|
|
else
|
|
|
|
dyn = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (dyn)
|
2020-04-21 01:14:13 +02:00
|
|
|
snprintf(id, sizeof(id), "%.14s", dyn->hostname);
|
2012-03-24 16:35:20 +01:00
|
|
|
else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
|
2020-04-21 01:14:13 +02:00
|
|
|
snprintf(id, sizeof(id), "%.14s", cmd_hostname_get());
|
2004-09-10 22:48:21 +02:00
|
|
|
else
|
2023-01-26 17:47:04 +01:00
|
|
|
snprintf(id, sizeof(id), "%pSY", lsp_id);
|
2020-07-13 14:37:59 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (frag)
|
2021-02-08 04:39:42 +01:00
|
|
|
snprintf(dest, dest_len, "%s.%02x-%02x", id,
|
|
|
|
LSP_PSEUDO_ID(lsp_id), LSP_FRAGMENT(lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
else
|
2021-02-08 04:39:42 +01:00
|
|
|
snprintf(dest, dest_len, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
/* Convert the lsp attribute bits to attribute string */
|
2018-06-19 18:22:01 +02:00
|
|
|
static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2018-06-19 18:22:01 +02:00
|
|
|
char *pos = buf;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (!lsp_bits)
|
2003-12-23 09:09:43 +01:00
|
|
|
return " none";
|
|
|
|
|
2018-06-19 18:22:01 +02:00
|
|
|
if (buf_size < 2 * 3)
|
|
|
|
return " error";
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* we only focus on the default metric */
|
2020-12-24 19:29:42 +01:00
|
|
|
pos += snprintf(pos, buf_size, "%d/",
|
|
|
|
ISIS_MASK_LSP_ATT_BITS(lsp_bits) ? 1 : 0);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2020-12-24 19:29:42 +01:00
|
|
|
pos += snprintf(pos, buf_size, "%d/",
|
|
|
|
ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-12-24 19:29:42 +01:00
|
|
|
snprintf(pos, buf_size, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2018-06-19 18:22:01 +02:00
|
|
|
return buf;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* this function prints the lsp on show isis database */
|
2022-02-24 11:31:18 +01:00
|
|
|
void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object *json,
|
|
|
|
char dynhost, struct isis *isis)
|
|
|
|
{
|
|
|
|
if (json) {
|
|
|
|
return lsp_print_json(lsp, json, dynhost, isis);
|
|
|
|
} else {
|
|
|
|
return lsp_print_vty(lsp, vty, dynhost, isis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
|
|
|
|
char dynhost, struct isis *isis)
|
|
|
|
{
|
|
|
|
char LSPid[255];
|
|
|
|
char age_out[8];
|
|
|
|
char b[200];
|
|
|
|
json_object *own_json;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
|
|
|
|
own_json = json_object_new_object();
|
|
|
|
json_object_object_add(json, "lsp", own_json);
|
|
|
|
json_object_string_add(own_json, "id", LSPid);
|
|
|
|
json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " ");
|
|
|
|
json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len);
|
|
|
|
snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno);
|
|
|
|
json_object_string_add(json, "seq-number", buf);
|
|
|
|
snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum);
|
|
|
|
json_object_string_add(json, "chksum", buf);
|
|
|
|
if (lsp->hdr.rem_lifetime == 0) {
|
|
|
|
snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
|
|
|
|
age_out[7] = '\0';
|
|
|
|
json_object_string_add(json, "holdtime", age_out);
|
|
|
|
} else {
|
|
|
|
json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime);
|
|
|
|
}
|
|
|
|
json_object_string_add(
|
|
|
|
json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty,
|
|
|
|
char dynhost, struct isis *isis)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2018-11-23 02:11:07 +01:00
|
|
|
char LSPid[255];
|
2012-03-24 16:35:20 +01:00
|
|
|
char age_out[8];
|
2018-06-19 18:22:01 +02:00
|
|
|
char b[200];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-02-08 04:39:42 +01:00
|
|
|
lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
|
2020-03-27 12:51:47 +01:00
|
|
|
vty_out(vty, "%5hu ", lsp->hdr.pdu_len);
|
|
|
|
vty_out(vty, "0x%08x ", lsp->hdr.seqno);
|
|
|
|
vty_out(vty, "0x%04hx ", lsp->hdr.checksum);
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp->hdr.rem_lifetime == 0) {
|
2020-04-20 20:12:38 +02:00
|
|
|
snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
|
2012-03-24 16:35:20 +01:00
|
|
|
age_out[7] = '\0';
|
|
|
|
vty_out(vty, "%7s ", age_out);
|
2003-12-23 09:09:43 +01:00
|
|
|
} else
|
2020-03-27 12:51:47 +01:00
|
|
|
vty_out(vty, " %5hu ", lsp->hdr.rem_lifetime);
|
2018-06-19 18:22:01 +02:00
|
|
|
vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
|
2017-04-27 13:56:45 +02:00
|
|
|
}
|
|
|
|
|
2022-02-24 11:31:18 +01:00
|
|
|
void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty,
|
|
|
|
struct json_object *json, char dynhost,
|
|
|
|
struct isis *isis)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-02-24 11:31:18 +01:00
|
|
|
if (json) {
|
|
|
|
lsp_print_json(lsp, json, dynhost, isis);
|
|
|
|
if (lsp->tlvs) {
|
|
|
|
isis_format_tlvs(lsp->tlvs, json);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
lsp_print_vty(lsp, vty, dynhost, isis);
|
|
|
|
if (lsp->tlvs)
|
|
|
|
vty_multiline(vty, " ", "%s",
|
|
|
|
isis_format_tlvs(lsp->tlvs, NULL));
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* print all the lsps info in the local lspdb */
|
2022-02-24 11:31:18 +01:00
|
|
|
int lsp_print_all(struct vty *vty, struct json_object *json,
|
|
|
|
struct lspdb_head *head, char detail, char dynhost,
|
|
|
|
struct isis *isis)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
struct isis_lsp *lsp;
|
2003-12-23 09:09:43 +01:00
|
|
|
int lsp_count = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (detail == ISIS_UI_LEVEL_BRIEF) {
|
2019-05-20 23:52:16 +02:00
|
|
|
frr_each (lspdb, head, lsp) {
|
2022-02-24 11:31:18 +01:00
|
|
|
lsp_print_common(lsp, vty, json, dynhost, isis);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_count++;
|
|
|
|
}
|
|
|
|
} else if (detail == ISIS_UI_LEVEL_DETAIL) {
|
2019-05-20 23:52:16 +02:00
|
|
|
frr_each (lspdb, head, lsp) {
|
2022-02-24 11:31:18 +01:00
|
|
|
lsp_print_detail(lsp, vty, json, dynhost, isis);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_count++;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return lsp_count;
|
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
static uint16_t lsp_rem_lifetime(struct isis_area *area, int level)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t rem_lifetime;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/* Add jitter to configured LSP lifetime */
|
|
|
|
rem_lifetime =
|
|
|
|
isis_jitter(area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER);
|
|
|
|
|
|
|
|
/* No jitter if the max refresh will be less than configure gen interval
|
|
|
|
*/
|
2015-11-10 18:32:11 +01:00
|
|
|
/* N.B. this calucation is acceptable since rem_lifetime is in
|
|
|
|
* [332,65535] at
|
|
|
|
* this point */
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
|
|
|
|
rem_lifetime = area->max_lsp_lifetime[level - 1];
|
|
|
|
|
|
|
|
return rem_lifetime;
|
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
static uint16_t lsp_refresh_time(struct isis_lsp *lsp, uint16_t rem_lifetime)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
struct isis_area *area = lsp->area;
|
|
|
|
int level = lsp->level;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t refresh_time;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/* Add jitter to LSP refresh time */
|
|
|
|
refresh_time =
|
|
|
|
isis_jitter(area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER);
|
|
|
|
|
|
|
|
/* RFC 4444 : make sure the refresh time is at least less than 300
|
|
|
|
* of the remaining lifetime and more than gen interval */
|
|
|
|
if (refresh_time <= area->lsp_gen_interval[level - 1]
|
|
|
|
|| refresh_time > (rem_lifetime - 300))
|
|
|
|
refresh_time = rem_lifetime - 300;
|
|
|
|
|
2015-11-10 18:32:11 +01:00
|
|
|
/* In cornercases, refresh_time might be <= lsp_gen_interval, however
|
|
|
|
* we accept this violation to satisfy refresh_time <= rem_lifetime -
|
|
|
|
* 300 */
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
return refresh_time;
|
|
|
|
}
|
|
|
|
|
2022-12-15 14:02:46 +01:00
|
|
|
static void lsp_build_internal_reach_ipv4(struct isis_lsp *lsp,
|
|
|
|
struct isis_area *area,
|
|
|
|
struct prefix_ipv4 *ipv4,
|
|
|
|
uint32_t metric)
|
|
|
|
{
|
|
|
|
struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {NULL};
|
|
|
|
|
|
|
|
if (area->oldmetric) {
|
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Adding old-style IP reachability for %pFX",
|
|
|
|
area->area_tag, ipv4);
|
|
|
|
isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4, metric);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (area->newmetric) {
|
|
|
|
lsp_debug("ISIS (%s): Adding te-style IP reachability for %pFX",
|
|
|
|
area->area_tag, ipv4);
|
|
|
|
|
|
|
|
if (area->srdb.enabled)
|
2022-01-04 02:31:45 +01:00
|
|
|
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
|
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(i) &&
|
|
|
|
!isis_flex_algo_elected_supported(i, area))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
2022-12-15 14:02:46 +01:00
|
|
|
pcfgs[i] =
|
|
|
|
isis_sr_cfg_prefix_find(area, ipv4, i);
|
2022-01-04 02:31:45 +01:00
|
|
|
}
|
2022-12-15 14:02:46 +01:00
|
|
|
|
|
|
|
isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric, false,
|
|
|
|
pcfgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lsp_build_internal_reach_ipv6(struct isis_lsp *lsp,
|
|
|
|
struct isis_area *area,
|
|
|
|
struct prefix_ipv6 *ipv6,
|
|
|
|
uint32_t metric)
|
|
|
|
{
|
|
|
|
struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {NULL};
|
|
|
|
|
|
|
|
lsp_debug("ISIS (%s): Adding IPv6 reachability for %pFX",
|
|
|
|
area->area_tag, ipv6);
|
|
|
|
|
|
|
|
if (area->srdb.enabled)
|
2022-01-04 02:31:45 +01:00
|
|
|
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
|
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(i) &&
|
|
|
|
!isis_flex_algo_elected_supported(i, area))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
2022-12-15 14:02:46 +01:00
|
|
|
pcfgs[i] = isis_sr_cfg_prefix_find(area, ipv6, i);
|
2022-01-04 02:31:45 +01:00
|
|
|
}
|
2022-12-15 14:02:46 +01:00
|
|
|
|
|
|
|
isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), ipv6,
|
|
|
|
metric, false, pcfgs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_area *area)
|
2015-11-12 14:24:22 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level);
|
2015-11-12 14:24:22 +01:00
|
|
|
if (!er_table)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
for (struct route_node *rn = route_top(er_table); rn;
|
|
|
|
rn = route_next(rn)) {
|
2015-11-12 14:24:22 +01:00
|
|
|
if (!rn->info)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p;
|
|
|
|
struct isis_ext_info *info = rn->info;
|
2015-11-12 14:24:22 +01:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
uint32_t metric = info->metric;
|
|
|
|
if (metric > MAX_WIDE_PATH_METRIC)
|
|
|
|
metric = MAX_WIDE_PATH_METRIC;
|
|
|
|
if (area->oldmetric && metric > 0x3f)
|
|
|
|
metric = 0x3f;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (area->oldmetric)
|
|
|
|
isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
|
|
|
|
metric);
|
2019-08-04 03:02:37 +02:00
|
|
|
if (area->newmetric) {
|
2021-12-11 07:22:42 +01:00
|
|
|
struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {
|
|
|
|
NULL};
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
if (area->srdb.enabled)
|
2022-01-04 02:31:45 +01:00
|
|
|
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
|
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(i) &&
|
|
|
|
!isis_flex_algo_elected_supported(
|
|
|
|
i, area))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
2021-12-11 07:22:42 +01:00
|
|
|
pcfgs[i] = isis_sr_cfg_prefix_find(
|
|
|
|
area, ipv4, i);
|
2022-01-04 02:31:45 +01:00
|
|
|
}
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric,
|
2021-12-11 07:22:42 +01:00
|
|
|
true, pcfgs);
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
}
|
2017-04-27 13:56:45 +02:00
|
|
|
}
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_area *area)
|
2015-11-12 14:24:22 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
struct route_table *er_table =
|
|
|
|
get_ext_reach(area, AF_INET6, lsp->level);
|
2015-11-12 14:24:22 +01:00
|
|
|
if (!er_table)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
for (struct route_node *rn = route_top(er_table); rn;
|
2018-07-22 21:49:02 +02:00
|
|
|
rn = srcdest_route_next(rn)) {
|
2015-11-12 14:24:22 +01:00
|
|
|
if (!rn->info)
|
|
|
|
continue;
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_ext_info *info = rn->info;
|
2018-07-22 21:49:02 +02:00
|
|
|
struct prefix_ipv6 *p, *src_p;
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
|
2018-07-22 21:49:02 +02:00
|
|
|
srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
|
|
|
|
(const struct prefix **)&src_p);
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
uint32_t metric = info->metric;
|
2015-11-12 14:24:22 +01:00
|
|
|
if (info->metric > MAX_WIDE_PATH_METRIC)
|
2017-07-05 18:37:36 +02:00
|
|
|
metric = MAX_WIDE_PATH_METRIC;
|
2018-07-22 21:49:02 +02:00
|
|
|
|
|
|
|
if (!src_p || !src_p->prefixlen) {
|
2021-12-11 07:22:42 +01:00
|
|
|
struct sr_prefix_cfg *pcfgs[SR_ALGORITHM_COUNT] = {
|
|
|
|
NULL};
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
if (area->srdb.enabled)
|
2022-01-04 02:31:45 +01:00
|
|
|
for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
|
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(i) &&
|
|
|
|
!isis_flex_algo_elected_supported(
|
|
|
|
i, area))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
2021-12-11 07:22:42 +01:00
|
|
|
pcfgs[i] = isis_sr_cfg_prefix_find(
|
|
|
|
area, p, i);
|
2022-01-04 02:31:45 +01:00
|
|
|
}
|
2019-08-04 03:02:37 +02:00
|
|
|
|
2018-07-22 21:49:02 +02:00
|
|
|
isis_tlvs_add_ipv6_reach(lsp->tlvs,
|
|
|
|
isis_area_ipv6_topology(area),
|
2021-12-11 07:22:42 +01:00
|
|
|
p, metric, true, pcfgs);
|
2018-07-22 21:49:02 +02:00
|
|
|
} else if (isis_area_ipv6_dstsrc_enabled(area)) {
|
|
|
|
isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
|
|
|
|
ISIS_MT_IPV6_DSTSRC,
|
|
|
|
p, src_p, metric);
|
|
|
|
}
|
2015-11-12 14:24:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
|
2015-11-12 14:24:22 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_build_ext_reach_ipv4(lsp, area);
|
|
|
|
lsp_build_ext_reach_ipv6(lsp, area);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
|
|
|
|
struct isis_area *area, int level)
|
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
uint8_t frag_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
|
|
|
|
memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
|
|
|
|
LSP_FRAGMENT(frag_id) = frag_num;
|
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(&area->lspdb[level - 1], frag_id);
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp) {
|
|
|
|
lsp_clear_data(lsp);
|
2017-09-23 20:01:43 +02:00
|
|
|
if (!lsp->lspu.zero_lsp)
|
|
|
|
lsp_link_fragment(lsp, lsp0);
|
2017-07-05 18:37:36 +02:00
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
|
|
|
|
lsp_bits_generate(level, area->overload_bit,
|
2020-12-24 19:29:42 +01:00
|
|
|
area->attached_bit_send, area),
|
2017-08-11 15:28:58 +02:00
|
|
|
0, lsp0, level);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->own_lsp = 1;
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_insert(&area->lspdb[level - 1], lsp);
|
2017-07-05 18:37:36 +02:00
|
|
|
return lsp;
|
2015-11-12 14:24:22 +01:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Builds the LSP data part. This func creates a new frag whenever
|
|
|
|
* area->lsp_frag_threshold is exceeded.
|
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
int level = lsp->level;
|
2017-07-05 18:37:36 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct isis_lsp *frag;
|
|
|
|
|
|
|
|
lsp_clear_data(lsp);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
|
|
|
|
lsp_clear_data(frag);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->tlvs = isis_alloc_tlvs();
|
2005-09-01 19:52:33 +02:00
|
|
|
lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
|
|
|
|
area->area_tag, level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
|
2020-12-24 19:29:42 +01:00
|
|
|
area->attached_bit_send, area);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_add_auth(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Protocols Supported */
|
2015-11-12 14:21:47 +01:00
|
|
|
if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct nlpids nlpids = {.count = 0};
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
if (area->ip_circuits > 0) {
|
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
|
|
|
|
area->area_tag);
|
2017-07-05 18:37:36 +02:00
|
|
|
nlpids.nlpids[nlpids.count] = NLPID_IP;
|
|
|
|
nlpids.count++;
|
2005-09-02 03:38:16 +02:00
|
|
|
}
|
2005-09-26 19:58:24 +02:00
|
|
|
if (area->ipv6_circuits > 0) {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
|
|
|
|
area->area_tag);
|
2017-07-05 18:37:36 +02:00
|
|
|
nlpids.nlpids[nlpids.count] = NLPID_IPV6;
|
|
|
|
nlpids.count++;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
|
2004-10-03 20:18:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
if (area_is_mt(area)) {
|
|
|
|
lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
struct isis_area_mt_setting **mt_settings;
|
|
|
|
unsigned int mt_count;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
mt_settings = area_mt_settings(area, &mt_count);
|
|
|
|
for (unsigned int i = 0; i < mt_count; i++) {
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_add_mt_router_info(
|
|
|
|
lsp->tlvs, mt_settings[i]->mtid,
|
|
|
|
mt_settings[i]->overload, false);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): MT %s", area->area_tag,
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_mtid2str(mt_settings[i]->mtid));
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2005-09-28 20:45:54 +02:00
|
|
|
} else {
|
|
|
|
lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
|
2015-11-12 14:21:47 +01:00
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Dynamic Hostname */
|
2005-09-28 20:45:54 +02:00
|
|
|
if (area->dynhostname) {
|
2017-08-29 01:52:29 +02:00
|
|
|
isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
|
2017-08-29 01:52:29 +02:00
|
|
|
area->area_tag, cmd_hostname_get());
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2005-09-26 19:39:48 +02:00
|
|
|
lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
|
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-08-04 03:02:37 +02:00
|
|
|
/* Add Router Capability TLV. */
|
2020-07-13 14:37:59 +02:00
|
|
|
if (area->isis->router_id != 0) {
|
2022-01-04 02:31:45 +01:00
|
|
|
struct isis_router_cap *rcap;
|
|
|
|
#ifndef FABRICD
|
|
|
|
struct isis_router_cap_fad *rcap_fad;
|
|
|
|
struct listnode *node;
|
|
|
|
struct flex_algo *fa;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
|
|
|
rcap = isis_tlvs_init_router_capability(lsp->tlvs);
|
2019-08-04 03:02:37 +02:00
|
|
|
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->router_id.s_addr = area->isis->router_id;
|
2021-12-18 10:03:01 +01:00
|
|
|
|
2022-01-04 02:31:45 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
/* Set flex-algo definitions */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node,
|
|
|
|
fa)) {
|
|
|
|
if (!fa->advertise_definition)
|
|
|
|
continue;
|
|
|
|
lsp_debug("ISIS (%s): Flex-Algo Definition %u",
|
|
|
|
area->area_tag, fa->algorithm);
|
|
|
|
isis_tlvs_set_router_capability_fad(lsp->tlvs, fa,
|
|
|
|
fa->algorithm,
|
|
|
|
area->isis->sysid);
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
/* Add SR Sub-TLVs if SR is enabled. */
|
|
|
|
if (area->srdb.enabled) {
|
|
|
|
struct isis_sr_db *srdb = &area->srdb;
|
|
|
|
uint32_t range_size;
|
|
|
|
|
2020-05-20 11:18:31 +02:00
|
|
|
/* SRGB first */
|
2019-08-04 03:02:37 +02:00
|
|
|
range_size = srdb->config.srgb_upper_bound
|
|
|
|
- srdb->config.srgb_lower_bound + 1;
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I |
|
|
|
|
ISIS_SUBTLV_SRGB_FLAG_V;
|
|
|
|
rcap->srgb.range_size = range_size;
|
|
|
|
rcap->srgb.lower_bound = srdb->config.srgb_lower_bound;
|
2020-05-20 11:18:31 +02:00
|
|
|
/* Then Algorithm */
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->algo[0] = SR_ALGORITHM_SPF;
|
|
|
|
rcap->algo[1] = SR_ALGORITHM_UNSET;
|
|
|
|
#ifndef FABRICD
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos,
|
|
|
|
node, fa)) {
|
|
|
|
if (fa->advertise_definition)
|
|
|
|
rcap_fad = rcap->fads[fa->algorithm];
|
|
|
|
else
|
|
|
|
rcap_fad = NULL;
|
|
|
|
|
|
|
|
if (!isis_flex_algo_elected_supported_local_fad(
|
|
|
|
fa->algorithm, area, &rcap_fad))
|
|
|
|
continue;
|
|
|
|
lsp_debug("ISIS (%s): SR Algorithm %u",
|
|
|
|
area->area_tag, fa->algorithm);
|
|
|
|
rcap->algo[fa->algorithm] = fa->algorithm;
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
2020-05-20 11:18:31 +02:00
|
|
|
/* SRLB */
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->srlb.flags = 0;
|
2020-05-20 11:18:31 +02:00
|
|
|
range_size = srdb->config.srlb_upper_bound
|
|
|
|
- srdb->config.srlb_lower_bound + 1;
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->srlb.range_size = range_size;
|
|
|
|
rcap->srlb.lower_bound = srdb->config.srlb_lower_bound;
|
2020-05-20 11:18:31 +02:00
|
|
|
/* And finally MSD */
|
2022-01-04 02:31:45 +01:00
|
|
|
rcap->msd = srdb->config.msd;
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
/* IPv4 address and TE router ID TLVs.
|
|
|
|
* In case of the first one we don't follow "C" vendor,
|
|
|
|
* but "J" vendor behavior - one IPv4 address is put
|
|
|
|
* into LSP. TE router ID will be the same if MPLS-TE
|
|
|
|
* is not activate or MPLS-TE router-id not specified
|
|
|
|
*/
|
2020-07-13 14:37:59 +02:00
|
|
|
if (area->isis->router_id != 0) {
|
|
|
|
struct in_addr id = {.s_addr = area->isis->router_id};
|
2020-10-18 13:33:54 +02:00
|
|
|
lsp_debug("ISIS (%s): Adding router ID %pI4 as IPv4 tlv.",
|
|
|
|
area->area_tag, &id);
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
/* If new style TLV's are in use, add TE router ID TLV
|
|
|
|
* Check if MPLS-TE is activate and mpls-te router-id set
|
|
|
|
* otherwise add exactly same data as for IPv4 address
|
|
|
|
*/
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->newmetric) {
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
if (IS_MPLS_TE(area->mta)
|
2020-12-14 20:01:31 +01:00
|
|
|
&& area->mta->router_id.s_addr != INADDR_ANY)
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
id.s_addr = area->mta->router_id.s_addr;
|
2017-04-27 13:56:38 +02:00
|
|
|
lsp_debug(
|
2005-09-26 19:39:48 +02:00
|
|
|
"ISIS (%s): Adding router ID also as TE router ID tlv.",
|
|
|
|
area->area_tag);
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_set_te_router_id(lsp->tlvs, &id);
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2005-09-28 20:45:54 +02:00
|
|
|
lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
|
2015-11-12 14:21:47 +01:00
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2021-06-30 17:23:56 +02:00
|
|
|
if (IS_MPLS_TE(area->mta)
|
|
|
|
&& !IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
|
|
|
|
lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
|
|
|
|
area->area_tag);
|
|
|
|
isis_tlvs_set_te_router_id_ipv6(lsp->tlvs,
|
|
|
|
&area->mta->router_id_ipv6);
|
|
|
|
}
|
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding circuit specific information.",
|
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-10 19:05:40 +02:00
|
|
|
if (fabricd) {
|
|
|
|
lsp_debug(
|
2020-03-27 12:51:47 +01:00
|
|
|
"ISIS (%s): Adding tier %hhu spine-leaf-extension tlv.",
|
2018-05-10 19:05:40 +02:00
|
|
|
area->area_tag, fabricd_tier(area));
|
|
|
|
isis_tlvs_add_spine_leaf(lsp->tlvs, fabricd_tier(area), true,
|
|
|
|
false, false, false);
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_circuit *circuit;
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
|
2016-07-28 17:23:32 +02:00
|
|
|
if (!circuit->interface)
|
2005-09-26 20:06:47 +02:00
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Processing %s circuit %p with unknown interface",
|
|
|
|
area->area_tag,
|
|
|
|
circuit_type2string(circuit->circ_type),
|
2005-09-26 19:39:48 +02:00
|
|
|
circuit);
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
lsp_debug("ISIS (%s): Processing %s circuit %s",
|
|
|
|
area->area_tag,
|
|
|
|
circuit_type2string(circuit->circ_type),
|
|
|
|
circuit->interface->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
if (circuit->state != C_STATE_UP) {
|
|
|
|
lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
|
|
|
|
area->area_tag);
|
2015-11-12 14:21:47 +01:00
|
|
|
continue;
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-02-14 22:50:06 +01:00
|
|
|
if (area->advertise_passive_only && !circuit->is_passive) {
|
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Circuit is not passive, ignoring.",
|
|
|
|
area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
uint32_t metric = area->oldmetric
|
|
|
|
? circuit->metric[level - 1]
|
|
|
|
: circuit->te_metric[level - 1];
|
|
|
|
|
2022-06-18 20:37:14 +02:00
|
|
|
if (circuit->ip_router && circuit->ip_addrs->count > 0) {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
2004-09-10 22:48:21 +02:00
|
|
|
"ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
|
2015-11-12 14:21:47 +01:00
|
|
|
area->area_tag);
|
2017-07-05 18:37:36 +02:00
|
|
|
struct listnode *ipnode;
|
|
|
|
struct prefix_ipv4 *ipv4;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
|
2022-12-15 14:02:46 +01:00
|
|
|
ipv4))
|
|
|
|
lsp_build_internal_reach_ipv4(lsp, area, ipv4,
|
|
|
|
metric);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-06-18 20:37:14 +02:00
|
|
|
if (circuit->ipv6_router && circuit->ipv6_non_link->count > 0) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct listnode *ipnode;
|
|
|
|
struct prefix_ipv6 *ipv6;
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
|
2022-12-15 14:02:46 +01:00
|
|
|
ipnode, ipv6))
|
|
|
|
lsp_build_internal_reach_ipv6(lsp, area, ipv6,
|
|
|
|
metric);
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
switch (circuit->circ_type) {
|
2015-11-12 14:21:47 +01:00
|
|
|
case CIRCUIT_T_BROADCAST:
|
|
|
|
if (level & circuit->is_type) {
|
2017-07-05 18:37:36 +02:00
|
|
|
uint8_t *ne_id =
|
|
|
|
(level == IS_LEVEL_1)
|
|
|
|
? circuit->u.bc.l1_desig_is
|
|
|
|
: circuit->u.bc.l2_desig_is;
|
|
|
|
|
|
|
|
if (LSP_PSEUDO_ID(ne_id)) {
|
|
|
|
if (area->oldmetric) {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Adding DIS %pPN as old-style neighbor",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_add_oldstyle_reach(
|
|
|
|
lsp->tlvs, ne_id,
|
|
|
|
metric);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
if (area->newmetric)
|
2017-04-27 13:56:43 +02:00
|
|
|
tlvs_add_mt_bcast(
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->tlvs, circuit,
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
level, ne_id, metric);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
} else {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
|
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
break;
|
2017-07-05 18:37:36 +02:00
|
|
|
case CIRCUIT_T_P2P: {
|
|
|
|
struct isis_adjacency *nei = circuit->u.p2p.neighbor;
|
2018-03-05 21:01:21 +01:00
|
|
|
if (nei && nei->adj_state == ISIS_ADJ_UP
|
|
|
|
&& (level & nei->circuit_t)) {
|
2017-07-05 18:37:36 +02:00
|
|
|
uint8_t ne_id[7];
|
|
|
|
memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID(ne_id) = 0;
|
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->oldmetric) {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Adding old-style is reach for %pSY",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_tlvs_add_oldstyle_reach(
|
|
|
|
lsp->tlvs, ne_id, metric);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->newmetric) {
|
2018-05-23 15:37:45 +02:00
|
|
|
uint32_t neighbor_metric;
|
|
|
|
if (fabricd_tier(area) == 0) {
|
|
|
|
neighbor_metric = 0xffe;
|
|
|
|
} else {
|
|
|
|
neighbor_metric = metric;
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
tlvs_add_mt_p2p(lsp->tlvs, circuit,
|
isisd: Update TLVs processing for TE, RI & SR
In preparation to Segment Routing:
- Update the management of Traffic Engineering subTLVs to the new tlvs parser
- Add Router Capability TLV 242 as per RFC 4971 & 7981
- Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25
Modified files:
- isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
- isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
TE subTLVs, Router Capability TLV and SR subTLVs
- isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
- isis_te.[c,h]: remove all old TE structures and managment functions,
and add hook call to set local and remote IP addresses as wellas update TE
parameters
- isis_zebra.[c,h]: add hook call when new interface is up
- isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
- tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
2019-07-26 16:07:39 +02:00
|
|
|
ne_id, neighbor_metric);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
} else {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
|
|
|
"ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
|
|
|
|
area->area_tag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
} break;
|
2012-03-24 16:35:20 +01:00
|
|
|
case CIRCUIT_T_LOOPBACK:
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
|
|
|
default:
|
2004-09-10 22:48:21 +02:00
|
|
|
zlog_warn("lsp_area_create: unknown circuit type");
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_build_ext_reach(lsp, area);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_tlvs *tlvs = lsp->tlvs;
|
|
|
|
lsp->tlvs = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-16 19:17:10 +02:00
|
|
|
lsp_adjust_stream(lsp);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_pack_pdu(lsp);
|
|
|
|
size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
|
|
|
|
lsp_clear_data(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
|
|
|
|
if (!fragments) {
|
|
|
|
zlog_warn("BUG: could not fragment own LSP:");
|
|
|
|
log_multiline(LOG_WARNING, " ", "%s",
|
2022-02-24 11:31:18 +01:00
|
|
|
isis_format_tlvs(tlvs, NULL));
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_free_tlvs(tlvs);
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
isis_free_tlvs(tlvs);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-22 22:17:20 +02:00
|
|
|
bool fragment_overflow = false;
|
2017-07-05 18:37:36 +02:00
|
|
|
frag = lsp;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
|
|
|
|
if (node != listhead(fragments)) {
|
2017-09-22 22:17:20 +02:00
|
|
|
if (LSP_FRAGMENT(frag->hdr.lsp_id) == 255) {
|
|
|
|
if (!fragment_overflow) {
|
|
|
|
fragment_overflow = true;
|
|
|
|
zlog_warn(
|
|
|
|
"ISIS (%s): Too much information for 256 fragments",
|
|
|
|
area->area_tag);
|
|
|
|
}
|
|
|
|
isis_free_tlvs(tlvs);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
|
|
|
|
lsp, area, level);
|
2018-10-16 19:17:10 +02:00
|
|
|
lsp_adjust_stream(frag);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
frag->tlvs = tlvs;
|
2017-04-27 13:56:43 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&fragments);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
|
|
|
|
area->area_tag);
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-24 16:35:20 +01:00
|
|
|
* 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
int lsp_generate(struct isis_area *area, int level)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_lsp *oldlsp, *newlsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t seq_num = 0;
|
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
uint16_t rem_lifetime, refresh_time;
|
2022-10-13 01:03:29 +02:00
|
|
|
uint32_t overload_time;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((area == NULL) || (area->is_type & level) != level)
|
|
|
|
return ISIS_ERROR;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-02-16 00:42:09 +01:00
|
|
|
/* Check if config is still being processed */
|
2022-12-11 16:51:58 +01:00
|
|
|
if (event_is_scheduled(t_isis_cfg))
|
2023-02-16 00:42:09 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
|
2020-07-13 14:37:59 +02:00
|
|
|
|
|
|
|
memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-10-13 01:03:29 +02:00
|
|
|
/* Check if device should be overloaded on startup */
|
|
|
|
if (device_startup) {
|
|
|
|
overload_time = isis_restart_read_overload_time(area);
|
|
|
|
if (overload_time > 0) {
|
|
|
|
isis_area_overload_bit_set(area, true);
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, set_overload_on_start_timer,
|
|
|
|
area, overload_time,
|
|
|
|
&area->t_overload_on_startup_timer);
|
2022-10-13 01:03:29 +02:00
|
|
|
}
|
|
|
|
device_startup = false;
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* only builds the lsp if the area shares the level */
|
2019-02-04 01:22:03 +01:00
|
|
|
oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (oldlsp) {
|
|
|
|
/* FIXME: we should actually initiate a purge */
|
2017-07-05 18:37:36 +02:00
|
|
|
seq_num = oldlsp->hdr.seqno;
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_search_and_destroy(&area->lspdb[level - 1],
|
|
|
|
oldlsp->hdr.lsp_id);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
rem_lifetime = lsp_rem_lifetime(area, level);
|
2020-12-24 19:29:42 +01:00
|
|
|
newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
|
|
|
|
lsp_bits_generate(area->is_type, area->overload_bit,
|
|
|
|
area->attached_bit_send, area),
|
|
|
|
0, NULL, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
newlsp->area = area;
|
|
|
|
newlsp->own_lsp = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_insert(&area->lspdb[level - 1], newlsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
/* build_lsp_data (newlsp, area); */
|
|
|
|
lsp_build(newlsp, area);
|
|
|
|
/* time to calculate our checksum */
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_seqno_update(newlsp);
|
2015-11-10 18:43:34 +01:00
|
|
|
newlsp->last_generated = time(NULL);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(newlsp, NULL);
|
2018-11-23 21:36:26 +01:00
|
|
|
area->lsp_gen_count[level - 1]++;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(area->t_lsp_refresh[level - 1]);
|
2015-11-10 18:43:34 +01:00
|
|
|
area->lsp_regenerate_pending[level - 1] = 0;
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
|
|
|
|
refresh_time, &area->t_lsp_refresh[level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_UPDATE_PACKETS) {
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Upd (%s): Building L%d LSP %pLS, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
|
|
|
|
area->area_tag, level, newlsp->hdr.lsp_id,
|
|
|
|
newlsp->hdr.pdu_len, newlsp->hdr.seqno,
|
|
|
|
newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
|
|
|
|
refresh_time);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
|
|
|
|
area->area_tag, level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-11-14 15:28:55 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
/* send northbound notification */
|
2020-09-15 22:46:15 +02:00
|
|
|
isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
|
|
|
|
newlsp->last_generated);
|
2018-11-14 15:28:55 +01:00
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
* Search own LSPs, update holding time and flood
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
static int lsp_regenerate(struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
struct lspdb_head *head;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_lsp *lsp, *frag;
|
|
|
|
struct listnode *node;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
uint16_t rem_lifetime, refresh_time;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((area == NULL) || (area->is_type & level) != level)
|
|
|
|
return ISIS_ERROR;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
head = &area->lspdb[level - 1];
|
2003-12-23 09:09:43 +01:00
|
|
|
memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
|
2020-07-13 14:37:59 +02:00
|
|
|
memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(head, lspid);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!lsp) {
|
2018-09-13 21:34:28 +02:00
|
|
|
flog_err(EC_LIB_DEVELOPMENT,
|
2018-09-13 21:38:57 +02:00
|
|
|
"ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
|
|
|
|
area->area_tag, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
return ISIS_ERROR;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_clear_data(lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build(lsp, area);
|
|
|
|
rem_lifetime = lsp_rem_lifetime(area, level);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.rem_lifetime = rem_lifetime;
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->last_generated = time(NULL);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(lsp, NULL);
|
2018-11-23 21:36:26 +01:00
|
|
|
area->lsp_gen_count[level - 1]++;
|
2012-03-24 16:35:20 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
|
2018-11-09 16:38:38 +01:00
|
|
|
if (!frag->tlvs) {
|
|
|
|
/* Updating and flooding should only affect fragments
|
|
|
|
* carrying data
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-12-24 19:29:42 +01:00
|
|
|
frag->hdr.lsp_bits =
|
|
|
|
lsp_bits_generate(level, area->overload_bit,
|
|
|
|
area->attached_bit_send, area);
|
2012-03-24 16:35:20 +01:00
|
|
|
/* Set the lifetime values of all the fragments to the same
|
|
|
|
* value,
|
|
|
|
* so that no fragment expires before the lsp is refreshed.
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
frag->hdr.rem_lifetime = rem_lifetime;
|
2017-09-23 20:01:43 +02:00
|
|
|
frag->age_out = ZERO_AGE_LIFETIME;
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(frag, NULL);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_seqno_update(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_refresh, &area->lsp_refresh_arg[level - 1],
|
|
|
|
refresh_time, &area->t_lsp_refresh[level - 1]);
|
2015-11-10 18:43:34 +01:00
|
|
|
area->lsp_regenerate_pending[level - 1] = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_UPDATE_PACKETS) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Upd (%s): Refreshed our L%d LSP %pLS, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus refresh %hus",
|
|
|
|
area->area_tag, level, lsp->hdr.lsp_id,
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
|
|
|
|
lsp->hdr.rem_lifetime, refresh_time);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
|
|
|
|
area->area_tag, level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-24 16:35:20 +01:00
|
|
|
* Something has changed or periodic refresh -> regenerate LSP
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2022-03-01 22:18:12 +01:00
|
|
|
static void lsp_refresh(struct event *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct lsp_refresh_arg *arg = EVENT_ARG(thread);
|
2004-02-11 21:26:31 +01:00
|
|
|
|
2018-10-24 06:27:17 +02:00
|
|
|
assert(arg);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2018-10-24 06:27:17 +02:00
|
|
|
struct isis_area *area = arg->area;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
assert(area);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2018-10-24 06:27:17 +02:00
|
|
|
int level = arg->level;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2018-10-24 06:27:17 +02:00
|
|
|
area->t_lsp_refresh[level - 1] = NULL;
|
|
|
|
area->lsp_regenerate_pending[level - 1] = 0;
|
|
|
|
|
|
|
|
if ((area->is_type & level) == 0)
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2020-05-19 13:52:04 +02:00
|
|
|
/*
|
|
|
|
* Throttle regeneration of LSPs (but not when BFD signalled a 'down'
|
|
|
|
* message)
|
|
|
|
*/
|
|
|
|
if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL)
|
|
|
|
< 100000L
|
|
|
|
&& !(area->bfd_force_spf_refresh)) {
|
2018-10-24 07:19:22 +02:00
|
|
|
sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
|
|
|
|
area->area_tag, level);
|
|
|
|
_lsp_regenerate_schedule(area, level, 0, false,
|
|
|
|
__func__, __FILE__, __LINE__);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2018-10-24 07:19:22 +02:00
|
|
|
}
|
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
2018-10-24 06:27:17 +02:00
|
|
|
"ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
|
|
|
|
area->area_tag, level);
|
2022-02-23 01:04:25 +01:00
|
|
|
lsp_regenerate(area, level);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2018-10-24 05:38:53 +02:00
|
|
|
int _lsp_regenerate_schedule(struct isis_area *area, int level,
|
2018-10-24 07:19:22 +02:00
|
|
|
int all_pseudo, bool postpone,
|
|
|
|
const char *func, const char *file,
|
|
|
|
int line)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t id[ISIS_SYS_ID_LEN + 2];
|
2003-12-23 09:09:43 +01:00
|
|
|
time_t now, diff;
|
2015-11-10 18:43:34 +01:00
|
|
|
long timeout;
|
2012-03-24 16:35:20 +01:00
|
|
|
struct listnode *cnode;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
int lvl;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area == NULL)
|
|
|
|
return ISIS_ERROR;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs Caller: %s %s:%d",
|
2015-11-10 18:43:34 +01:00
|
|
|
area->area_tag, circuit_t2string(level),
|
2018-10-24 05:38:53 +02:00
|
|
|
all_pseudo ? "" : "not ",
|
|
|
|
func, file, line);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-07-13 14:37:59 +02:00
|
|
|
memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
|
2003-12-23 09:09:43 +01:00
|
|
|
now = time(NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
|
|
|
|
if (!((level & lvl) && (area->is_type & lvl)))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-24 07:19:22 +02:00
|
|
|
if (postpone) {
|
|
|
|
monotime(&area->last_lsp_refresh_event[lvl - 1]);
|
|
|
|
}
|
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Checking whether L%d needs to be scheduled",
|
|
|
|
area->area_tag, lvl);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-05-19 13:52:04 +02:00
|
|
|
if (area->lsp_regenerate_pending[lvl - 1]
|
|
|
|
&& !(area->bfd_signalled_down)) {
|
|
|
|
/*
|
|
|
|
* Note: in case of a BFD 'down' message the refresh is
|
|
|
|
* scheduled once again just to be sure
|
|
|
|
*/
|
2022-12-11 14:19:00 +01:00
|
|
|
struct timeval remain = event_timer_remain(
|
2015-11-10 18:43:34 +01:00
|
|
|
area->t_lsp_refresh[lvl - 1]);
|
|
|
|
sched_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"ISIS (%s): Regeneration is already pending, nothing todo. (Due in %lld.%03lld seconds)",
|
2015-11-10 18:43:34 +01:00
|
|
|
area->area_tag, (long long)remain.tv_sec,
|
|
|
|
(long long)remain.tv_usec / 1000);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(&area->lspdb[lvl - 1], id);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!lsp) {
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
|
|
|
|
area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
/*
|
|
|
|
* Throttle avoidance
|
|
|
|
*/
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
|
|
|
|
area->area_tag, (long long)lsp->last_generated,
|
|
|
|
(long long)now);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(area->t_lsp_refresh[lvl - 1]);
|
2004-09-10 22:48:21 +02:00
|
|
|
diff = now - lsp->last_generated;
|
2020-05-19 13:52:04 +02:00
|
|
|
if (diff < area->lsp_gen_interval[lvl - 1]
|
|
|
|
&& !(area->bfd_signalled_down)) {
|
2015-11-10 18:43:34 +01:00
|
|
|
timeout =
|
|
|
|
1000 * (area->lsp_gen_interval[lvl - 1] - diff);
|
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
|
|
|
|
area->area_tag, timeout);
|
2004-09-10 22:48:21 +02:00
|
|
|
} else {
|
2012-10-26 11:18:19 +02:00
|
|
|
/*
|
2020-05-19 13:52:04 +02:00
|
|
|
* Schedule LSP refresh ASAP
|
2012-10-26 11:18:19 +02:00
|
|
|
*/
|
2020-05-19 13:52:04 +02:00
|
|
|
if (area->bfd_signalled_down) {
|
|
|
|
sched_debug(
|
2021-03-21 00:52:38 +01:00
|
|
|
"ISIS (%s): Scheduling immediately due to BFD 'down' message.",
|
2020-05-19 13:52:04 +02:00
|
|
|
area->area_tag);
|
|
|
|
area->bfd_signalled_down = false;
|
|
|
|
area->bfd_force_spf_refresh = true;
|
2021-03-17 13:24:19 +01:00
|
|
|
timeout = 0;
|
2020-05-19 13:52:04 +02:00
|
|
|
} else {
|
2021-03-17 13:24:19 +01:00
|
|
|
int64_t time_since_last = monotime_since(
|
|
|
|
&area->last_lsp_refresh_event[lvl - 1],
|
|
|
|
NULL);
|
|
|
|
timeout = time_since_last < 100000L
|
|
|
|
? (100000L - time_since_last)/1000
|
|
|
|
: 0;
|
|
|
|
if (timeout > 0)
|
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
|
|
|
|
area->area_tag, timeout);
|
|
|
|
else
|
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
|
|
|
|
area->area_tag);
|
2020-05-19 13:52:04 +02:00
|
|
|
}
|
2015-11-10 18:43:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
area->lsp_regenerate_pending[lvl - 1] = 1;
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer_msec(master, lsp_refresh,
|
|
|
|
&area->lsp_refresh_arg[lvl - 1], timeout,
|
|
|
|
&area->t_lsp_refresh[lvl - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (all_pseudo) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
|
|
|
|
lsp_regenerate_schedule_pseudo(circuit, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
return ISIS_OK;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Funcs for pseudonode LSPs
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
|
|
|
|
int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_adjacency *adj;
|
|
|
|
struct list *adj_list;
|
2015-11-12 14:21:47 +01:00
|
|
|
struct listnode *node;
|
2005-09-26 19:39:48 +02:00
|
|
|
struct isis_area *area = circuit->area;
|
2021-06-30 17:23:56 +02:00
|
|
|
uint16_t mtid;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_clear_data(lsp);
|
|
|
|
lsp->tlvs = isis_alloc_tlvs();
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Constructing pseudo LSP %pLS for interface %s level %d",
|
|
|
|
area->area_tag, lsp->hdr.lsp_id, circuit->interface->name,
|
|
|
|
level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
lsp->level = level;
|
2015-11-12 14:21:47 +01:00
|
|
|
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
|
2020-12-24 19:29:42 +01:00
|
|
|
lsp->hdr.lsp_bits = lsp_bits_generate(
|
|
|
|
level, 0, circuit->area->attached_bit_send, area);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
/*
|
|
|
|
* add self to IS neighbours
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
|
|
|
|
|
2020-07-13 14:37:59 +02:00
|
|
|
memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
|
2017-07-05 18:37:36 +02:00
|
|
|
LSP_PSEUDO_ID(ne_id) = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (circuit->area->oldmetric) {
|
|
|
|
isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
|
2023-01-26 17:47:04 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %pPN as old-style neighbor (self)",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
if (circuit->area->newmetric) {
|
2021-06-30 17:23:56 +02:00
|
|
|
if (area_is_mt(circuit->area))
|
|
|
|
mtid = ISIS_MT_IPV4_UNICAST;
|
|
|
|
else
|
|
|
|
mtid = ISIS_MT_DISABLE;
|
|
|
|
isis_tlvs_add_extended_reach(lsp->tlvs, mtid, ne_id, 0, NULL);
|
2023-01-26 17:47:04 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %pPN as te-style neighbor (self)",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
adj_list = list_new();
|
|
|
|
isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
|
2017-07-05 18:37:36 +02:00
|
|
|
if (!(adj->level & level)) {
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Ignoring neighbor %pSY, level does not intersect",
|
|
|
|
area->area_tag, adj->sysid);
|
2017-07-05 18:37:36 +02:00
|
|
|
continue;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (!(level == IS_LEVEL_1
|
|
|
|
&& adj->sys_type == ISIS_SYSTYPE_L1_IS)
|
|
|
|
&& !(level == IS_LEVEL_1
|
|
|
|
&& adj->sys_type == ISIS_SYSTYPE_L2_IS
|
|
|
|
&& adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
|
|
|
|
&& !(level == IS_LEVEL_2
|
|
|
|
&& adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
|
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Ignoring neighbor %pSY, level does not match",
|
|
|
|
area->area_tag, adj->sysid);
|
2017-07-05 18:37:36 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
if (circuit->area->oldmetric) {
|
|
|
|
isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
|
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Adding %pPN as old-style neighbor (peer)",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-05 18:37:36 +02:00
|
|
|
}
|
|
|
|
if (circuit->area->newmetric) {
|
|
|
|
isis_tlvs_add_extended_reach(lsp->tlvs,
|
|
|
|
ISIS_MT_IPV4_UNICAST,
|
2020-08-10 17:49:47 +02:00
|
|
|
ne_id, 0, NULL);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS (%s): Adding %pPN as te-style neighbor (peer)",
|
|
|
|
area->area_tag, ne_id);
|
2017-07-05 18:37:36 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&adj_list);
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
|
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
struct lspdb_head *head = &circuit->area->lspdb[level - 1];
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_lsp *lsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
uint16_t rem_lifetime, refresh_time;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((circuit->is_type & level) != level
|
|
|
|
|| (circuit->state != C_STATE_UP)
|
|
|
|
|| (circuit->circ_type != CIRCUIT_T_BROADCAST)
|
|
|
|
|| (circuit->u.bc.is_dr[level - 1] == 0))
|
|
|
|
return ISIS_ERROR;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-10-09 14:00:44 +02:00
|
|
|
memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
LSP_FRAGMENT(lsp_id) = 0;
|
|
|
|
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/*
|
|
|
|
* If for some reason have a pseudo LSP in the db already -> regenerate
|
|
|
|
*/
|
2019-02-04 01:22:03 +01:00
|
|
|
if (lsp_search(head, lsp_id))
|
2012-03-24 16:35:20 +01:00
|
|
|
return lsp_regenerate_schedule_pseudo(circuit, level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
rem_lifetime = lsp_rem_lifetime(circuit->area, level);
|
|
|
|
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
|
2020-12-24 19:29:42 +01:00
|
|
|
lsp_bits_generate(circuit->area->is_type, 0,
|
|
|
|
circuit->area->attached_bit_send,
|
|
|
|
circuit->area),
|
|
|
|
0, NULL, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->area = circuit->area;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build_pseudo(lsp, circuit, level);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_pack_pdu(lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->own_lsp = 1;
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_insert(head, lsp);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(lsp, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
circuit->lsp_regenerate_pending[level - 1] = 0;
|
|
|
|
if (level == IS_LEVEL_1)
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
|
|
|
|
refresh_time,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
else if (level == IS_LEVEL_2)
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
|
|
|
|
refresh_time,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_UPDATE_PACKETS) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Upd (%s): Built L%d Pseudo LSP %pLS, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
|
|
|
|
circuit->area->area_tag, level, lsp->hdr.lsp_id,
|
|
|
|
lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.rem_lifetime, refresh_time);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-02-04 01:22:03 +01:00
|
|
|
struct lspdb_head *head = &circuit->area->lspdb[level - 1];
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_lsp *lsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
uint16_t rem_lifetime, refresh_time;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((circuit->is_type & level) != level
|
|
|
|
|| (circuit->state != C_STATE_UP)
|
|
|
|
|| (circuit->circ_type != CIRCUIT_T_BROADCAST)
|
|
|
|
|| (circuit->u.bc.is_dr[level - 1] == 0))
|
|
|
|
return ISIS_ERROR;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-10-09 14:00:44 +02:00
|
|
|
memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT(lsp_id) = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(head, lsp_id);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!lsp) {
|
2018-09-13 21:34:28 +02:00
|
|
|
flog_err(EC_LIB_DEVELOPMENT,
|
2023-01-26 17:47:04 +01:00
|
|
|
"lsp_regenerate_pseudo: no l%d LSP %pLS found!", level,
|
|
|
|
lsp_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
return ISIS_ERROR;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
rem_lifetime = lsp_rem_lifetime(circuit->area, level);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.rem_lifetime = rem_lifetime;
|
|
|
|
lsp_build_pseudo(lsp, circuit, level);
|
|
|
|
lsp_inc_seqno(lsp, 0);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->last_generated = time(NULL);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(lsp, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
|
|
|
|
if (level == IS_LEVEL_1)
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_l1_refresh_pseudo, circuit,
|
|
|
|
refresh_time,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
else if (level == IS_LEVEL_2)
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_l2_refresh_pseudo, circuit,
|
|
|
|
refresh_time,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_UPDATE_PACKETS) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Upd (%s): Refreshed L%d Pseudo LSP %pLS, len %hu, seq 0x%08x, cksum 0x%04hx, lifetime %hus, refresh %hus",
|
|
|
|
circuit->area->area_tag, level, lsp->hdr.lsp_id,
|
|
|
|
lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->hdr.rem_lifetime, refresh_time);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/*
|
|
|
|
* Something has changed or periodic refresh -> regenerate pseudo LSP
|
|
|
|
*/
|
2022-03-01 22:18:12 +01:00
|
|
|
static void lsp_l1_refresh_pseudo(struct event *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_circuit *circuit;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t id[ISIS_SYS_ID_LEN + 2];
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
circuit = EVENT_ARG(thread);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2004-09-10 23:19:13 +02:00
|
|
|
circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
|
2012-03-24 16:35:20 +01:00
|
|
|
circuit->lsp_regenerate_pending[0] = 0;
|
2004-09-10 23:19:13 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((circuit->u.bc.is_dr[0] == 0)
|
|
|
|
|| (circuit->is_type & IS_LEVEL_1) == 0) {
|
2020-10-09 14:00:44 +02:00
|
|
|
memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
LSP_PSEUDO_ID(id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT(id) = 0;
|
|
|
|
lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2022-02-23 01:04:25 +01:00
|
|
|
lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2022-03-01 22:18:12 +01:00
|
|
|
static void lsp_l2_refresh_pseudo(struct event *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_circuit *circuit;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t id[ISIS_SYS_ID_LEN + 2];
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
circuit = EVENT_ARG(thread);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2004-09-10 23:19:13 +02:00
|
|
|
circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
|
2012-03-24 16:35:20 +01:00
|
|
|
circuit->lsp_regenerate_pending[1] = 0;
|
2004-09-10 23:19:13 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((circuit->u.bc.is_dr[1] == 0)
|
|
|
|
|| (circuit->is_type & IS_LEVEL_2) == 0) {
|
2020-10-09 14:00:44 +02:00
|
|
|
memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
LSP_PSEUDO_ID(id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT(id) = 0;
|
|
|
|
lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2022-02-23 01:04:25 +01:00
|
|
|
lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
|
2012-03-24 16:35:20 +01:00
|
|
|
time_t now, diff;
|
2015-11-10 18:43:34 +01:00
|
|
|
long timeout;
|
2012-03-24 16:35:20 +01:00
|
|
|
int lvl;
|
2015-11-10 18:43:34 +01:00
|
|
|
struct isis_area *area = circuit->area;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-13 19:27:54 +01:00
|
|
|
if (circuit->circ_type != CIRCUIT_T_BROADCAST
|
2012-03-24 16:35:20 +01:00
|
|
|
|| circuit->state != C_STATE_UP)
|
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
|
|
|
|
area->area_tag, circuit_t2string(level),
|
|
|
|
circuit->interface->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-07-13 14:37:59 +02:00
|
|
|
memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT(lsp_id) = 0;
|
|
|
|
now = time(NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
|
|
|
|
area->area_tag, lvl);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!((level & lvl) && (circuit->is_type & lvl))) {
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug("ISIS (%s): Level is not active on circuit",
|
|
|
|
area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
if (circuit->u.bc.is_dr[lvl - 1] == 0) {
|
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): This IS is not DR, nothing to do.",
|
|
|
|
area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
if (circuit->lsp_regenerate_pending[lvl - 1]) {
|
2022-12-11 14:19:00 +01:00
|
|
|
struct timeval remain = event_timer_remain(
|
2015-11-10 18:43:34 +01:00
|
|
|
circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
|
|
|
sched_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"ISIS (%s): Regenerate is already pending, nothing todo. (Due in %lld.%03lld seconds)",
|
2015-11-10 18:43:34 +01:00
|
|
|
area->area_tag, (long long)remain.tv_sec,
|
|
|
|
(long long)remain.tv_usec / 1000);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!lsp) {
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
|
|
|
|
area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/*
|
|
|
|
* Throttle avoidance
|
|
|
|
*/
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
|
|
|
|
area->area_tag, (long long)lsp->last_generated,
|
|
|
|
(long long)now);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
diff = now - lsp->last_generated;
|
|
|
|
if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
|
2017-07-22 14:52:33 +02:00
|
|
|
timeout =
|
|
|
|
1000 * (circuit->area->lsp_gen_interval[lvl - 1]
|
|
|
|
- diff);
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug(
|
|
|
|
"ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
|
|
|
|
area->area_tag, timeout);
|
2012-03-24 16:35:20 +01:00
|
|
|
} else {
|
2015-11-10 18:43:34 +01:00
|
|
|
timeout = 100;
|
|
|
|
sched_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms.",
|
2015-11-10 18:43:34 +01:00
|
|
|
area->area_tag, timeout);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
circuit->lsp_regenerate_pending[lvl - 1] = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
if (lvl == IS_LEVEL_1) {
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer_msec(
|
2017-04-25 00:33:25 +02:00
|
|
|
master, lsp_l1_refresh_pseudo, circuit, timeout,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
2015-11-10 18:43:34 +01:00
|
|
|
} else if (lvl == IS_LEVEL_2) {
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer_msec(
|
2017-04-25 00:33:25 +02:00
|
|
|
master, lsp_l2_refresh_pseudo, circuit, timeout,
|
|
|
|
&circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return ISIS_OK;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Walk through LSPs for an area
|
|
|
|
* - set remaining lifetime
|
|
|
|
*/
|
2022-03-01 22:18:12 +01:00
|
|
|
void lsp_tick(struct event *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_area *area;
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
int level;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t rem_lifetime;
|
fabricd: adjacency formation optimization as per section 2.4
OpenFabric changes IS-IS's initial database synchronization. While
regular IS-IS will simultaneuously exchange LSPs with all neighboring
routers during startup, this is considered too much churn for a densely
connected fabric.
To mitigate this, OpenFabric prescribes that a router should only
bring up an adjacency with a single neighbor and perform a full
synchronization with that neighbor, before bringing up further
adjacencies.
This is implemented by having a field `initial_sync_state` in the
fabricd datastructure which tracks whether an initial sync is still
pending, currently in progress, or complete.
When an initial sync is pending, the state will transition to the
in-progress state when the first IIH is received.
During this state, all IIHs from other routers are ignored. Any
IIHs transmitted on any link other than the one to the router with
which we are performing the initial sync will always report the far
end as DOWN in their threeway handshake state, avoiding the formation of
additional adjacencies.
The state will be left if all the SRM and SSN flags on the
initial-sync circuit are cleared (meaning that initial sync has
completed). This is checked in `lsp_tick`. When this condition occurrs,
we progress to the initial-sync-complete state, allowing other
adjacencies to form.
The state can also be left if the initial synchronization is taking too
long to succeed, for whatever reason. In that case, we fall back to the
initial-sync-pending state and will reattempt initial synchronization
with a different neighbor.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-04-02 17:55:26 +02:00
|
|
|
bool fabricd_sync_incomplete = false;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
area = EVENT_ARG(thread);
|
2003-12-23 09:09:43 +01:00
|
|
|
assert(area);
|
2004-09-10 23:19:13 +02:00
|
|
|
area->t_tick = NULL;
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, lsp_tick, area, 1, &area->t_tick);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
fabricd: adjacency formation optimization as per section 2.4
OpenFabric changes IS-IS's initial database synchronization. While
regular IS-IS will simultaneuously exchange LSPs with all neighboring
routers during startup, this is considered too much churn for a densely
connected fabric.
To mitigate this, OpenFabric prescribes that a router should only
bring up an adjacency with a single neighbor and perform a full
synchronization with that neighbor, before bringing up further
adjacencies.
This is implemented by having a field `initial_sync_state` in the
fabricd datastructure which tracks whether an initial sync is still
pending, currently in progress, or complete.
When an initial sync is pending, the state will transition to the
in-progress state when the first IIH is received.
During this state, all IIHs from other routers are ignored. Any
IIHs transmitted on any link other than the one to the router with
which we are performing the initial sync will always report the far
end as DOWN in their threeway handshake state, avoiding the formation of
additional adjacencies.
The state will be left if all the SRM and SSN flags on the
initial-sync circuit are cleared (meaning that initial sync has
completed). This is checked in `lsp_tick`. When this condition occurrs,
we progress to the initial-sync-complete state, allowing other
adjacencies to form.
The state can also be left if the initial synchronization is taking too
long to succeed, for whatever reason. In that case, we fall back to the
initial-sync-pending state and will reattempt initial synchronization
with a different neighbor.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-04-02 17:55:26 +02:00
|
|
|
struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
* Remove LSPs which have aged out
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
for (level = 0; level < ISIS_LEVELS; level++) {
|
2019-02-04 01:22:03 +01:00
|
|
|
struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
|
2019-05-20 23:52:16 +02:00
|
|
|
frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
|
2019-02-04 01:22:03 +01:00
|
|
|
/*
|
|
|
|
* The lsp rem_lifetime is kept at 0 for MaxAge
|
|
|
|
* or
|
|
|
|
* ZeroAgeLifetime depending on explicit purge
|
|
|
|
* or
|
|
|
|
* natural age out. So schedule spf only once
|
|
|
|
* when
|
|
|
|
* the first time rem_lifetime becomes 0.
|
|
|
|
*/
|
|
|
|
rem_lifetime = lsp->hdr.rem_lifetime;
|
|
|
|
lsp_set_time(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
/*
|
|
|
|
* Schedule may run spf which should be done
|
|
|
|
* only after
|
|
|
|
* the lsp rem_lifetime becomes 0 for the first
|
|
|
|
* time.
|
|
|
|
* ISO 10589 - 7.3.16.4 first paragraph.
|
|
|
|
*/
|
|
|
|
if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
|
|
|
|
/* 7.3.16.4 a) set SRM flags on all */
|
|
|
|
/* 7.3.16.4 b) retain only the header */
|
|
|
|
if (lsp->area->purge_originator)
|
|
|
|
lsp_purge(lsp, lsp->level, NULL);
|
|
|
|
else
|
|
|
|
lsp_flood(lsp, NULL);
|
|
|
|
/* 7.3.16.4 c) record the time to purge
|
|
|
|
* FIXME */
|
|
|
|
isis_spf_schedule(lsp->area, lsp->level);
|
2021-06-22 19:59:02 +02:00
|
|
|
isis_te_lsp_event(lsp, LSP_TICK);
|
2019-02-04 01:22:03 +01:00
|
|
|
}
|
2019-02-18 21:34:06 +01:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
if (lsp->age_out == 0) {
|
|
|
|
zlog_debug(
|
2023-01-26 17:47:04 +01:00
|
|
|
"ISIS-Upd (%s): L%u LSP %pLS seq 0x%08x aged out",
|
2019-02-04 01:22:03 +01:00
|
|
|
area->area_tag, lsp->level,
|
2023-01-26 17:47:04 +01:00
|
|
|
lsp->hdr.lsp_id, lsp->hdr.seqno);
|
2019-02-04 01:22:03 +01:00
|
|
|
|
|
|
|
/* if we're aging out fragment 0, lsp_destroy()
|
|
|
|
* below will delete all other fragments too,
|
|
|
|
* so we need to skip over those
|
|
|
|
*/
|
|
|
|
if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
|
|
|
|
while (next &&
|
|
|
|
!memcmp(next->hdr.lsp_id,
|
|
|
|
lsp->hdr.lsp_id,
|
|
|
|
ISIS_SYS_ID_LEN + 1))
|
|
|
|
next = lspdb_next(
|
|
|
|
&area->lspdb[level],
|
|
|
|
next);
|
|
|
|
|
|
|
|
lspdb_del(&area->lspdb[level], lsp);
|
|
|
|
lsp_destroy(lsp);
|
|
|
|
lsp = NULL;
|
|
|
|
}
|
fabricd: adjacency formation optimization as per section 2.4
OpenFabric changes IS-IS's initial database synchronization. While
regular IS-IS will simultaneuously exchange LSPs with all neighboring
routers during startup, this is considered too much churn for a densely
connected fabric.
To mitigate this, OpenFabric prescribes that a router should only
bring up an adjacency with a single neighbor and perform a full
synchronization with that neighbor, before bringing up further
adjacencies.
This is implemented by having a field `initial_sync_state` in the
fabricd datastructure which tracks whether an initial sync is still
pending, currently in progress, or complete.
When an initial sync is pending, the state will transition to the
in-progress state when the first IIH is received.
During this state, all IIHs from other routers are ignored. Any
IIHs transmitted on any link other than the one to the router with
which we are performing the initial sync will always report the far
end as DOWN in their threeway handshake state, avoiding the formation of
additional adjacencies.
The state will be left if all the SRM and SSN flags on the
initial-sync circuit are cleared (meaning that initial sync has
completed). This is checked in `lsp_tick`. When this condition occurrs,
we progress to the initial-sync-complete state, allowing other
adjacencies to form.
The state can also be left if the initial synchronization is taking too
long to succeed, for whatever reason. In that case, we fall back to the
initial-sync-pending state and will reattempt initial synchronization
with a different neighbor.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-04-02 17:55:26 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
if (fabricd_init_c && lsp) {
|
|
|
|
fabricd_sync_incomplete |=
|
|
|
|
ISIS_CHECK_FLAG(lsp->SSNflags,
|
|
|
|
fabricd_init_c);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
if (fabricd_init_c
|
|
|
|
&& !fabricd_sync_incomplete
|
|
|
|
&& !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
|
fabricd: adjacency formation optimization as per section 2.4
OpenFabric changes IS-IS's initial database synchronization. While
regular IS-IS will simultaneuously exchange LSPs with all neighboring
routers during startup, this is considered too much churn for a densely
connected fabric.
To mitigate this, OpenFabric prescribes that a router should only
bring up an adjacency with a single neighbor and perform a full
synchronization with that neighbor, before bringing up further
adjacencies.
This is implemented by having a field `initial_sync_state` in the
fabricd datastructure which tracks whether an initial sync is still
pending, currently in progress, or complete.
When an initial sync is pending, the state will transition to the
in-progress state when the first IIH is received.
During this state, all IIHs from other routers are ignored. Any
IIHs transmitted on any link other than the one to the router with
which we are performing the initial sync will always report the far
end as DOWN in their threeway handshake state, avoiding the formation of
additional adjacencies.
The state will be left if all the SRM and SSN flags on the
initial-sync circuit are cleared (meaning that initial sync has
completed). This is checked in `lsp_tick`. When this condition occurrs,
we progress to the initial-sync-complete state, allowing other
adjacencies to form.
The state can also be left if the initial synchronization is taking too
long to succeed, for whatever reason. In that case, we fall back to the
initial-sync-pending state and will reattempt initial synchronization
with a different neighbor.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-04-02 17:55:26 +02:00
|
|
|
fabricd_initial_sync_finish(area);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!lsp)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
lsp_purge(lsp, level, NULL);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Purge own LSP that is received and we don't have.
|
|
|
|
* -> Do as in 7.3.16.4
|
|
|
|
*/
|
2017-07-05 18:37:36 +02:00
|
|
|
void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
|
2004-09-10 22:48:21 +02:00
|
|
|
struct isis_area *area)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* We need to create the LSP to be purged
|
|
|
|
*/
|
2005-09-01 19:52:33 +02:00
|
|
|
lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->area = area;
|
2015-11-10 18:21:44 +01:00
|
|
|
lsp->level = level;
|
2018-10-16 19:17:10 +02:00
|
|
|
lsp_adjust_stream(lsp);
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp->age_out = ZERO_AGE_LIFETIME;
|
2018-11-24 00:36:37 +01:00
|
|
|
lsp->area->lsp_purge_count[level - 1]++;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
|
|
|
|
lsp->hdr.rem_lifetime = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-31 15:14:26 +02:00
|
|
|
lsp_purge_add_poi(lsp, NULL);
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
lsp_pack_pdu(lsp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-04 01:22:03 +01:00
|
|
|
lsp_insert(&area->lspdb[lsp->level - 1], lsp);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
lsp_flood(lsp, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
|
|
|
|
assert(lsp);
|
|
|
|
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
if (!lsp->area)
|
|
|
|
return;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
struct list *circuit_list = lsp->area->circuit_list;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
|
|
|
|
if (set) {
|
|
|
|
isis_tx_queue_add(circuit->tx_queue, lsp,
|
|
|
|
TX_LSP_NORMAL);
|
|
|
|
} else {
|
|
|
|
isis_tx_queue_del(circuit->tx_queue, lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
|
2018-11-16 16:31:37 +01:00
|
|
|
void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
|
|
|
|
const char *func, const char *file, int line)
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
{
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_FLOODING) {
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug("Flooding LSP %pLS%s%s (From %s %s:%d)",
|
|
|
|
lsp->hdr.lsp_id, circuit ? " except on " : "",
|
|
|
|
circuit ? circuit->interface->name : "", func, file,
|
|
|
|
line);
|
2018-11-16 16:31:37 +01:00
|
|
|
}
|
|
|
|
|
2018-11-09 16:40:17 +01:00
|
|
|
if (!fabricd)
|
2018-05-10 17:40:04 +02:00
|
|
|
lsp_set_all_srmflags(lsp, true);
|
2018-11-09 16:40:17 +01:00
|
|
|
else
|
2018-11-23 03:13:56 +01:00
|
|
|
fabricd_lsp_flood(lsp, circuit);
|
2018-11-09 16:40:17 +01:00
|
|
|
|
|
|
|
if (circuit)
|
|
|
|
isis_tx_queue_del(circuit->tx_queue, lsp);
|
fabricd: reimplement LSP transmission logic
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.
This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.
To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.
This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
2018-05-10 17:37:05 +02:00
|
|
|
}
|
2018-09-27 14:23:06 +02:00
|
|
|
|
|
|
|
static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
|
|
|
|
{
|
|
|
|
lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
|
2021-01-30 01:36:22 +01:00
|
|
|
|
|
|
|
/* when an adjacency state changes determine if we need to
|
|
|
|
* change attach_bits in other area's LSPs
|
|
|
|
*/
|
|
|
|
isis_reset_attach_bit(adj);
|
|
|
|
|
2018-09-27 14:23:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-21 02:27:56 +02:00
|
|
|
/*
|
|
|
|
* Iterate over all IP reachability TLVs in a LSP (all fragments) of the given
|
|
|
|
* address-family and MT-ID.
|
|
|
|
*/
|
|
|
|
int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
|
|
|
|
lsp_ip_reach_iter_cb cb, void *arg)
|
|
|
|
{
|
|
|
|
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
|
|
|
|
struct isis_lsp *frag;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
/* Parse LSP */
|
2020-08-21 02:27:56 +02:00
|
|
|
if (lsp->tlvs) {
|
|
|
|
if (!fabricd && !pseudo_lsp && family == AF_INET
|
|
|
|
&& mtid == ISIS_MT_IPV4_UNICAST) {
|
|
|
|
struct isis_item_list *reachs[] = {
|
|
|
|
&lsp->tlvs->oldstyle_ip_reach,
|
|
|
|
&lsp->tlvs->oldstyle_ip_reach_ext};
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < array_size(reachs); i++) {
|
|
|
|
struct isis_oldstyle_ip_reach *r;
|
|
|
|
|
|
|
|
for (r = (struct isis_oldstyle_ip_reach *)
|
|
|
|
reachs[i]
|
|
|
|
->head;
|
|
|
|
r; r = r->next) {
|
|
|
|
bool external = i ? true : false;
|
|
|
|
|
|
|
|
if ((*cb)((struct prefix *)&r->prefix,
|
|
|
|
r->metric, external, NULL,
|
|
|
|
arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pseudo_lsp && family == AF_INET) {
|
|
|
|
struct isis_item_list *ipv4_reachs;
|
|
|
|
|
|
|
|
if (mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
ipv4_reachs = &lsp->tlvs->extended_ip_reach;
|
|
|
|
else
|
|
|
|
ipv4_reachs = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->mt_ip_reach, mtid);
|
|
|
|
|
|
|
|
struct isis_extended_ip_reach *r;
|
|
|
|
for (r = ipv4_reachs ? (struct isis_extended_ip_reach *)
|
|
|
|
ipv4_reachs->head
|
|
|
|
: NULL;
|
|
|
|
r; r = r->next) {
|
|
|
|
if ((*cb)((struct prefix *)&r->prefix,
|
|
|
|
r->metric, false, r->subtlvs, arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pseudo_lsp && family == AF_INET6) {
|
|
|
|
struct isis_item_list *ipv6_reachs;
|
|
|
|
struct isis_ipv6_reach *r;
|
|
|
|
|
|
|
|
if (mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
ipv6_reachs = &lsp->tlvs->ipv6_reach;
|
|
|
|
else
|
|
|
|
ipv6_reachs = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->mt_ipv6_reach, mtid);
|
|
|
|
|
|
|
|
for (r = ipv6_reachs ? (struct isis_ipv6_reach *)
|
|
|
|
ipv6_reachs->head
|
|
|
|
: NULL;
|
|
|
|
r; r = r->next) {
|
|
|
|
if ((*cb)((struct prefix *)&r->prefix,
|
|
|
|
r->metric, r->external, r->subtlvs,
|
|
|
|
arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
/* Parse LSP fragments if it is not a fragment itself */
|
|
|
|
if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
|
|
|
|
if (!frag->tlvs)
|
|
|
|
continue;
|
2020-08-21 02:27:56 +02:00
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
|
|
|
|
arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
2020-08-21 02:27:56 +02:00
|
|
|
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over all IS reachability TLVs in a LSP (all fragments) of the given
|
|
|
|
* MT-ID.
|
|
|
|
*/
|
|
|
|
int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
|
|
|
|
lsp_is_reach_iter_cb cb, void *arg)
|
|
|
|
{
|
|
|
|
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
|
|
|
|
struct isis_lsp *frag;
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_item *head;
|
|
|
|
struct isis_item_list *te_neighs;
|
|
|
|
|
|
|
|
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
/* Parse LSP */
|
2020-08-21 02:27:56 +02:00
|
|
|
if (lsp->tlvs) {
|
|
|
|
if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) {
|
|
|
|
head = lsp->tlvs->oldstyle_reach.head;
|
|
|
|
for (struct isis_oldstyle_reach *reach =
|
|
|
|
(struct isis_oldstyle_reach *)head;
|
|
|
|
reach; reach = reach->next) {
|
|
|
|
if ((*cb)(reach->id, reach->metric, true, NULL,
|
|
|
|
arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
te_neighs = &lsp->tlvs->extended_reach;
|
|
|
|
else
|
|
|
|
te_neighs =
|
|
|
|
isis_get_mt_items(&lsp->tlvs->mt_reach, mtid);
|
|
|
|
if (te_neighs) {
|
|
|
|
head = te_neighs->head;
|
|
|
|
for (struct isis_extended_reach *reach =
|
|
|
|
(struct isis_extended_reach *)head;
|
|
|
|
reach; reach = reach->next) {
|
|
|
|
if ((*cb)(reach->id, reach->metric, false,
|
|
|
|
reach->subtlvs, arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
/* Parse LSP fragments if it not a fragment itself. */
|
|
|
|
if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
|
|
|
|
if (!frag->tlvs)
|
|
|
|
continue;
|
2020-08-21 02:27:56 +02:00
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
if (isis_lsp_iterate_is_reach(frag, mtid, cb, arg)
|
|
|
|
== LSP_ITER_STOP)
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
2020-08-21 02:27:56 +02:00
|
|
|
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2018-09-27 14:23:06 +02:00
|
|
|
void lsp_init(void)
|
|
|
|
{
|
2022-09-27 20:09:21 +02:00
|
|
|
device_startup = true;
|
2018-09-27 14:23:06 +02:00
|
|
|
hook_register(isis_adj_state_change_hook,
|
|
|
|
lsp_handle_adj_state_change);
|
|
|
|
}
|