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
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
2015-11-12 14:24:22 +01:00
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
2003-12-23 09:09:43 +01:00
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2005-05-03 11:27:23 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#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"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
#include "isisd/dict.h"
|
|
|
|
#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_tlv.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"
|
2016-04-19 19:03:05 +02:00
|
|
|
#include "isisd/isis_te.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-24 12:45:28 +02:00
|
|
|
/* staticly assigned vars for printing purposes */
|
|
|
|
char lsp_bits_string[200]; /* FIXME: enough ? */
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static int lsp_l1_refresh (struct thread *thread);
|
|
|
|
static int lsp_l2_refresh (struct thread *thread);
|
|
|
|
static int lsp_l1_refresh_pseudo (struct thread *thread);
|
|
|
|
static int lsp_l2_refresh_pseudo (struct thread *thread);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
|
|
|
lsp_id_cmp (u_char * id1, u_char * id2)
|
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
dict_t *
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_db_init (void)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dict_t *dict;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return dict;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_lsp *
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_search (u_char * id, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *node;
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2003-12-23 09:09:43 +01:00
|
|
|
dnode_t *dn;
|
|
|
|
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug ("searching db");
|
2004-09-10 22:48:21 +02:00
|
|
|
for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
|
2004-12-24 01:14:50 +01:00
|
|
|
dnode_get (dn));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME DEBUG */
|
|
|
|
|
|
|
|
node = dict_lookup (lspdb, id);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (node)
|
2004-09-10 22:48:21 +02:00
|
|
|
return (struct isis_lsp *) dnode_get (node);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_clear_data (struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
if (!lsp)
|
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (lsp->tlv_data.hostname)
|
|
|
|
isis_dynhn_remove (lsp->lsp_header->lsp_id);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->own_lsp)
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.nlpids)
|
2012-03-24 16:35:20 +01:00
|
|
|
XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->tlv_data.hostname)
|
2012-03-24 16:35:20 +01:00
|
|
|
XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
|
|
|
|
if (lsp->tlv_data.router_id)
|
|
|
|
XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
free_tlvs (&lsp->tlv_data);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_destroy (struct isis_lsp *lsp)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
struct listnode *cnode, *lnode, *lnnode;
|
|
|
|
struct isis_lsp *lsp_in_list;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (!lsp)
|
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
isisd: Segmentation fault on isis daemon fixes
I have a fix for 2 segmentation fault scenarios on the isis daemon:
1. When running a command "isis passive" on an interface in the
following context:
"end"
"configure terminal "
"interface dummy0"
"isis passive"
The trace back collected:
isis_adjacency.c:521
family=2,
root_sysid=0x20aee6d0 "", parent=0x20af4d68) at isis_spf.c:999
sysid=0x20aee6d0 "")
at isis_spf.c:1217
isis_spf.c:1372
isis_lsp.c:416
isis_lsp.c:1660
isis_main.c:368
The fix location:
file name: isisd/isis_adjacency.c
routine name: isis_adj_build_up_list
2. When deleting the existing isis router instance:
"end"
"configure terminal "
"no router isis DEAD"
The fix location:
isisd/isis_events.c, routine circuit_resign_level
isisd/isis_lsp.c, routine lsp_destroy
isisd/isis_route.c, isis_route_validate
The trace back collection:
"DEAD") at isisd.c:252
argc=1, argv=0xbfc39054) at isisd.c:1520
vty=0x20d6f528, cmd=0x0) at command.c:2121
cmd=0x0, vtysh=0) at command.c:2155
isis DEAD") at vty.c:433
isis_main.c:368
and
"DEAD") at isisd.c:260
argc=1, argv=0xbfd6cf54) at isisd.c:1520
vty=0x208cb528, cmd=0x0) at command.c:2121
cmd=0x0, vtysh=0) at command.c:2155
isis DEAD") at vty.c:433
isis_main.c:368
The patch is included.
patchwork #833: http://patchwork.quagga.net/patch/833/
2013-04-26 20:38:34 +02:00
|
|
|
if (lsp->area->circuit_list) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
|
|
|
|
{
|
|
|
|
if (circuit->lsp_queue == NULL)
|
|
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
|
|
|
|
if (lsp_in_list == lsp)
|
|
|
|
list_delete_node(circuit->lsp_queue, lnode);
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
|
|
|
|
ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_clear_data (lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
|
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
list_delete (lsp->lspu.frags);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->lspu.frags = NULL;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_spf_schedule (lsp->area, lsp->level);
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
isis_spf_schedule6 (lsp->area, lsp->level);
|
|
|
|
#endif
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (lsp->pdu)
|
|
|
|
stream_free (lsp->pdu);
|
|
|
|
XFREE (MTYPE_ISIS_LSP, lsp);
|
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
void
|
|
|
|
lsp_db_destroy (dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *dnode, *next;
|
|
|
|
struct isis_lsp *lsp;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
dnode = dict_first (lspdb);
|
2004-09-10 22:48:21 +02:00
|
|
|
while (dnode)
|
|
|
|
{
|
|
|
|
next = dict_next (lspdb, dnode);
|
|
|
|
lsp = dnode_get (dnode);
|
|
|
|
lsp_destroy (lsp);
|
|
|
|
dict_delete_free (lspdb, dnode);
|
|
|
|
dnode = next;
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
dict_free (lspdb);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove all the frags belonging to the given lsp
|
|
|
|
*/
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_remove_frags (struct list *frags, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *dnode;
|
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;
|
|
|
|
|
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))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
|
|
|
|
lsp_destroy (lsp);
|
|
|
|
dnode_destroy (dict_delete (lspdb, dnode));
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
list_delete_all_node (frags);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_search_and_destroy (u_char * id, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *node;
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
|
|
|
|
node = dict_lookup (lspdb, id);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (node)
|
|
|
|
{
|
|
|
|
node = dict_delete (lspdb, node);
|
|
|
|
lsp = dnode_get (node);
|
|
|
|
/*
|
|
|
|
* If this is a zero lsp, remove all the frags now
|
|
|
|
*/
|
|
|
|
if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
|
|
|
|
{
|
|
|
|
if (lsp->lspu.frags)
|
|
|
|
lsp_remove_frags (lsp->lspu.frags, lspdb);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
dnode_destroy (node);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compares a LSP to given values
|
|
|
|
* Params are given in net order
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
|
|
|
lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
|
2003-12-23 09:09:43 +01:00
|
|
|
u_int16_t checksum, u_int16_t rem_lifetime)
|
|
|
|
{
|
2004-09-10 22:48:21 +02:00
|
|
|
/* no point in double ntohl on seqnum */
|
|
|
|
if (lsp->lsp_header->seq_num == seq_num &&
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->lsp_header->checksum == checksum &&
|
|
|
|
/*comparing with 0, no need to do ntohl */
|
|
|
|
((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
|
2004-09-10 22:48:21 +02:00
|
|
|
(lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
|
|
|
|
{
|
|
|
|
if (isis->debugs & DEBUG_SNP_PACKETS)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
|
2004-12-24 01:14:50 +01:00
|
|
|
" lifetime %us",
|
|
|
|
areatag,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->rem_lifetime));
|
|
|
|
zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
|
|
|
|
" cksum 0x%04x, lifetime %us",
|
|
|
|
areatag,
|
|
|
|
ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
return LSP_EQUAL;
|
|
|
|
}
|
2003-12-23 09:09:43 +01: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.
|
|
|
|
*/
|
|
|
|
if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num)
|
|
|
|
|| (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
|
|
|
|
&& ( (lsp->lsp_header->rem_lifetime != 0
|
|
|
|
&& rem_lifetime == 0)
|
|
|
|
|| lsp->lsp_header->checksum != checksum)))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
if (isis->debugs & DEBUG_SNP_PACKETS)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
|
2004-12-24 01:14:50 +01:00
|
|
|
" lifetime %us",
|
|
|
|
areatag,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
|
|
|
|
zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
|
|
|
|
"cksum 0x%04x, lifetime %us",
|
|
|
|
areatag,
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->rem_lifetime));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
return LSP_NEWER;
|
|
|
|
}
|
|
|
|
if (isis->debugs & DEBUG_SNP_PACKETS)
|
|
|
|
{
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug
|
2012-03-24 16:35:20 +01:00
|
|
|
("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
|
2004-09-10 22:48:21 +02:00
|
|
|
areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
|
|
|
|
ntohs (checksum), ntohs (rem_lifetime));
|
2004-12-24 01:14:50 +01:00
|
|
|
zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
|
|
|
|
" cksum 0x%04x, lifetime %us", areatag,
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->rem_lifetime));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
return LSP_OLDER;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static void
|
|
|
|
lsp_auth_add (struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
struct isis_passwd *passwd;
|
|
|
|
unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the authentication info if its present
|
|
|
|
*/
|
|
|
|
(lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
|
|
|
|
(passwd = &lsp->area->domain_passwd);
|
|
|
|
switch (passwd->type)
|
|
|
|
{
|
|
|
|
/* Cleartext */
|
|
|
|
case ISIS_PASSWD_TYPE_CLEARTXT:
|
|
|
|
memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
|
|
|
|
tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* HMAC MD5 */
|
|
|
|
case ISIS_PASSWD_TYPE_HMAC_MD5:
|
|
|
|
/* Remember where TLV is written so we can later
|
|
|
|
* overwrite the MD5 hash */
|
|
|
|
lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
|
|
|
|
memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
|
|
|
|
lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
|
|
|
|
lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
|
|
|
|
memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
|
|
|
|
ISIS_AUTH_MD5_SIZE);
|
|
|
|
tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
|
|
|
|
lsp->pdu);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lsp_auth_update (struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
struct isis_passwd *passwd;
|
|
|
|
unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
|
|
|
|
uint16_t checksum, rem_lifetime;
|
|
|
|
|
|
|
|
/* For HMAC MD5 we need to recompute the md5 hash and store it */
|
|
|
|
(lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
|
|
|
|
(passwd = &lsp->area->domain_passwd);
|
|
|
|
if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In transient conditions (when net is configured where authentication
|
|
|
|
* config and lsp regenerate schedule is not yet run), there could be
|
|
|
|
* an own_lsp with auth_tlv_offset set to 0. In such a case, simply
|
|
|
|
* return, when lsp_regenerate is run, lsp will have auth tlv.
|
|
|
|
*/
|
|
|
|
if (lsp->auth_tlv_offset == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 5304 set auth value, checksum and remaining lifetime to zero
|
|
|
|
* before computation and reset to old values after computation.
|
|
|
|
*/
|
|
|
|
checksum = lsp->lsp_header->checksum;
|
|
|
|
rem_lifetime = lsp->lsp_header->rem_lifetime;
|
|
|
|
lsp->lsp_header->checksum = 0;
|
|
|
|
lsp->lsp_header->rem_lifetime = 0;
|
|
|
|
/* Set the authentication value as well to zero */
|
|
|
|
memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
|
|
|
|
0, ISIS_AUTH_MD5_SIZE);
|
|
|
|
/* Compute autentication value */
|
|
|
|
hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
|
|
|
|
(unsigned char *) &passwd->passwd, passwd->len,
|
2015-03-03 08:55:26 +01:00
|
|
|
(unsigned char *) &hmac_md5_hash);
|
2012-03-24 16:35:20 +01:00
|
|
|
/* Copy the hash into the stream */
|
|
|
|
memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
|
|
|
|
hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
|
|
|
|
memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
|
|
|
|
ISIS_AUTH_MD5_SIZE);
|
|
|
|
/* Copy back the checksum and remaining lifetime */
|
|
|
|
lsp->lsp_header->checksum = checksum;
|
|
|
|
lsp->lsp_header->rem_lifetime = rem_lifetime;
|
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
|
|
|
|
{
|
|
|
|
u_int32_t newseq;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
|
|
|
|
newseq = ntohl (lsp->lsp_header->seq_num) + 1;
|
|
|
|
else
|
2012-03-24 16:35:20 +01:00
|
|
|
newseq = seq_num + 1;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->lsp_header->seq_num = htonl (newseq);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/* Recompute authentication and checksum information */
|
|
|
|
lsp_auth_update (lsp);
|
|
|
|
/* ISO 10589 - 7.3.11 Generation of the checksum
|
|
|
|
* The checksum shall be computed over all fields in the LSP which appear
|
|
|
|
* after the Remaining Lifetime field. This field (and those appearing
|
|
|
|
* before it) are excluded so that the LSP may be aged by systems without
|
|
|
|
* requiring recomputation.
|
|
|
|
*/
|
|
|
|
fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
|
|
|
|
ntohs (lsp->lsp_header->pdu_len) - 12, 12);
|
|
|
|
|
|
|
|
isis_spf_schedule (lsp->area, lsp->level);
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
isis_spf_schedule6 (lsp->area, lsp->level);
|
|
|
|
#endif
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Genetates checksum for LSP and its frags
|
|
|
|
*/
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_seqnum_update (struct isis_lsp *lsp0)
|
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *node;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_inc_seqnum (lsp0, 0);
|
|
|
|
|
|
|
|
if (!lsp0->lspu.frags)
|
|
|
|
return;
|
|
|
|
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
|
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
|
|
|
lsp_inc_seqnum (lsp, 0);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-28 08:48:05 +02:00
|
|
|
static u_int8_t
|
2015-08-25 01:40:14 +02:00
|
|
|
lsp_bits_generate (int level, int overload_bit, int attached_bit)
|
2012-03-28 08:48:05 +02:00
|
|
|
{
|
|
|
|
u_int8_t lsp_bits = 0;
|
|
|
|
if (level == IS_LEVEL_1)
|
|
|
|
lsp_bits = IS_LEVEL_1;
|
|
|
|
else
|
|
|
|
lsp_bits = IS_LEVEL_1_AND_2;
|
|
|
|
if (overload_bit)
|
|
|
|
lsp_bits |= overload_bit;
|
2015-08-25 01:40:14 +02:00
|
|
|
if (attached_bit)
|
|
|
|
lsp_bits |= attached_bit;
|
2012-03-28 08:48:05 +02:00
|
|
|
return lsp_bits;
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_update_data (struct isis_lsp *lsp, 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
|
|
|
{
|
2004-09-10 22:48:21 +02:00
|
|
|
uint32_t expected = 0, found;
|
2003-12-23 09:09:43 +01:00
|
|
|
int retval;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* free the old lsp data */
|
|
|
|
lsp_clear_data (lsp);
|
|
|
|
|
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);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* setting pointers to the correct place */
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
|
|
|
|
lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
|
|
|
|
ISIS_FIXED_HDR_LEN);
|
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);
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Get LSP data i.e. TLVs
|
|
|
|
*/
|
|
|
|
expected |= TLVFLAG_AUTH_INFO;
|
|
|
|
expected |= TLVFLAG_AREA_ADDRS;
|
|
|
|
expected |= TLVFLAG_IS_NEIGHS;
|
|
|
|
expected |= TLVFLAG_NLPID;
|
|
|
|
if (area->dynhostname)
|
|
|
|
expected |= TLVFLAG_DYN_HOSTNAME;
|
2004-09-10 22:48:21 +02:00
|
|
|
if (area->newmetric)
|
|
|
|
{
|
|
|
|
expected |= TLVFLAG_TE_IS_NEIGHS;
|
|
|
|
expected |= TLVFLAG_TE_IPV4_REACHABILITY;
|
|
|
|
expected |= TLVFLAG_TE_ROUTER_ID;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
expected |= TLVFLAG_IPV4_ADDR;
|
|
|
|
expected |= TLVFLAG_IPV4_INT_REACHABILITY;
|
|
|
|
expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
expected |= TLVFLAG_IPV6_ADDR;
|
|
|
|
expected |= TLVFLAG_IPV6_REACHABILITY;
|
|
|
|
#endif /* HAVE_IPV6 */
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
|
|
|
|
ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
|
|
|
|
ntohs (lsp->lsp_header->pdu_len) -
|
|
|
|
ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
|
|
|
|
&expected, &found, &lsp->tlv_data,
|
|
|
|
NULL);
|
|
|
|
if (retval != ISIS_OK)
|
|
|
|
{
|
|
|
|
zlog_warn ("Could not parse LSP");
|
|
|
|
return;
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-28 08:48:05 +02:00
|
|
|
isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
|
|
|
|
(lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
|
|
|
|
IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_update (struct isis_lsp *lsp, struct stream *stream,
|
|
|
|
struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2005-09-18 19:51:02 +02:00
|
|
|
dnode_t *dnode = NULL;
|
2005-09-16 16:44:23 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* Remove old LSP from database. This is required since the
|
|
|
|
* lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
|
|
|
|
* and will update it with the new data in the stream. */
|
2005-09-18 19:51:02 +02:00
|
|
|
dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
|
|
|
|
if (dnode)
|
|
|
|
dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
|
2005-09-16 16:44:23 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* rebuild the lsp data */
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_update_data (lsp, stream, area, level);
|
2005-09-16 16:44:23 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* insert the lsp back into the database */
|
|
|
|
lsp_insert (lsp, area->lspdb[level - 1]);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* creation of LSP directly from what we received */
|
|
|
|
struct isis_lsp *
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_new_from_stream_ptr (struct stream *stream,
|
|
|
|
u_int16_t pdu_len, struct isis_lsp *lsp0,
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
|
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_update_data (lsp, stream, area, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (lsp0 == NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* zero lsp -> create the list for fragments
|
|
|
|
*/
|
|
|
|
lsp->lspu.frags = list_new ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* a fragment -> set the backpointer and add this to zero lsps frag list
|
|
|
|
*/
|
|
|
|
lsp->lspu.zero_lsp = lsp0;
|
|
|
|
listnode_add (lsp0->lspu.frags, lsp);
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_lsp *
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp_new(struct isis_area *area, u_char * lsp_id,
|
|
|
|
u_int16_t rem_lifetime, u_int32_t seq_num,
|
|
|
|
u_int8_t lsp_bits, u_int16_t checksum, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
|
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;
|
2015-11-10 18:04:44 +01:00
|
|
|
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
|
2003-12-23 09:09:43 +01:00
|
|
|
if (LSP_FRAGMENT (lsp_id) == 0)
|
|
|
|
lsp->lspu.frags = list_new ();
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
|
|
|
|
lsp->lsp_header = (struct isis_link_state_hdr *)
|
|
|
|
(STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* at first we fill the FIXED HEADER */
|
2012-03-24 16:35:20 +01:00
|
|
|
(level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
|
2004-09-10 22:48:21 +02:00
|
|
|
fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* now for the LSP HEADER */
|
|
|
|
/* Minimal LSP PDU size */
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
2003-12-23 09:09:43 +01:00
|
|
|
memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->lsp_header->checksum = checksum; /* Provided in network order */
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->lsp_header->seq_num = htonl (seq_num);
|
|
|
|
lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
|
|
|
|
lsp->lsp_header->lsp_bits = lsp_bits;
|
|
|
|
lsp->level = level;
|
|
|
|
lsp->age_out = ZERO_AGE_LIFETIME;
|
|
|
|
|
2005-02-09 16:51:56 +01:00
|
|
|
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2005-09-04 23:36:36 +02:00
|
|
|
if (isis->debugs & DEBUG_EVENTS)
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
|
2005-09-04 23:36:36 +02:00
|
|
|
sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
|
|
|
|
LSP_FRAGMENT (lsp->lsp_header->lsp_id),
|
2012-03-24 16:35:20 +01:00
|
|
|
ntohl (lsp->lsp_header->pdu_len),
|
2005-09-04 23:36:36 +02:00
|
|
|
ntohl (lsp->lsp_header->seq_num));
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (lsp->lsp_header->seq_num != 0)
|
|
|
|
{
|
|
|
|
isis_spf_schedule (lsp->area, lsp->level);
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
isis_spf_schedule6 (lsp->area, lsp->level);
|
|
|
|
#endif
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build a list of LSPs with non-zero ht bounded by start and stop ids
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
void
|
|
|
|
lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
|
|
|
|
struct list *list, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *first, *last, *curr;
|
|
|
|
|
|
|
|
first = dict_lower_bound (lspdb, start_id);
|
|
|
|
if (!first)
|
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
last = dict_upper_bound (lspdb, stop_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
curr = first;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
|
2003-12-23 09:09:43 +01:00
|
|
|
listnode_add (list, first->dict_data);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
while (curr)
|
|
|
|
{
|
|
|
|
curr = dict_next (lspdb, curr);
|
|
|
|
if (curr &&
|
|
|
|
((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
|
|
|
|
listnode_add (list, curr->dict_data);
|
|
|
|
if (curr == last)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-24 16:35:20 +01:00
|
|
|
* Build a list of num_lsps LSPs bounded by start_id and stop_id.
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
void
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
|
2004-09-10 22:48:21 +02:00
|
|
|
struct list *list, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
u_char count;
|
2003-12-23 09:09:43 +01:00
|
|
|
dnode_t *first, *last, *curr;
|
|
|
|
|
|
|
|
first = dict_lower_bound (lspdb, start_id);
|
|
|
|
if (!first)
|
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
last = dict_upper_bound (lspdb, stop_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
curr = first;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
listnode_add (list, first->dict_data);
|
2012-03-24 16:35:20 +01:00
|
|
|
count = 1;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
while (curr)
|
|
|
|
{
|
|
|
|
curr = dict_next (lspdb, curr);
|
|
|
|
if (curr)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
listnode_add (list, curr->dict_data);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if (count == num_lsps || curr == last)
|
|
|
|
break;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build a list of LSPs with SSN flag set for the given circuit
|
|
|
|
*/
|
|
|
|
void
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
|
|
|
|
struct list *list, dict_t * lspdb)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dnode_t *dnode, *next;
|
|
|
|
struct isis_lsp *lsp;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_char count = 0;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
dnode = dict_first (lspdb);
|
2004-09-10 22:48:21 +02:00
|
|
|
while (dnode != NULL)
|
|
|
|
{
|
|
|
|
next = dict_next (lspdb, dnode);
|
|
|
|
lsp = dnode_get (dnode);
|
|
|
|
if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
listnode_add (list, lsp);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
if (count == num_lsps)
|
|
|
|
break;
|
2004-09-10 22:48:21 +02:00
|
|
|
dnode = next;
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_set_time (struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
assert (lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (lsp->lsp_header->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
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->lsp_header->rem_lifetime =
|
2003-12-23 09:09:43 +01:00
|
|
|
htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2004-09-10 22:48:21 +02:00
|
|
|
lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_dynhn *dyn = NULL;
|
2004-09-10 22:48:21 +02:00
|
|
|
u_char id[SYSID_STRLEN];
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
if (dynhost)
|
|
|
|
dyn = dynhn_find_by_id (lsp_id);
|
|
|
|
else
|
|
|
|
dyn = NULL;
|
|
|
|
|
|
|
|
if (dyn)
|
2012-03-24 16:35:20 +01:00
|
|
|
sprintf ((char *)id, "%.14s", dyn->name.name);
|
|
|
|
else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
|
|
|
|
sprintf ((char *)id, "%.14s", unix_hostname ());
|
2004-09-10 22:48:21 +02:00
|
|
|
else
|
|
|
|
memcpy (id, sysid_print (lsp_id), 15);
|
2003-12-23 09:09:43 +01:00
|
|
|
if (frag)
|
2004-09-26 18:24:14 +02:00
|
|
|
sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
|
2004-09-10 22:48:21 +02:00
|
|
|
LSP_FRAGMENT (lsp_id));
|
2003-12-23 09:09:43 +01:00
|
|
|
else
|
2004-09-26 18:24:14 +02:00
|
|
|
sprintf ((char *)trg, "%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 */
|
2004-10-07 22:07:40 +02:00
|
|
|
const char *
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_bits2string (u_char * lsp_bits)
|
|
|
|
{
|
|
|
|
char *pos = lsp_bits_string;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!*lsp_bits)
|
2003-12-23 09:09:43 +01:00
|
|
|
return " none";
|
|
|
|
|
|
|
|
/* we only focus on the default metric */
|
|
|
|
pos += sprintf (pos, "%d/",
|
2004-09-10 22:48:21 +02:00
|
|
|
ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
pos += sprintf (pos, "%d/",
|
2004-09-10 22:48:21 +02:00
|
|
|
ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
|
|
|
|
|
|
|
|
pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
*(pos) = '\0';
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
return lsp_bits_string;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* this function prints the lsp on show isis database */
|
2012-03-24 16:35:20 +01:00
|
|
|
void
|
|
|
|
lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
u_char LSPid[255];
|
2012-03-24 16:35:20 +01:00
|
|
|
char age_out[8];
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
|
|
|
|
vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len));
|
|
|
|
vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
|
|
|
|
vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
|
2004-09-10 22:48:21 +02:00
|
|
|
if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
snprintf (age_out, 8, "(%u)", lsp->age_out);
|
|
|
|
age_out[7] = '\0';
|
|
|
|
vty_out (vty, "%7s ", age_out);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
else
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime));
|
|
|
|
vty_out (vty, "%s%s",
|
|
|
|
lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
void
|
|
|
|
lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct area_addr *area_addr;
|
2004-09-10 22:48:21 +02:00
|
|
|
int i;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *lnode;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct is_neigh *is_neigh;
|
|
|
|
struct te_is_neigh *te_is_neigh;
|
|
|
|
struct ipv4_reachability *ipv4_reach;
|
|
|
|
struct in_addr *ipv4_addr;
|
|
|
|
struct te_ipv4_reachability *te_ipv4_reach;
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
struct ipv6_reachability *ipv6_reach;
|
|
|
|
struct in6_addr in6;
|
2006-12-08 02:09:50 +01:00
|
|
|
u_char buff[BUFSIZ];
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif
|
|
|
|
u_char LSPid[255];
|
|
|
|
u_char hostname[255];
|
|
|
|
u_char ipv4_reach_prefix[20];
|
|
|
|
u_char ipv4_reach_mask[20];
|
|
|
|
u_char ipv4_address[20];
|
|
|
|
|
|
|
|
lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_print (lsp, vty, dynhost);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/* for all area address */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->tlv_data.area_addrs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2004-10-07 22:07:40 +02:00
|
|
|
vty_out (vty, " Area Address: %s%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
isonet_print (area_addr->area_addr, area_addr->addr_len),
|
|
|
|
VTY_NEWLINE);
|
|
|
|
}
|
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
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* for the nlpid tlv */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->tlv_data.nlpids)
|
|
|
|
{
|
|
|
|
for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
|
|
|
|
{
|
|
|
|
switch (lsp->tlv_data.nlpids->nlpids[i])
|
|
|
|
{
|
|
|
|
case NLPID_IP:
|
|
|
|
case NLPID_IPV6:
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " NLPID : 0x%X%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
|
|
|
|
break;
|
|
|
|
default:
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE);
|
2004-09-10 22:48:21 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/* for the hostname tlv */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp->tlv_data.hostname)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
bzero (hostname, sizeof (hostname));
|
2004-09-10 22:48:21 +02:00
|
|
|
memcpy (hostname, lsp->tlv_data.hostname->name,
|
|
|
|
lsp->tlv_data.hostname->namelen);
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* authentication tlv */
|
|
|
|
if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
|
|
|
|
vty_out (vty, " Auth type : md5%s", VTY_NEWLINE);
|
|
|
|
else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
|
|
|
|
vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2004-10-07 22:07:40 +02:00
|
|
|
/* TE router id */
|
|
|
|
if (lsp->tlv_data.router_id)
|
|
|
|
{
|
|
|
|
memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
|
|
|
|
sizeof (ipv4_address));
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE);
|
2004-10-07 22:07:40 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (lsp->tlv_data.ipv4_addrs)
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
|
|
|
|
{
|
|
|
|
memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
|
|
|
|
vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
|
|
|
|
}
|
|
|
|
|
2004-10-07 22:07:40 +02:00
|
|
|
/* for the IS neighbor tlv */
|
|
|
|
if (lsp->tlv_data.is_neighs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
|
2004-10-07 22:07:40 +02:00
|
|
|
{
|
|
|
|
lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IS : %s%s",
|
2004-10-07 22:07:40 +02:00
|
|
|
is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* for the internal reachable tlv */
|
|
|
|
if (lsp->tlv_data.ipv4_int_reachs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
|
|
|
|
ipv4_reach))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
|
|
|
|
sizeof (ipv4_reach_prefix));
|
|
|
|
memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
|
|
|
|
sizeof (ipv4_reach_mask));
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
|
|
|
|
ipv4_reach_mask, VTY_NEWLINE);
|
|
|
|
}
|
2003-12-23 12:51:08 +01:00
|
|
|
|
|
|
|
/* for the external reachable tlv */
|
|
|
|
if (lsp->tlv_data.ipv4_ext_reachs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode,
|
|
|
|
ipv4_reach))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
|
|
|
|
sizeof (ipv4_reach_prefix));
|
|
|
|
memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
|
|
|
|
sizeof (ipv4_reach_mask));
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
|
|
|
|
ipv4_reach_mask, VTY_NEWLINE);
|
|
|
|
}
|
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
|
|
|
|
2003-12-23 12:51:08 +01:00
|
|
|
/* IPv6 tlv */
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
if (lsp->tlv_data.ipv6_reachs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
memset (&in6, 0, sizeof (in6));
|
|
|
|
memcpy (in6.s6_addr, ipv6_reach->prefix,
|
|
|
|
PSIZE (ipv6_reach->prefix_len));
|
2004-09-26 18:24:14 +02:00
|
|
|
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
|
2016-05-07 01:29:36 +02:00
|
|
|
if ((ipv6_reach->control_info &
|
2004-09-10 22:48:21 +02:00
|
|
|
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
ntohl (ipv6_reach->metric),
|
|
|
|
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
2003-12-23 12:51:08 +01:00
|
|
|
else
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
|
2004-09-10 22:48:21 +02:00
|
|
|
ntohl (ipv6_reach->metric),
|
|
|
|
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
2003-12-23 12:51:08 +01:00
|
|
|
}
|
|
|
|
#endif
|
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
|
|
|
|
2004-10-07 22:07:40 +02:00
|
|
|
/* TE IS neighbor tlv */
|
2003-12-23 09:09:43 +01:00
|
|
|
if (lsp->tlv_data.te_is_neighs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
|
|
|
|
GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
|
2016-04-19 19:03:05 +02:00
|
|
|
if (IS_MPLS_TE(isisMplsTE))
|
|
|
|
mpls_te_print_detail(vty, te_is_neigh);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-10-07 22:07:40 +02:00
|
|
|
/* TE IPv4 tlv */
|
2003-12-23 09:09:43 +01:00
|
|
|
if (lsp->tlv_data.te_ipv4_reachs)
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
|
|
|
|
te_ipv4_reach))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2004-10-07 22:07:40 +02:00
|
|
|
/* FIXME: There should be better way to output this stuff. */
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
|
2004-10-07 22:07:40 +02:00
|
|
|
ntohl (te_ipv4_reach->te_metric),
|
2004-09-10 22:48:21 +02:00
|
|
|
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
|
|
|
|
te_ipv4_reach->control)),
|
2004-10-07 22:07:40 +02:00
|
|
|
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out (vty, "%s", VTY_NEWLINE);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
return;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* print all the lsps info in the local lspdb */
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
|
|
|
lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
dnode_t *node = dict_first (lspdb), *next;
|
2003-12-23 09:09:43 +01:00
|
|
|
int lsp_count = 0;
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (detail == ISIS_UI_LEVEL_BRIEF)
|
|
|
|
{
|
|
|
|
while (node != NULL)
|
|
|
|
{
|
|
|
|
/* I think it is unnecessary, so I comment it out */
|
|
|
|
/* dict_contains (lspdb, node); */
|
|
|
|
next = dict_next (lspdb, node);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_print (dnode_get (node), vty, dynhost);
|
2004-09-10 22:48:21 +02:00
|
|
|
node = next;
|
|
|
|
lsp_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (detail == ISIS_UI_LEVEL_DETAIL)
|
|
|
|
{
|
|
|
|
while (node != NULL)
|
|
|
|
{
|
|
|
|
next = dict_next (lspdb, node);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_print_detail (dnode_get (node), vty, dynhost);
|
2004-09-10 22:48:21 +02:00
|
|
|
node = next;
|
|
|
|
lsp_count++;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return lsp_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FRAG_THOLD(S,T) \
|
2012-03-24 16:35:20 +01:00
|
|
|
((STREAM_SIZE(S)*T)/100)
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/* stream*, area->lsp_frag_threshold, increment */
|
|
|
|
#define FRAG_NEEDED(S,T,I) \
|
|
|
|
(STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
|
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
|
|
|
|
* variable length (TE TLVs, sub TLVs). */
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
|
2004-09-10 22:48:21 +02:00
|
|
|
int tlvsize, int frag_thold,
|
|
|
|
int tlv_build_func (struct list *, struct stream *))
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
int count, i;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* can we fit all ? */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
|
|
|
|
{
|
|
|
|
tlv_build_func (*from, lsp->pdu);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (listcount (*to) != 0)
|
|
|
|
{
|
|
|
|
struct listnode *node, *nextnode;
|
|
|
|
void *elem;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
|
|
|
|
{
|
|
|
|
listnode_add (*to, elem);
|
|
|
|
list_delete_node (*from, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
list_free (*to);
|
|
|
|
*to = *from;
|
|
|
|
*from = NULL;
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
|
|
|
|
{
|
|
|
|
/* fit all we can */
|
|
|
|
count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
|
|
|
|
(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
|
2012-03-24 16:35:20 +01:00
|
|
|
count = count / tlvsize;
|
|
|
|
if (count > (int)listcount (*from))
|
|
|
|
count = listcount (*from);
|
2004-09-10 22:48:21 +02:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
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
|
|
|
listnode_add (*to, listgetdata (listhead (*from)));
|
|
|
|
listnode_delete (*from, listgetdata (listhead (*from)));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
tlv_build_func (*to, lsp->pdu);
|
|
|
|
}
|
2005-02-09 16:51:56 +01:00
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-19 19:03:05 +02:00
|
|
|
/* Process IS_NEIGHBOURS TLV with TE subTLVs */
|
|
|
|
void
|
|
|
|
lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
|
|
|
|
{
|
|
|
|
int count, size = 0;
|
|
|
|
struct listnode *node, *nextnode;
|
|
|
|
struct te_is_neigh *elem;
|
|
|
|
|
|
|
|
/* Start computing real size of TLVs */
|
|
|
|
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
|
|
|
|
size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
|
|
|
|
|
|
|
|
/* can we fit all ? */
|
|
|
|
if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
|
|
|
|
{
|
|
|
|
tlv_add_te_is_neighs (*from, lsp->pdu);
|
|
|
|
if (listcount (*to) != 0)
|
|
|
|
{
|
|
|
|
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
|
|
|
|
{
|
|
|
|
listnode_add (*to, elem);
|
|
|
|
list_delete_node (*from, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
list_free (*to);
|
|
|
|
*to = *from;
|
|
|
|
*from = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* fit all we can */
|
|
|
|
/* Compute remaining place in LSP PDU */
|
|
|
|
count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
|
|
|
|
(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
|
|
|
|
/* Determine size of TE SubTLVs */
|
|
|
|
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
|
|
|
|
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
while (count > 0)
|
|
|
|
{
|
|
|
|
listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
|
|
|
|
listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
|
|
|
|
|
|
|
|
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
|
|
|
|
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
tlv_add_te_is_neighs (*to, lsp->pdu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static u_int16_t
|
|
|
|
lsp_rem_lifetime (struct isis_area *area, int level)
|
|
|
|
{
|
|
|
|
u_int16_t rem_lifetime;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u_int16_t
|
|
|
|
lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
|
|
|
|
{
|
|
|
|
struct isis_area *area = lsp->area;
|
|
|
|
int level = lsp->level;
|
|
|
|
u_int16_t refresh_time;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static struct isis_lsp *
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
|
|
|
|
int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2004-09-10 22:48:21 +02:00
|
|
|
u_char frag_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
|
|
|
|
LSP_FRAGMENT (frag_id) = frag_num;
|
2012-03-24 16:35:20 +01:00
|
|
|
/* FIXME add authentication TLV for fragment LSPs */
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp = lsp_search (frag_id, area->lspdb[level - 1]);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (lsp)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
/* Clear the TLVs */
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_clear_data (lsp);
|
|
|
|
return lsp;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
|
2015-08-25 01:40:14 +02:00
|
|
|
lsp_bits_generate (level, area->overload_bit,
|
|
|
|
area->attached_bit), 0, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->area = area;
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->own_lsp = 1;
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_insert (lsp, area->lspdb[level - 1]);
|
2003-12-23 09:09:43 +01:00
|
|
|
listnode_add (lsp0->lspu.frags, lsp);
|
|
|
|
lsp->lspu.zero_lsp = lsp0;
|
|
|
|
return lsp;
|
|
|
|
}
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
static void
|
|
|
|
lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
|
|
|
|
struct tlvs *tlv_data)
|
|
|
|
{
|
|
|
|
struct route_table *er_table;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct prefix_ipv4 *ipv4;
|
|
|
|
struct isis_ext_info *info;
|
|
|
|
struct ipv4_reachability *ipreach;
|
|
|
|
struct te_ipv4_reachability *te_ipreach;
|
|
|
|
|
|
|
|
er_table = get_ext_reach(area, AF_INET, lsp->level);
|
|
|
|
if (!er_table)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (rn = route_top(er_table); rn; rn = route_next(rn))
|
|
|
|
{
|
|
|
|
if (!rn->info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ipv4 = (struct prefix_ipv4*)&rn->p;
|
|
|
|
info = rn->info;
|
|
|
|
if (area->oldmetric)
|
|
|
|
{
|
|
|
|
if (tlv_data->ipv4_ext_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data->ipv4_ext_reachs = list_new();
|
|
|
|
tlv_data->ipv4_ext_reachs->del = free_tlv;
|
|
|
|
}
|
|
|
|
ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
|
|
|
|
|
|
|
|
ipreach->prefix.s_addr = ipv4->prefix.s_addr;
|
|
|
|
masklen2ip(ipv4->prefixlen, &ipreach->mask);
|
|
|
|
ipreach->prefix.s_addr &= ipreach->mask.s_addr;
|
|
|
|
|
|
|
|
if ((info->metric & 0x3f) != info->metric)
|
|
|
|
ipreach->metrics.metric_default = 0x3f;
|
|
|
|
else
|
|
|
|
ipreach->metrics.metric_default = info->metric;
|
|
|
|
ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
|
|
|
|
ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
|
|
|
|
ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
|
|
|
|
listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
|
|
|
|
}
|
|
|
|
if (area->newmetric)
|
|
|
|
{
|
|
|
|
if (tlv_data->te_ipv4_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data->te_ipv4_reachs = list_new();
|
|
|
|
tlv_data->te_ipv4_reachs->del = free_tlv;
|
|
|
|
}
|
|
|
|
te_ipreach =
|
|
|
|
XCALLOC(MTYPE_ISIS_TLV,
|
|
|
|
sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
|
|
|
|
if (info->metric > MAX_WIDE_PATH_METRIC)
|
|
|
|
te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
|
|
|
|
else
|
|
|
|
te_ipreach->te_metric = htonl(info->metric);
|
|
|
|
te_ipreach->control = ipv4->prefixlen & 0x3f;
|
|
|
|
memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
|
|
|
|
PSIZE(ipv4->prefixlen));
|
|
|
|
listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
|
|
|
|
struct tlvs *tlv_data)
|
|
|
|
{
|
|
|
|
struct route_table *er_table;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct prefix_ipv6 *ipv6;
|
|
|
|
struct isis_ext_info *info;
|
|
|
|
struct ipv6_reachability *ip6reach;
|
|
|
|
|
|
|
|
er_table = get_ext_reach(area, AF_INET6, lsp->level);
|
|
|
|
if (!er_table)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (rn = route_top(er_table); rn; rn = route_next(rn))
|
|
|
|
{
|
|
|
|
if (!rn->info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ipv6 = (struct prefix_ipv6*)&rn->p;
|
|
|
|
info = rn->info;
|
|
|
|
|
|
|
|
if (tlv_data->ipv6_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data->ipv6_reachs = list_new();
|
|
|
|
tlv_data->ipv6_reachs->del = free_tlv;
|
|
|
|
}
|
|
|
|
ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
|
|
|
|
if (info->metric > MAX_WIDE_PATH_METRIC)
|
|
|
|
ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
|
|
|
|
else
|
|
|
|
ip6reach->metric = htonl(info->metric);
|
|
|
|
ip6reach->control_info = DISTRIBUTION_EXTERNAL;
|
|
|
|
ip6reach->prefix_len = ipv6->prefixlen;
|
|
|
|
memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
|
|
|
|
listnode_add(tlv_data->ipv6_reachs, ip6reach);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
|
|
|
|
struct tlvs *tlv_data)
|
|
|
|
{
|
|
|
|
lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
|
|
|
|
lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct is_neigh *is_neigh;
|
2005-09-26 19:39:48 +02:00
|
|
|
struct te_is_neigh *te_is_neigh;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *node, *ipnode;
|
2003-12-23 09:09:43 +01:00
|
|
|
int level = lsp->level;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
struct prefix_ipv4 *ipv4;
|
|
|
|
struct ipv4_reachability *ipreach;
|
2005-09-26 19:39:48 +02:00
|
|
|
struct te_ipv4_reachability *te_ipreach;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_adjacency *nei;
|
|
|
|
#ifdef HAVE_IPV6
|
2015-11-10 18:33:14 +01:00
|
|
|
struct prefix_ipv6 *ipv6, ip6prefix;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct ipv6_reachability *ip6reach;
|
|
|
|
#endif /* HAVE_IPV6 */
|
|
|
|
struct tlvs tlv_data;
|
|
|
|
struct isis_lsp *lsp0 = lsp;
|
2004-10-03 20:18:34 +02:00
|
|
|
struct in_addr *routerid;
|
2012-03-24 16:35:20 +01:00
|
|
|
uint32_t expected = 0, found = 0;
|
|
|
|
uint32_t metric;
|
|
|
|
u_char zero_id[ISIS_SYS_ID_LEN + 1];
|
|
|
|
int retval = ISIS_OK;
|
2015-11-12 14:21:47 +01:00
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
|
|
|
lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Building the zero lsp
|
|
|
|
*/
|
|
|
|
memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
|
|
|
|
|
|
|
|
/* Reset stream endp. Stream is always there and on every LSP refresh only
|
|
|
|
* TLV part of it is overwritten. So we must seek past header we will not
|
|
|
|
* touch. */
|
|
|
|
stream_reset (lsp->pdu);
|
|
|
|
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the authentication info if its present
|
|
|
|
*/
|
|
|
|
lsp_auth_add (lsp);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First add the tlvs related to area
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Area addresses */
|
|
|
|
if (lsp->tlv_data.area_addrs == NULL)
|
|
|
|
lsp->tlv_data.area_addrs = list_new ();
|
|
|
|
list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (listcount (lsp->tlv_data.area_addrs) > 0)
|
|
|
|
tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Protocols Supported */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (area->ip_circuits > 0
|
2003-12-23 09:09:43 +01:00
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
|| area->ipv6_circuits > 0
|
|
|
|
#endif /* HAVE_IPV6 */
|
2004-09-10 22:48:21 +02:00
|
|
|
)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2005-09-01 19:52:33 +02:00
|
|
|
lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->tlv_data.nlpids->count = 0;
|
2004-09-10 22:48:21 +02:00
|
|
|
if (area->ip_circuits > 0)
|
|
|
|
{
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->tlv_data.nlpids->count++;
|
|
|
|
lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
#ifdef HAVE_IPV6
|
2004-09-10 22:48:21 +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);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->tlv_data.nlpids->count++;
|
|
|
|
lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
|
|
|
|
NLPID_IPV6;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* HAVE_IPV6 */
|
2012-03-24 16:35:20 +01:00
|
|
|
tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* Dynamic Hostname */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (area->dynhostname)
|
|
|
|
{
|
2015-11-12 14:09:08 +01:00
|
|
|
const char *hostname = unix_hostname();
|
|
|
|
size_t hostname_len = strlen(hostname);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct hostname));
|
2003-12-23 09:56:18 +01:00
|
|
|
|
2015-11-12 14:09:08 +01:00
|
|
|
strncpy((char *)lsp->tlv_data.hostname->name, hostname,
|
|
|
|
sizeof(lsp->tlv_data.hostname->name));
|
|
|
|
if (hostname_len <= MAX_TLV_LEN)
|
|
|
|
lsp->tlv_data.hostname->namelen = hostname_len;
|
|
|
|
else
|
|
|
|
lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
|
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
|
|
|
|
lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
|
2012-03-24 16:35:20 +01:00
|
|
|
tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2005-09-26 19:58:24 +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 and this address is same as router id. */
|
2012-03-24 16:35:20 +01:00
|
|
|
if (isis->router_id != 0)
|
2004-10-03 20:18:34 +02:00
|
|
|
{
|
2015-11-12 14:21:47 +01:00
|
|
|
inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
|
|
|
|
lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf);
|
2004-10-03 20:18:34 +02:00
|
|
|
if (lsp->tlv_data.ipv4_addrs == NULL)
|
2005-09-02 03:38:16 +02:00
|
|
|
{
|
|
|
|
lsp->tlv_data.ipv4_addrs = list_new ();
|
|
|
|
lsp->tlv_data.ipv4_addrs->del = free_tlv;
|
|
|
|
}
|
2004-10-03 20:18:34 +02:00
|
|
|
|
|
|
|
routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
|
2012-03-24 16:35:20 +01:00
|
|
|
routerid->s_addr = isis->router_id;
|
2004-10-03 20:18:34 +02:00
|
|
|
listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
|
2005-09-26 19:58:24 +02:00
|
|
|
tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
|
2004-10-03 20:18:34 +02:00
|
|
|
|
2005-09-26 19:58:24 +02:00
|
|
|
/* Exactly same data is put into TE router ID TLV, but only if new style
|
|
|
|
* TLV's are in use. */
|
|
|
|
if (area->newmetric)
|
|
|
|
{
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
|
2005-09-26 19:58:24 +02:00
|
|
|
lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct in_addr));
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->tlv_data.router_id->id.s_addr = isis->router_id;
|
|
|
|
tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
|
|
|
|
TE_ROUTER_ID);
|
2005-09-26 19:58:24 +02:00
|
|
|
}
|
2004-10-03 20:18:34 +02:00
|
|
|
}
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
|
|
|
|
}
|
2005-09-19 06:23:34 +02:00
|
|
|
|
2005-09-26 19:58:24 +02:00
|
|
|
memset (&tlv_data, 0, sizeof (struct tlvs));
|
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Then build lists of tlvs related to circuits
|
|
|
|
*/
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2015-11-12 14:21:47 +01:00
|
|
|
if (!circuit->interface)
|
|
|
|
lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
|
|
|
|
area->area_tag, circuit_type2string(circuit->circ_type), circuit);
|
|
|
|
else
|
|
|
|
lsp_debug("ISIS (%s): Processing %s circuit %s",
|
|
|
|
area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (circuit->state != C_STATE_UP)
|
2015-11-12 14:21:47 +01:00
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
/*
|
|
|
|
* Add IPv4 internal reachability of this circuit
|
|
|
|
*/
|
|
|
|
if (circuit->ip_router && circuit->ip_addrs &&
|
|
|
|
circuit->ip_addrs->count > 0)
|
|
|
|
{
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->oldmetric)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (tlv_data.ipv4_int_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.ipv4_int_reachs = list_new ();
|
|
|
|
tlv_data.ipv4_int_reachs->del = free_tlv;
|
|
|
|
}
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
|
2005-09-26 19:39:48 +02:00
|
|
|
{
|
|
|
|
ipreach =
|
|
|
|
XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
|
2016-07-28 17:23:32 +02:00
|
|
|
ipreach->metrics.metric_default = circuit->metric[level - 1];
|
|
|
|
ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
|
|
|
|
ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
|
|
|
|
ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
|
2005-09-26 19:39:48 +02:00
|
|
|
masklen2ip (ipv4->prefixlen, &ipreach->mask);
|
|
|
|
ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
|
|
|
|
(ipv4->prefix.s_addr));
|
2015-11-12 14:21:47 +01:00
|
|
|
inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf));
|
|
|
|
lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
|
|
|
|
area->area_tag, buf, ipv4->prefixlen);
|
2005-09-26 19:39:48 +02:00
|
|
|
listnode_add (tlv_data.ipv4_int_reachs, ipreach);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->newmetric)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (tlv_data.te_ipv4_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.te_ipv4_reachs = list_new ();
|
|
|
|
tlv_data.te_ipv4_reachs->del = free_tlv;
|
|
|
|
}
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
|
2005-09-26 19:39:48 +02:00
|
|
|
{
|
|
|
|
/* FIXME All this assumes that we have no sub TLVs. */
|
|
|
|
te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct te_ipv4_reachability) +
|
|
|
|
((ipv4->prefixlen + 7)/8) - 1);
|
2005-09-26 20:06:47 +02:00
|
|
|
|
|
|
|
if (area->oldmetric)
|
2016-07-28 17:23:32 +02:00
|
|
|
te_ipreach->te_metric = htonl (circuit->metric[level - 1]);
|
2005-09-26 20:06:47 +02:00
|
|
|
else
|
|
|
|
te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
|
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
te_ipreach->control = (ipv4->prefixlen & 0x3F);
|
|
|
|
memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
|
|
|
|
(ipv4->prefixlen + 7)/8);
|
2015-11-12 14:21:47 +01:00
|
|
|
inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf));
|
|
|
|
lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
|
|
|
|
area->area_tag, buf, ipv4->prefixlen);
|
2005-09-26 19:39:48 +02:00
|
|
|
listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
#ifdef HAVE_IPV6
|
2004-09-10 22:48:21 +02:00
|
|
|
/*
|
|
|
|
* Add IPv6 reachability of this circuit
|
|
|
|
*/
|
|
|
|
if (circuit->ipv6_router && circuit->ipv6_non_link &&
|
|
|
|
circuit->ipv6_non_link->count > 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (tlv_data.ipv6_reachs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.ipv6_reachs = list_new ();
|
2005-09-02 03:38:16 +02:00
|
|
|
tlv_data.ipv6_reachs->del = free_tlv;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
ip6reach =
|
2005-09-01 19:52:33 +02:00
|
|
|
XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
|
2005-09-26 20:06:47 +02:00
|
|
|
|
|
|
|
if (area->oldmetric)
|
|
|
|
ip6reach->metric =
|
2016-07-28 17:23:32 +02:00
|
|
|
htonl (circuit->metric[level - 1]);
|
2005-09-26 20:06:47 +02:00
|
|
|
else
|
|
|
|
ip6reach->metric = htonl (circuit->te_metric[level - 1]);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
ip6reach->control_info = 0;
|
|
|
|
ip6reach->prefix_len = ipv6->prefixlen;
|
2015-11-10 18:33:14 +01:00
|
|
|
memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
|
|
|
|
apply_mask_ipv6(&ip6prefix);
|
2015-11-12 14:21:47 +01:00
|
|
|
|
2015-11-10 18:33:14 +01:00
|
|
|
inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
|
|
|
|
area->area_tag, buf, ipv6->prefixlen);
|
|
|
|
|
2015-11-10 18:33:14 +01:00
|
|
|
memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
|
2004-09-21 16:17:04 +02:00
|
|
|
sizeof (ip6reach->prefix));
|
2004-09-10 22:48:21 +02:00
|
|
|
listnode_add (tlv_data.ipv6_reachs, ip6reach);
|
|
|
|
}
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* HAVE_IPV6 */
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
switch (circuit->circ_type)
|
|
|
|
{
|
|
|
|
case CIRCUIT_T_BROADCAST:
|
2012-03-24 16:35:20 +01:00
|
|
|
if (level & circuit->is_type)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->oldmetric)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (tlv_data.is_neighs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.is_neighs = list_new ();
|
|
|
|
tlv_data.is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
|
2012-03-24 16:35:20 +01:00
|
|
|
if (level == IS_LEVEL_1)
|
2005-09-26 19:39:48 +02:00
|
|
|
memcpy (is_neigh->neigh_id,
|
|
|
|
circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
|
|
|
|
else
|
|
|
|
memcpy (is_neigh->neigh_id,
|
|
|
|
circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
|
2016-07-28 17:23:32 +02:00
|
|
|
is_neigh->metrics.metric_default = circuit->metric[level - 1];
|
|
|
|
is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
|
|
|
|
is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
|
|
|
|
is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!memcmp (is_neigh->neigh_id, zero_id,
|
|
|
|
ISIS_SYS_ID_LEN + 1))
|
2015-11-12 14:21:47 +01:00
|
|
|
{
|
|
|
|
XFREE (MTYPE_ISIS_TLV, is_neigh);
|
|
|
|
lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
|
|
|
|
area->area_tag);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
else
|
2015-11-12 14:21:47 +01:00
|
|
|
{
|
|
|
|
listnode_add (tlv_data.is_neighs, is_neigh);
|
|
|
|
lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
|
|
|
|
area->area_tag, sysid_print(is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(is_neigh->neigh_id));
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->newmetric)
|
|
|
|
{
|
|
|
|
if (tlv_data.te_is_neighs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.te_is_neighs = list_new ();
|
|
|
|
tlv_data.te_is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct te_is_neigh));
|
2012-03-24 16:35:20 +01:00
|
|
|
if (level == IS_LEVEL_1)
|
2005-09-26 19:39:48 +02:00
|
|
|
memcpy (te_is_neigh->neigh_id,
|
|
|
|
circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
|
|
|
|
else
|
|
|
|
memcpy (te_is_neigh->neigh_id,
|
|
|
|
circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
|
2005-09-26 20:06:47 +02:00
|
|
|
if (area->oldmetric)
|
2016-07-28 17:23:32 +02:00
|
|
|
metric = circuit->metric[level - 1];
|
2005-09-26 20:06:47 +02:00
|
|
|
else
|
2012-03-24 16:35:20 +01:00
|
|
|
metric = circuit->te_metric[level - 1];
|
|
|
|
SET_TE_METRIC(te_is_neigh, metric);
|
|
|
|
if (!memcmp (te_is_neigh->neigh_id, zero_id,
|
|
|
|
ISIS_SYS_ID_LEN + 1))
|
2015-11-12 14:21:47 +01:00
|
|
|
{
|
|
|
|
XFREE (MTYPE_ISIS_TLV, te_is_neigh);
|
|
|
|
lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
|
|
|
|
area->area_tag);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
else
|
2015-11-12 14:21:47 +01:00
|
|
|
{
|
2016-04-19 19:03:05 +02:00
|
|
|
/* Check if MPLS_TE is activate */
|
|
|
|
if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
|
|
|
|
/* Add SubTLVs & Adjust real size of SubTLVs */
|
|
|
|
te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
|
|
|
|
else
|
|
|
|
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
|
|
|
|
te_is_neigh->sub_tlvs_length = 0;
|
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
|
|
|
|
lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
|
|
|
|
area->area_tag, sysid_print(te_is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(te_is_neigh->neigh_id));
|
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
|
|
|
|
area->area_tag);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
break;
|
|
|
|
case CIRCUIT_T_P2P:
|
|
|
|
nei = circuit->u.p2p.neighbor;
|
|
|
|
if (nei && (level & nei->circuit_t))
|
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (area->oldmetric)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (tlv_data.is_neighs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.is_neighs = list_new ();
|
|
|
|
tlv_data.is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
|
|
|
|
memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
|
2016-07-28 17:23:32 +02:00
|
|
|
is_neigh->metrics.metric_default = circuit->metric[level - 1];
|
|
|
|
is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
|
|
|
|
is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
|
|
|
|
is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
|
2005-09-26 19:39:48 +02:00
|
|
|
listnode_add (tlv_data.is_neighs, is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
|
|
|
|
sysid_print(is_neigh->neigh_id));
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
|
|
|
if (area->newmetric)
|
|
|
|
{
|
|
|
|
uint32_t metric;
|
|
|
|
|
|
|
|
if (tlv_data.te_is_neighs == NULL)
|
|
|
|
{
|
|
|
|
tlv_data.te_is_neighs = list_new ();
|
|
|
|
tlv_data.te_is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct te_is_neigh));
|
|
|
|
memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
metric = circuit->te_metric[level - 1];
|
|
|
|
SET_TE_METRIC(te_is_neigh, metric);
|
2016-04-19 19:03:05 +02:00
|
|
|
/* Check if MPLS_TE is activate */
|
|
|
|
if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
|
|
|
|
/* Update Local and Remote IP address for MPLS TE circuit parameters */
|
|
|
|
/* NOTE sure that it is the pertinent place for that updates */
|
|
|
|
/* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */
|
|
|
|
/* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */
|
|
|
|
|
|
|
|
/* Add SubTLVs & Adjust real size of SubTLVs */
|
|
|
|
te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
|
|
|
|
else
|
|
|
|
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
|
|
|
|
te_is_neigh->sub_tlvs_length = 0;
|
2005-09-26 19:39:48 +02:00
|
|
|
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
|
|
|
|
sysid_print(te_is_neigh->neigh_id));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
|
|
|
|
area->area_tag);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
break;
|
2012-03-24 16:35:20 +01:00
|
|
|
case CIRCUIT_T_LOOPBACK:
|
|
|
|
break;
|
2004-09-10 22:48:21 +02:00
|
|
|
default:
|
|
|
|
zlog_warn ("lsp_area_create: unknown circuit type");
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
lsp_build_ext_reach(lsp, area, &tlv_data);
|
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.ipv4_int_reachs == NULL)
|
|
|
|
lsp->tlv_data.ipv4_int_reachs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
|
|
|
|
&lsp->tlv_data.ipv4_int_reachs,
|
|
|
|
IPV4_REACH_LEN, area->lsp_frag_threshold,
|
2015-11-12 14:24:22 +01:00
|
|
|
tlv_add_ipv4_int_reachs);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.ipv4_ext_reachs == NULL)
|
|
|
|
lsp->tlv_data.ipv4_ext_reachs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
|
|
|
|
&lsp->tlv_data.ipv4_ext_reachs,
|
|
|
|
IPV4_REACH_LEN, area->lsp_frag_threshold,
|
|
|
|
tlv_add_ipv4_ext_reachs);
|
|
|
|
if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
|
|
|
|
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
|
|
|
|
* TLVs (sub TLVs!). */
|
|
|
|
while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.te_ipv4_reachs == NULL)
|
|
|
|
lsp->tlv_data.te_ipv4_reachs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
|
|
|
|
&lsp->tlv_data.te_ipv4_reachs,
|
2012-03-24 16:35:20 +01:00
|
|
|
TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
|
|
|
|
tlv_add_te_ipv4_reachs);
|
2005-09-26 19:39:48 +02:00
|
|
|
if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.ipv6_reachs == NULL)
|
|
|
|
lsp->tlv_data.ipv6_reachs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
|
|
|
|
&lsp->tlv_data.ipv6_reachs,
|
|
|
|
IPV6_REACH_LEN, area->lsp_frag_threshold,
|
|
|
|
tlv_add_ipv6_reachs);
|
|
|
|
if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_IPV6 */
|
|
|
|
|
|
|
|
while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.is_neighs == NULL)
|
|
|
|
lsp->tlv_data.is_neighs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.is_neighs,
|
|
|
|
&lsp->tlv_data.is_neighs,
|
|
|
|
IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
|
|
|
|
tlv_add_is_neighs);
|
|
|
|
if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.te_is_neighs == NULL)
|
|
|
|
lsp->tlv_data.te_is_neighs = list_new ();
|
|
|
|
lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
|
|
|
|
IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
|
|
|
|
tlv_add_te_is_neighs);
|
|
|
|
if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
|
|
|
|
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
|
|
|
lsp0, area, level);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
2005-09-26 19:39:48 +02:00
|
|
|
|
|
|
|
free_tlvs (&tlv_data);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/* Validate the LSP */
|
|
|
|
retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
|
|
|
|
ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
|
|
|
|
stream_get_endp (lsp->pdu) -
|
|
|
|
ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
|
|
|
|
&expected, &found, &tlv_data, NULL);
|
|
|
|
assert (retval == ISIS_OK);
|
|
|
|
|
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;
|
|
|
|
u_int32_t seq_num = 0;
|
|
|
|
u_char lspid[ISIS_SYS_ID_LEN + 2];
|
2012-03-24 16:35:20 +01:00
|
|
|
u_int16_t rem_lifetime, refresh_time;
|
|
|
|
|
|
|
|
if ((area == NULL) || (area->is_type & level) != level)
|
|
|
|
return ISIS_ERROR;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
|
|
|
|
memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
|
|
|
|
/* only builds the lsp if the area shares the level */
|
2012-03-24 16:35:20 +01:00
|
|
|
oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
|
|
|
|
if (oldlsp)
|
|
|
|
{
|
|
|
|
/* FIXME: we should actually initiate a purge */
|
|
|
|
seq_num = ntohl (oldlsp->lsp_header->seq_num);
|
|
|
|
lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
|
|
|
|
area->lspdb[level - 1]);
|
|
|
|
}
|
|
|
|
rem_lifetime = lsp_rem_lifetime (area, level);
|
2015-11-10 18:43:31 +01:00
|
|
|
newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
|
2015-08-25 01:40:14 +02:00
|
|
|
area->is_type | area->overload_bit | area->attached_bit,
|
|
|
|
0, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
newlsp->area = area;
|
|
|
|
newlsp->own_lsp = 1;
|
|
|
|
|
|
|
|
lsp_insert (newlsp, area->lspdb[level - 1]);
|
|
|
|
/* build_lsp_data (newlsp, area); */
|
|
|
|
lsp_build (newlsp, area);
|
|
|
|
/* time to calculate our checksum */
|
|
|
|
lsp_seqnum_update (newlsp);
|
2015-11-10 18:43:34 +01:00
|
|
|
newlsp->last_generated = time(NULL);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_set_all_srmflags (newlsp);
|
|
|
|
|
|
|
|
refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
|
2015-11-10 18:43:34 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
|
2015-11-10 18:43:34 +01:00
|
|
|
area->lsp_regenerate_pending[level - 1] = 0;
|
2012-03-24 16:35:20 +01:00
|
|
|
if (level == IS_LEVEL_1)
|
|
|
|
THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
|
|
|
|
lsp_l1_refresh, area, refresh_time);
|
|
|
|
else if (level == IS_LEVEL_2)
|
|
|
|
THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
|
|
|
|
lsp_l2_refresh, area, refresh_time);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (isis->debugs & DEBUG_UPDATE_PACKETS)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
|
|
|
|
"seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
|
|
|
|
area->area_tag, level,
|
|
|
|
rawlspid_print (newlsp->lsp_header->lsp_id),
|
|
|
|
ntohl (newlsp->lsp_header->pdu_len),
|
|
|
|
ntohl (newlsp->lsp_header->seq_num),
|
|
|
|
ntohs (newlsp->lsp_header->checksum),
|
|
|
|
ntohs (newlsp->lsp_header->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);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-24 16:35:20 +01:00
|
|
|
* Search own LSPs, update holding time and set SRM
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
2005-01-18 14:53:33 +01:00
|
|
|
static int
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_regenerate (struct isis_area *area, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2012-11-27 02:10:30 +01:00
|
|
|
dict_t *lspdb;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_lsp *lsp, *frag;
|
|
|
|
struct listnode *node;
|
|
|
|
u_char lspid[ISIS_SYS_ID_LEN + 2];
|
2012-03-24 16:35:20 +01:00
|
|
|
u_int16_t rem_lifetime, refresh_time;
|
|
|
|
|
|
|
|
if ((area == NULL) || (area->is_type & level) != level)
|
|
|
|
return ISIS_ERROR;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-11-27 02:10:30 +01:00
|
|
|
lspdb = area->lspdb[level - 1];
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
|
|
|
|
memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp = lsp_search (lspid, lspdb);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!lsp)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_err ("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;
|
|
|
|
}
|
|
|
|
|
|
|
|
lsp_clear_data (lsp);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_build (lsp, area);
|
2015-08-25 01:40:14 +02:00
|
|
|
lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
|
|
|
|
area->attached_bit);
|
2012-03-24 16:35:20 +01:00
|
|
|
rem_lifetime = lsp_rem_lifetime (area, level);
|
|
|
|
lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_seqnum_update (lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->last_generated = time (NULL);
|
|
|
|
lsp_set_all_srmflags (lsp);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-28 08:48:05 +02:00
|
|
|
frag->lsp_header->lsp_bits = lsp_bits_generate (level,
|
2015-08-25 01:40:14 +02:00
|
|
|
area->overload_bit,
|
|
|
|
area->attached_bit);
|
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.
|
|
|
|
*/
|
|
|
|
frag->lsp_header->rem_lifetime = htons (rem_lifetime);
|
|
|
|
lsp_set_all_srmflags (frag);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
refresh_time = lsp_refresh_time (lsp, rem_lifetime);
|
|
|
|
if (level == IS_LEVEL_1)
|
|
|
|
THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
|
|
|
|
lsp_l1_refresh, area, refresh_time);
|
|
|
|
else if (level == IS_LEVEL_2)
|
|
|
|
THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
|
|
|
|
lsp_l2_refresh, area, refresh_time);
|
2015-11-10 18:43:34 +01:00
|
|
|
area->lsp_regenerate_pending[level - 1] = 0;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
if (isis->debugs & DEBUG_UPDATE_PACKETS)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
|
|
|
|
"seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
|
|
|
|
area->area_tag, level,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (lsp->lsp_header->pdu_len),
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->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);
|
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
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
static int
|
|
|
|
lsp_l1_refresh (struct thread *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_area *area;
|
|
|
|
|
|
|
|
area = THREAD_ARG (thread);
|
|
|
|
assert (area);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
area->t_lsp_refresh[0] = NULL;
|
2012-03-24 16:35:20 +01:00
|
|
|
area->lsp_regenerate_pending[0] = 0;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((area->is_type & IS_LEVEL_1) == 0)
|
|
|
|
return ISIS_ERROR;
|
2004-02-11 21:26:31 +01:00
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
|
2012-03-24 16:35:20 +01:00
|
|
|
return lsp_regenerate (area, IS_LEVEL_1);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static int
|
|
|
|
lsp_l2_refresh (struct thread *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_area *area;
|
|
|
|
|
|
|
|
area = THREAD_ARG (thread);
|
|
|
|
assert (area);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
area->t_lsp_refresh[1] = NULL;
|
|
|
|
area->lsp_regenerate_pending[1] = 0;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((area->is_type & IS_LEVEL_2) == 0)
|
|
|
|
return ISIS_ERROR;
|
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
|
2012-03-24 16:35:20 +01:00
|
|
|
return lsp_regenerate (area, IS_LEVEL_2);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
u_char id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (area == NULL)
|
|
|
|
return ISIS_ERROR;
|
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
|
|
|
|
area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
|
2003-12-23 09:09:43 +01:00
|
|
|
now = time (NULL);
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!((level & lvl) && (area->is_type & lvl)))
|
|
|
|
continue;
|
|
|
|
|
2015-11-10 18:43:34 +01:00
|
|
|
sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
|
|
|
|
area->area_tag, lvl);
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area->lsp_regenerate_pending[lvl - 1])
|
2015-11-10 18:43:34 +01:00
|
|
|
{
|
|
|
|
struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
|
|
|
|
sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
|
|
|
|
" (Due in %lld.%03lld seconds)", area->area_tag,
|
|
|
|
(long long)remain.tv_sec, (long long)remain.tv_usec / 1000);
|
|
|
|
continue;
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
lsp = lsp_search (id, area->lspdb[lvl - 1]);
|
|
|
|
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;
|
|
|
|
}
|
2012-03-24 16:35:20 +01: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);
|
2012-03-24 16:35:20 +01:00
|
|
|
THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
|
2004-09-10 22:48:21 +02:00
|
|
|
diff = now - lsp->last_generated;
|
2012-03-24 16:35:20 +01:00
|
|
|
if (diff < area->lsp_gen_interval[lvl - 1])
|
|
|
|
{
|
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);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
else
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2012-10-26 11:18:19 +02:00
|
|
|
/*
|
|
|
|
* lsps are not regenerated if lsp_regenerate function is called
|
|
|
|
* directly. However if the lsp_regenerate call is queued for
|
|
|
|
* later execution it works.
|
|
|
|
*/
|
2015-11-10 18:43:34 +01:00
|
|
|
timeout = 100;
|
|
|
|
sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
|
|
|
|
" Scheduling for execution in %ld ms.", area->area_tag, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
area->lsp_regenerate_pending[lvl - 1] = 1;
|
|
|
|
if (lvl == IS_LEVEL_1)
|
|
|
|
{
|
|
|
|
THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
|
|
|
|
lsp_l1_refresh, area, timeout);
|
|
|
|
}
|
|
|
|
else if (lvl == IS_LEVEL_2)
|
|
|
|
{
|
|
|
|
THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
|
|
|
|
lsp_l2_refresh, area, timeout);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
if (all_pseudo)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
|
|
|
|
lsp_regenerate_schedule_pseudo (circuit, level);
|
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
|
|
|
|
*/
|
2005-01-18 14:53:33 +01:00
|
|
|
static void
|
2004-09-10 22:48:21 +02:00
|
|
|
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 is_neigh *is_neigh;
|
2005-09-26 19:39:48 +02:00
|
|
|
struct te_is_neigh *te_is_neigh;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct es_neigh *es_neigh;
|
|
|
|
struct list *adj_list;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *node;
|
2015-11-12 14:21:47 +01:00
|
|
|
struct isis_area *area = circuit->area;
|
|
|
|
|
|
|
|
lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
|
|
|
|
area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
|
|
|
|
circuit->interface->name, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp->level = level;
|
2012-03-24 16:35:20 +01:00
|
|
|
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
|
2015-08-25 01:40:14 +02:00
|
|
|
lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
|
|
|
|
circuit->area->attached_bit);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* add self to IS neighbours
|
|
|
|
*/
|
2005-09-26 19:39:48 +02:00
|
|
|
if (circuit->area->oldmetric)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2005-09-26 19:39:48 +02:00
|
|
|
if (lsp->tlv_data.is_neighs == NULL)
|
|
|
|
{
|
|
|
|
lsp->tlv_data.is_neighs = list_new ();
|
|
|
|
lsp->tlv_data.is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
|
|
|
|
|
|
|
|
memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
listnode_add (lsp->tlv_data.is_neighs, is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
|
|
|
|
area->area_tag, sysid_print(is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(is_neigh->neigh_id));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2005-09-26 19:39:48 +02:00
|
|
|
if (circuit->area->newmetric)
|
|
|
|
{
|
|
|
|
if (lsp->tlv_data.te_is_neighs == NULL)
|
|
|
|
{
|
|
|
|
lsp->tlv_data.te_is_neighs = list_new ();
|
|
|
|
lsp->tlv_data.te_is_neighs->del = free_tlv;
|
|
|
|
}
|
|
|
|
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
|
2005-05-03 11:27:23 +02:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
|
|
|
|
area->area_tag, sysid_print(te_is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(te_is_neigh->neigh_id));
|
2005-09-26 19:39:48 +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);
|
|
|
|
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
if (adj->level & level)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
|
|
|
|
(level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
|
2005-09-26 19:39:48 +02:00
|
|
|
adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
|
2012-03-24 16:35:20 +01:00
|
|
|
(level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
/* an IS neighbour -> add it */
|
2005-09-26 19:39:48 +02:00
|
|
|
if (circuit->area->oldmetric)
|
|
|
|
{
|
|
|
|
is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
|
2005-05-03 11:27:23 +02:00
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
listnode_add (lsp->tlv_data.is_neighs, is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
|
|
|
|
area->area_tag, sysid_print(is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(is_neigh->neigh_id));
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
|
|
|
if (circuit->area->newmetric)
|
|
|
|
{
|
|
|
|
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
|
|
|
|
sizeof (struct te_is_neigh));
|
|
|
|
memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
|
|
|
|
area->area_tag, sysid_print(te_is_neigh->neigh_id),
|
|
|
|
LSP_PSEUDO_ID(te_is_neigh->neigh_id));
|
2005-09-26 19:39:48 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
|
2004-09-10 22:48:21 +02:00
|
|
|
{
|
|
|
|
/* an ES neigbour add it, if we are building level 1 LSP */
|
|
|
|
/* FIXME: the tlv-format is hard to use here */
|
|
|
|
if (lsp->tlv_data.es_neighs == NULL)
|
|
|
|
{
|
|
|
|
lsp->tlv_data.es_neighs = list_new ();
|
|
|
|
lsp->tlv_data.es_neighs->del = free_tlv;
|
|
|
|
}
|
2005-05-03 11:27:23 +02:00
|
|
|
es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
|
2005-09-01 19:52:33 +02:00
|
|
|
listnode_add (lsp->tlv_data.es_neighs, es_neigh);
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
|
|
|
|
area->area_tag, sysid_print(es_neigh->first_es_neigh));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2015-11-12 14:21:47 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
|
|
|
|
area->area_tag, sysid_print(adj->sysid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
|
|
|
|
area->area_tag, sysid_print(adj->sysid));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
list_delete (adj_list);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2015-11-12 14:21:47 +01:00
|
|
|
lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
|
|
|
|
|
2005-09-03 18:29:40 +02:00
|
|
|
/* Reset endp of stream to overwrite only TLV part of it. */
|
2005-09-04 23:36:36 +02:00
|
|
|
stream_reset (lsp->pdu);
|
2005-09-03 18:29:40 +02:00
|
|
|
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Add the authentication info if it's present
|
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_auth_add (lsp);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
|
|
|
|
tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
|
|
|
|
|
2005-09-26 19:39:48 +02:00
|
|
|
if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
|
|
|
|
tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
|
|
|
|
tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
|
|
|
|
|
2005-02-09 16:51:56 +01:00
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* Recompute authentication and checksum information */
|
|
|
|
lsp_auth_update (lsp);
|
|
|
|
fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
|
|
|
|
ntohs (lsp->lsp_header->pdu_len) - 12, 12);
|
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)
|
|
|
|
{
|
|
|
|
dict_t *lspdb = circuit->area->lspdb[level - 1];
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
u_int16_t rem_lifetime, refresh_time;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_FRAGMENT (lsp_id) = 0;
|
|
|
|
LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If for some reason have a pseudo LSP in the db already -> regenerate
|
|
|
|
*/
|
|
|
|
if (lsp_search (lsp_id, lspdb))
|
|
|
|
return lsp_regenerate_schedule_pseudo (circuit, level);
|
|
|
|
|
|
|
|
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,
|
2015-08-25 01:40:14 +02:00
|
|
|
circuit->area->is_type | circuit->area->attached_bit,
|
|
|
|
0, level);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->area = circuit->area;
|
|
|
|
|
|
|
|
lsp_build_pseudo (lsp, circuit, level);
|
|
|
|
|
|
|
|
lsp->own_lsp = 1;
|
|
|
|
lsp_insert (lsp, lspdb);
|
|
|
|
lsp_set_all_srmflags (lsp);
|
|
|
|
|
|
|
|
refresh_time = lsp_refresh_time (lsp, rem_lifetime);
|
|
|
|
THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
|
|
|
|
circuit->lsp_regenerate_pending[level - 1] = 0;
|
|
|
|
if (level == IS_LEVEL_1)
|
|
|
|
THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
|
|
|
|
lsp_l1_refresh_pseudo, circuit, refresh_time);
|
|
|
|
else if (level == IS_LEVEL_2)
|
|
|
|
THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
|
|
|
|
lsp_l2_refresh_pseudo, circuit, refresh_time);
|
|
|
|
|
|
|
|
if (isis->debugs & DEBUG_UPDATE_PACKETS)
|
|
|
|
{
|
|
|
|
zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
|
|
|
|
"seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
|
|
|
|
circuit->area->area_tag, level,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (lsp->lsp_header->pdu_len),
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->rem_lifetime),
|
|
|
|
refresh_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
2005-01-18 14:53:33 +01:00
|
|
|
static int
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
dict_t *lspdb = circuit->area->lspdb[level - 1];
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
|
2012-03-24 16:35:20 +01:00
|
|
|
u_int16_t rem_lifetime, refresh_time;
|
|
|
|
|
|
|
|
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;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
memcpy (lsp_id, 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;
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp = lsp_search (lsp_id, lspdb);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (!lsp)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
|
|
|
|
level, rawlspid_print (lsp_id));
|
2004-09-10 22:48:21 +02:00
|
|
|
return ISIS_ERROR;
|
|
|
|
}
|
|
|
|
lsp_clear_data (lsp);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
lsp_build_pseudo (lsp, circuit, level);
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
|
2015-08-25 01:40:14 +02:00
|
|
|
lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
|
|
|
|
circuit->area->attached_bit);
|
2012-03-24 16:35:20 +01:00
|
|
|
rem_lifetime = lsp_rem_lifetime (circuit->area, level);
|
|
|
|
lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_inc_seqnum (lsp, 0);
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp->last_generated = time (NULL);
|
|
|
|
lsp_set_all_srmflags (lsp);
|
|
|
|
|
|
|
|
refresh_time = lsp_refresh_time (lsp, rem_lifetime);
|
|
|
|
if (level == IS_LEVEL_1)
|
|
|
|
THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
|
|
|
|
lsp_l1_refresh_pseudo, circuit, refresh_time);
|
|
|
|
else if (level == IS_LEVEL_2)
|
|
|
|
THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
|
|
|
|
lsp_l2_refresh_pseudo, circuit, refresh_time);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
|
|
|
if (isis->debugs & DEBUG_UPDATE_PACKETS)
|
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
|
|
|
|
"seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
|
|
|
|
circuit->area->area_tag, level,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (lsp->lsp_header->pdu_len),
|
|
|
|
ntohl (lsp->lsp_header->seq_num),
|
|
|
|
ntohs (lsp->lsp_header->checksum),
|
|
|
|
ntohs (lsp->lsp_header->rem_lifetime),
|
|
|
|
refresh_time);
|
2004-09-10 22:48:21 +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
|
|
|
|
*/
|
|
|
|
static int
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_l1_refresh_pseudo (struct thread *thread)
|
|
|
|
{
|
|
|
|
struct isis_circuit *circuit;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_char id[ISIS_SYS_ID_LEN + 2];
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
circuit = THREAD_ARG (thread);
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID (id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT (id) = 0;
|
|
|
|
lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
|
|
|
|
return ISIS_ERROR;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static int
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_l2_refresh_pseudo (struct thread *thread)
|
|
|
|
{
|
|
|
|
struct isis_circuit *circuit;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_char id[ISIS_SYS_ID_LEN + 2];
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
circuit = THREAD_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)
|
|
|
|
{
|
|
|
|
memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID (id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT (id) = 0;
|
|
|
|
lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
|
|
|
|
return ISIS_ERROR;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
|
|
|
|
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;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (circuit == NULL ||
|
|
|
|
circuit->circ_type != CIRCUIT_T_BROADCAST ||
|
|
|
|
circuit->state != C_STATE_UP)
|
|
|
|
return ISIS_OK;
|
2003-12-23 09:09:43 +01: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);
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
|
|
|
|
LSP_FRAGMENT (lsp_id) = 0;
|
|
|
|
now = time (NULL);
|
2004-09-10 22:48:21 +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);
|
|
|
|
|
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;
|
|
|
|
}
|
2003-12-23 09:09:43 +01: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (circuit->lsp_regenerate_pending[lvl - 1])
|
|
|
|
{
|
|
|
|
struct timeval remain =
|
|
|
|
thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
|
|
|
sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
|
|
|
|
" (Due in %lld.%03lld seconds)", area->area_tag,
|
|
|
|
(long long)remain.tv_sec, (long long)remain.tv_usec/1000);
|
|
|
|
continue;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
|
|
|
|
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;
|
|
|
|
}
|
2003-12-23 09:09:43 +01: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);
|
2012-03-24 16:35:20 +01:00
|
|
|
THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
|
|
|
|
diff = now - lsp->last_generated;
|
|
|
|
if (diff < circuit->area->lsp_gen_interval[lvl - 1])
|
|
|
|
{
|
2015-11-10 18:43:34 +01:00
|
|
|
timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff);
|
|
|
|
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("ISIS (%s): Last generation was more than lsp_gen_interval ago."
|
|
|
|
" Scheduling for execution in %ld ms.", area->area_tag, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
circuit->lsp_regenerate_pending[lvl - 1] = 1;
|
|
|
|
|
|
|
|
if (lvl == IS_LEVEL_1)
|
|
|
|
{
|
|
|
|
THREAD_TIMER_MSEC_ON(master,
|
|
|
|
circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
|
|
|
|
lsp_l1_refresh_pseudo, circuit, timeout);
|
|
|
|
}
|
|
|
|
else if (lvl == IS_LEVEL_2)
|
|
|
|
{
|
|
|
|
THREAD_TIMER_MSEC_ON(master,
|
|
|
|
circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
|
|
|
|
lsp_l2_refresh_pseudo, circuit, timeout);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
}
|
2003-12-23 09:09:43 +01: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
|
|
|
|
* - set LSPs with SRMflag set for sending
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
int
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp_tick (struct thread *thread)
|
|
|
|
{
|
|
|
|
struct isis_area *area;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
struct isis_lsp *lsp;
|
|
|
|
struct list *lsp_list;
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *lspnode, *cnode;
|
2003-12-23 09:09:43 +01:00
|
|
|
dnode_t *dnode, *dnode_next;
|
|
|
|
int level;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_int16_t rem_lifetime;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
lsp_list = list_new ();
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
area = THREAD_ARG (thread);
|
|
|
|
assert (area);
|
2004-09-10 23:19:13 +02:00
|
|
|
area->t_tick = NULL;
|
2004-09-10 22:48:21 +02:00
|
|
|
THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Build a list of LSPs with (any) SRMflag set
|
|
|
|
* and removed the ones that have aged out
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
for (level = 0; level < ISIS_LEVELS; level++)
|
|
|
|
{
|
|
|
|
if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
for (dnode = dict_first (area->lspdb[level]);
|
|
|
|
dnode != NULL; dnode = dnode_next)
|
|
|
|
{
|
|
|
|
dnode_next = dict_next (area->lspdb[level], dnode);
|
|
|
|
lsp = dnode_get (dnode);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 = ntohs(lsp->lsp_header->rem_lifetime);
|
|
|
|
lsp_set_time (lsp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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->lsp_header->seq_num != 0)
|
|
|
|
{
|
|
|
|
/* 7.3.16.4 a) set SRM flags on all */
|
|
|
|
lsp_set_all_srmflags (lsp);
|
|
|
|
/* 7.3.16.4 b) retain only the header FIXME */
|
|
|
|
/* 7.3.16.4 c) record the time to purge FIXME */
|
|
|
|
/* run/schedule spf */
|
|
|
|
/* isis_spf_schedule is called inside lsp_destroy() below;
|
|
|
|
* so it is not needed here. */
|
|
|
|
/* isis_spf_schedule (lsp->area, lsp->level); */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lsp->age_out == 0)
|
|
|
|
{
|
|
|
|
zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
|
|
|
|
area->area_tag,
|
|
|
|
lsp->level,
|
|
|
|
rawlspid_print (lsp->lsp_header->lsp_id),
|
|
|
|
ntohl (lsp->lsp_header->seq_num));
|
|
|
|
lsp_destroy (lsp);
|
|
|
|
lsp = NULL;
|
|
|
|
dict_delete_free (area->lspdb[level], dnode);
|
|
|
|
}
|
|
|
|
else if (flags_any_set (lsp->SRMflags))
|
|
|
|
listnode_add (lsp_list, lsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send LSPs on circuits indicated by the SRMflags
|
|
|
|
*/
|
|
|
|
if (listcount (lsp_list) > 0)
|
|
|
|
{
|
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_RO (area->circuit_list, cnode, circuit))
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
int diff = time (NULL) - circuit->lsp_queue_last_cleared;
|
|
|
|
if (circuit->lsp_queue == NULL ||
|
|
|
|
diff < MIN_LSP_TRANS_INTERVAL)
|
|
|
|
continue;
|
2005-09-28 20:45:54 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
if (circuit->upadjcount[lsp->level - 1] &&
|
|
|
|
ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
|
|
|
|
{
|
|
|
|
/* Add the lsp only if it is not already in lsp
|
|
|
|
* queue */
|
|
|
|
if (! listnode_lookup (circuit->lsp_queue, lsp))
|
|
|
|
{
|
|
|
|
listnode_add (circuit->lsp_queue, lsp);
|
|
|
|
thread_add_event (master, send_lsp, circuit, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
list_delete_all_node (lsp_list);
|
|
|
|
}
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
list_delete (lsp_list);
|
|
|
|
|
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_lsp *lsp;
|
2012-03-24 16:35:20 +01:00
|
|
|
u_int16_t seq_num;
|
|
|
|
u_int8_t lsp_bits;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!lsp)
|
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* store old values */
|
|
|
|
seq_num = lsp->lsp_header->seq_num;
|
|
|
|
lsp_bits = lsp->lsp_header->lsp_bits;
|
|
|
|
|
|
|
|
/* reset stream */
|
|
|
|
lsp_clear_data (lsp);
|
|
|
|
stream_reset (lsp->pdu);
|
|
|
|
|
|
|
|
/* update header */
|
|
|
|
lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
|
|
|
memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
|
|
|
|
lsp->lsp_header->checksum = 0;
|
|
|
|
lsp->lsp_header->seq_num = seq_num;
|
|
|
|
lsp->lsp_header->rem_lifetime = 0;
|
|
|
|
lsp->lsp_header->lsp_bits = lsp_bits;
|
|
|
|
lsp->level = level;
|
|
|
|
lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
|
|
|
|
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add and update the authentication info if its present
|
|
|
|
*/
|
|
|
|
lsp_auth_add (lsp);
|
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
|
|
|
lsp_auth_update (lsp);
|
|
|
|
fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
|
|
|
|
ntohs (lsp->lsp_header->pdu_len) - 12, 12);
|
|
|
|
|
|
|
|
lsp_set_all_srmflags (lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Purge own LSP that is received and we don't have.
|
|
|
|
* -> Do as in 7.3.16.4
|
|
|
|
*/
|
|
|
|
void
|
2015-11-10 18:21:44 +01:00
|
|
|
lsp_purge_non_exist (int level,
|
|
|
|
struct isis_link_state_hdr *lsp_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;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2015-11-10 18:43:31 +01:00
|
|
|
lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
|
2012-03-24 16:35:20 +01:00
|
|
|
fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
|
2004-09-10 22:48:21 +02:00
|
|
|
: L2_LINK_STATE);
|
|
|
|
lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
|
|
|
|
ISIS_FIXED_HDR_LEN);
|
2003-12-23 09:09:43 +01:00
|
|
|
memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
|
2012-03-24 16:35:20 +01:00
|
|
|
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Set the remaining lifetime to 0
|
|
|
|
*/
|
|
|
|
lsp->lsp_header->rem_lifetime = 0;
|
2012-03-24 16:35:20 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add and update the authentication info if its present
|
|
|
|
*/
|
|
|
|
lsp_auth_add (lsp);
|
|
|
|
lsp_auth_update (lsp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the PDU length to header plus any authentication TLV.
|
|
|
|
*/
|
|
|
|
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Put the lsp into LSPdb
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
lsp_insert (lsp, area->lspdb[lsp->level - 1]);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Send in to whole area
|
|
|
|
*/
|
2012-03-24 16:35:20 +01:00
|
|
|
lsp_set_all_srmflags (lsp);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
void lsp_set_all_srmflags (struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
|
|
|
|
assert (lsp);
|
|
|
|
|
|
|
|
ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
|
|
|
|
|
|
|
|
if (lsp->area)
|
|
|
|
{
|
|
|
|
struct list *circuit_list = lsp->area->circuit_list;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
|
|
|
|
{
|
|
|
|
ISIS_SET_FLAG(lsp->SRMflags, circuit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|