Merge pull request #2875 from opensourcerouting/fabricd

OpenFabric support
This commit is contained in:
Donald Sharp 2018-09-08 13:48:48 -04:00 committed by GitHub
commit 714e135429
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 5272 additions and 3145 deletions

View File

@ -388,6 +388,8 @@ AC_ARG_ENABLE(sharpd,
AS_HELP_STRING([--enable-sharpd], [build sharpd]))
AC_ARG_ENABLE(staticd,
AS_HELP_STRING([--disable-staticd], [do not build staticd]))
AC_ARG_ENABLE(fabricd,
AS_HELP_STRING([--disable-fabricd], [do not build fabricd]))
AC_ARG_ENABLE(bgp-announce,
AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement]))
AC_ARG_ENABLE(bgp-vnc,
@ -1208,11 +1210,12 @@ case "$host_os" in
if test $ac_cv_header_net_bpf_h = no; then
if test $ac_cv_header_sys_dlpi_h = no; then
AC_MSG_RESULT(none)
if test "${enable_isisd}" = yes; then
if test "${enable_isisd}" = yes -o "${enable_fabricd}" = yes; then
AC_MSG_FAILURE([IS-IS support requested but no packet backend found])
fi
AC_MSG_WARN([*** IS-IS support will not be built ***])
enable_isisd="no"
enable_fabricd="no"
else
AC_MSG_RESULT(DLPI)
fi
@ -1440,6 +1443,7 @@ AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no")
AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no")
AM_CONDITIONAL(SHARPD, test "${enable_sharpd}" = "yes")
AM_CONDITIONAL(STATICD, test "${enable_staticd}" != "no")
AM_CONDITIONAL(FABRICD, test "${enable_fabricd}" != "no")
if test "${enable_bgp_announce}" = "no";then
AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra)

View File

@ -125,6 +125,7 @@ These following options control the daemon's VTY (interactive command line) inte
pbrd 2615
staticd 2616
bfdd 2617
fabricd 2618
Port 2607 is used for ospfd's Opaque LSA API.

View File

@ -333,6 +333,7 @@ man_pages = [
('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1),
('frr', 'frr', 'a systemd interaction script', [], 1),
('bfdd', 'bfdd', fwfrr.format("a bfd"), [], 8),
('fabricd', 'fabricd', fwfrr.format("an OpenFabric "), [], 8),
]
# -- Options for Texinfo output -------------------------------------------

38
doc/manpages/fabricd.rst Normal file
View File

@ -0,0 +1,38 @@
*******
FABRICD
*******
.. include:: defines.rst
.. |DAEMON| replace:: fabricd
SYNOPSIS
========
|DAEMON| |synopsis-options-hv|
|DAEMON| |synopsis-options|
DESCRIPTION
===========
|DAEMON| is a routing component that works with the FRRouting routing engine.
OPTIONS
=======
OPTIONS available for the |DAEMON| command:
.. include:: common-options.rst
FILES
=====
|INSTALL_PREFIX_SBIN|/|DAEMON|
The default location of the |DAEMON| binary.
|INSTALL_PREFIX_ETC|/|DAEMON|.conf
The default location of the |DAEMON| config file.
$(PWD)/|DAEMON|.log
If the |DAEMON| process is configured to output logs to a file, then you
will find this file in the directory where you started |DAEMON|.
.. include:: epilogue.rst

View File

@ -10,6 +10,7 @@
bgpd
eigrpd
isisd
fabricd
ldpd
nhrpd
ospf6d

View File

@ -9,6 +9,7 @@ man_RSTFILES = \
doc/manpages/defines.rst \
doc/manpages/eigrpd.rst \
doc/manpages/epilogue.rst \
doc/manpages/fabricd.rst \
doc/manpages/frr.rst \
doc/manpages/index.rst \
doc/manpages/isisd.rst \

404
doc/user/fabricd.rst Normal file
View File

@ -0,0 +1,404 @@
.. _fabricd:
**********
OpenFabric
**********
OpenFabric, specified in :t:`draft-white-openfabric-06.txt`, is a routing
protocol derived from IS-IS, providing link-state routing with efficient
flooding for topologies like spine-leaf networks.
FRR implements OpenFabric in a daemon called *fabricd*
.. _configuring-fabricd:
Configuring fabricd
===================
There are no *fabricd* specific options. Common options can be specified
(:ref:`common-invocation-options`) to *fabricd*. *fabricd* needs to acquire
interface information from *zebra* in order to function. Therefore *zebra* must
be running before invoking *fabricd*. Also, if *zebra* is restarted then *fabricd*
must be too.
Like other daemons, *fabricd* configuration is done in an OpenFabric specific
configuration file :file:`fabricd.conf`.
.. _openfabric-router:
OpenFabric router
=================
To enable the OpenFabric routing protocol, an OpenFabric router needs to be created
in the configuration:
.. index:: router openfabric WORD
.. clicmd:: router openfabric WORD
.. index:: no router openfabric WORD
.. clicmd:: no router openfabric WORD
Enable or disable the OpenFabric process by specifying the OpenFabric domain with
'WORD'.
.. index:: net XX.XXXX. ... .XXX.XX
.. clicmd:: net XX.XXXX. ... .XXX.XX
.. index:: no net XX.XXXX. ... .XXX.XX
.. clicmd:: no net XX.XXXX. ... .XXX.XX
Set/Unset network entity title (NET) provided in ISO format.
.. index:: domain-password [clear | md5] <password>
.. clicmd:: domain-password [clear | md5] <password>
.. index:: no domain-password
.. clicmd:: no domain-password
Configure the authentication password for a domain, as clear text or md5 one.
.. index:: log-adjacency-changes
.. clicmd:: log-adjacency-changes
.. index:: no log-adjacency-changes
.. clicmd:: no log-adjacency-changes
Log changes in adjacency state.
.. index:: set-overload-bit
.. clicmd:: set-overload-bit
.. index:: no set-overload-bit
.. clicmd:: no set-overload-bit
Set overload bit to avoid any transit traffic.
.. index:: purge-originator
.. clicmd:: purge-originator
.. index:: no purge-originator
.. clicmd:: no purge-originator
Enable or disable :rfc:`6232` purge originator identification.
.. index:: fabric-tier (0-14)
.. clicmd:: fabric-tier (0-14)
.. index:: no fabric-tier
.. clicmd:: no fabric-tier
Configure a static tier number to advertise as location in the fabric
.. _openfabric-timer:
OpenFabric Timer
================
.. index:: lsp-gen-interval (1-120)
.. clicmd:: lsp-gen-interval (1-120)
.. index:: no lsp-gen-interval
.. clicmd:: no lsp-gen-interval
Set minimum interval in seconds between regenerating same LSP.
.. index:: lsp-refresh-interval (1-65235)
.. clicmd:: lsp-refresh-interval (1-65235)
.. index:: no lsp-refresh-interval
.. clicmd:: no lsp-refresh-interval
Set LSP refresh interval in seconds.
.. index:: max-lsp-lifetime (360-65535)
.. clicmd:: max-lsp-lifetime (360-65535)
.. index:: no max-lsp-lifetime
.. clicmd:: no max-lsp-lifetime
Set LSP maximum LSP lifetime in seconds.
.. index:: spf-interval (1-120)
.. clicmd:: spf-interval (1-120)
.. index:: no spf-interval
.. clicmd:: no spf-interval
Set minimum interval between consecutive SPF calculations in seconds.
.. _openfabric-interface:
OpenFabric interface
====================
.. index:: ip router openfabric WORD
.. clicmd:: ip router openfabric WORD
.. index:: no ip router openfabric WORD
.. clicmd:: no ip router openfabric WORD
.. _ip-router-openfabric-word:
Activate OpenFabric on this interface. Note that the name
of OpenFabric instance must be the same as the one used to configure the
routing process (see command :clicmd:`router openfabric WORD`).
.. index:: openfabric csnp-interval (1-600)
.. clicmd:: openfabric csnp-interval (1-600)
.. index:: no openfabric csnp-interval
.. clicmd:: no openfabric csnp-interval
Set CSNP interval in seconds.
.. index:: openfabric hello-interval (1-600)
.. clicmd:: openfabric hello-interval (1-600)
.. index:: no openfabric hello-interval
.. clicmd:: no openfabric hello-interval
Set Hello interval in seconds.
.. index:: openfabric hello-multiplier (2-100)
.. clicmd:: openfabric hello-multiplier (2-100)
.. index:: no openfabric hello-multiplier
.. clicmd:: no openfabric hello-multiplier
Set multiplier for Hello holding time.
.. index:: openfabric metric (0-16777215)
.. clicmd:: openfabric metric (0-16777215)
.. index:: no openfabric metric
.. clicmd:: no openfabric metric
Set interface metric value.
.. index:: openfabric passive
.. clicmd:: openfabric passive
.. index:: no openfabric passive
.. clicmd:: no openfabric passive
Configure the passive mode for this interface.
.. index:: openfabric password [clear | md5] <password>
.. clicmd:: openfabric password [clear | md5] <password>
.. index:: no openfabric password
.. clicmd:: no openfabric password
Configure the authentication password (clear or encoded text) for the
interface.
.. index:: openfabric psnp-interval (1-120)
.. clicmd:: openfabric psnp-interval (1-120)
.. index:: no openfabric psnp-interval
.. clicmd:: no openfabric psnp-interval
Set PSNP interval in seconds.
.. _showing-openfabric-information:
Showing OpenFabric information
==============================
.. index:: show openfabric summary
.. clicmd:: show openfabric summary
Show summary information about OpenFabric.
.. index:: show openfabric hostname
.. clicmd:: show openfabric hostname
Show which hostnames are associated with which OpenFabric system ids.
.. index:: show openfabric interface
.. clicmd:: show openfabric interface
.. index:: show openfabric interface detail
.. clicmd:: show openfabric interface detail
.. index:: show openfabric interface <interface name>
.. clicmd:: show openfabric interface <interface name>
Show state and configuration of specified OpenFabric interface, or all interfaces
if no interface is given with or without details.
.. index:: show openfabric neighbor
.. clicmd:: show openfabric neighbor
.. index:: show openfabric neighbor <System Id>
.. clicmd:: show openfabric neighbor <System Id>
.. index:: show openfabric neighbor detail
.. clicmd:: show openfabric neighbor detail
Show state and information of specified OpenFabric neighbor, or all neighbors if
no system id is given with or without details.
.. index:: show openfabric database
.. clicmd:: show openfabric database
.. index:: show openfabric database [detail]
.. clicmd:: show openfabric database [detail]
.. index:: show openfabric database <LSP id> [detail]
.. clicmd:: show openfabric database <LSP id> [detail]
.. index:: show openfabric database detail <LSP id>
.. clicmd:: show openfabric database detail <LSP id>
Show the OpenFabric database globally, for a specific LSP id without or with
details.
.. index:: show openfabric topology
.. clicmd:: show openfabric topology
Show calculated OpenFabric paths and associated topology information.
.. _debugging-openfabric:
Debugging OpenFabric
====================
.. index:: debug openfabric adj-packets
.. clicmd:: debug openfabric adj-packets
.. index:: no debug openfabric adj-packets
.. clicmd:: no debug openfabric adj-packets
OpenFabric Adjacency related packets.
.. index:: debug openfabric checksum-errors
.. clicmd:: debug openfabric checksum-errors
.. index:: no debug openfabric checksum-errors
.. clicmd:: no debug openfabric checksum-errors
OpenFabric LSP checksum errors.
.. index:: debug openfabric events
.. clicmd:: debug openfabric events
.. index:: no debug openfabric events
.. clicmd:: no debug openfabric events
OpenFabric Events.
.. index:: debug openfabric local-updates
.. clicmd:: debug openfabric local-updates
.. index:: no debug openfabric local-updates
.. clicmd:: no debug openfabric local-updates
OpenFabric local update packets.
.. index:: debug openfabric lsp-gen
.. clicmd:: debug openfabric lsp-gen
.. index:: no debug openfabric lsp-gen
.. clicmd:: no debug openfabric lsp-gen
Generation of own LSPs.
.. index:: debug openfabric lsp-sched
.. clicmd:: debug openfabric lsp-sched
.. index:: no debug openfabric lsp-sched
.. clicmd:: no debug openfabric lsp-sched
Debug scheduling of generation of own LSPs.
.. index:: debug openfabric packet-dump
.. clicmd:: debug openfabric packet-dump
.. index:: no debug openfabric packet-dump
.. clicmd:: no debug openfabric packet-dump
OpenFabric packet dump.
.. index:: debug openfabric protocol-errors
.. clicmd:: debug openfabric protocol-errors
.. index:: no debug openfabric protocol-errors
.. clicmd:: no debug openfabric protocol-errors
OpenFabric LSP protocol errors.
.. index:: debug openfabric route-events
.. clicmd:: debug openfabric route-events
.. index:: no debug openfabric route-events
.. clicmd:: no debug openfabric route-events
OpenFabric Route related events.
.. index:: debug openfabric snp-packets
.. clicmd:: debug openfabric snp-packets
.. index:: no debug openfabric snp-packets
.. clicmd:: no debug openfabric snp-packets
OpenFabric CSNP/PSNP packets.
.. index:: debug openfabric spf-events
.. clicmd:: debug openfabric spf-events
.. index:: debug openfabric spf-statistics
.. clicmd:: debug openfabric spf-statistics
.. index:: debug openfabric spf-triggers
.. clicmd:: debug openfabric spf-triggers
.. index:: no debug openfabric spf-events
.. clicmd:: no debug openfabric spf-events
.. index:: no debug openfabric spf-statistics
.. clicmd:: no debug openfabric spf-statistics
.. index:: no debug openfabric spf-triggers
.. clicmd:: no debug openfabric spf-triggers
OpenFabric Shortest Path First Events, Timing and Statistic Data and triggering
events.
.. index:: debug openfabric update-packets
.. clicmd:: debug openfabric update-packets
.. index:: no debug openfabric update-packets
.. clicmd:: no debug openfabric update-packets
Update related packets.
.. index:: show debugging openfabric
.. clicmd:: show debugging openfabric
Print which OpenFabric debug levels are active.
OpenFabric configuration example
================================
A simple example:
.. code-block:: frr
!
interface lo
ip address 192.0.2.1/32
ip router openfabric 1
ipv6 address 2001:db8::1/128
ipv6 router openfabric 1
!
interface eth0
ip router openfabric 1
ipv6 router openfabric 1
!
interface eth1
ip router openfabric 1
ipv6 router openfabric 1
!
router openfabric 1
net 49.0000.0000.0001.00

View File

@ -42,6 +42,7 @@ Protocols
bfd
bgp
babeld
fabricd
ldpd
eigrpd
isisd

View File

@ -139,6 +139,10 @@ options from the list below.
Do not build isisd.
.. option:: --disable-fabricd
Do not build fabricd.
.. option:: --enable-isis-topology
Enable IS-IS topology generator.

View File

@ -106,6 +106,14 @@ writing, *isisd* does not support multiple ISIS processes.
Set overload bit to avoid any transit traffic.
.. index:: purge-originator
.. clicmd:: purge-originator
.. index:: no purge-originator
.. clicmd:: no purge-originator
Enable or disable :rfc:`6232` purge originator identification.
.. _isis-timer:
ISIS Timer

View File

@ -32,6 +32,7 @@ systemd. The file initially looks like this:
staticd=no
pbrd=no
bfdd=no
fabricd=no
To enable a particular daemon, simply change the corresponding 'no' to 'yes'.
Subsequent service restarts should start the daemon.
@ -68,6 +69,7 @@ This file has several parts. Here is an example:
staticd_options=" --daemon -A 127.0.0.1"
pbrd_options=" --daemon -A 127.0.0.1"
bfdd_options=" --daemon -A 127.0.0.1"
fabricd_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
watchfrr_enable=yes
@ -139,6 +141,7 @@ add the following entries to :file:`/etc/services`.
ldpd 2612/tcp # LDPd vty
eigprd 2613/tcp # EIGRPd vty
bfdd 2617/tcp # bfdd vty
fabricd 2618/tcp # fabricd vty
If you use a FreeBSD newer than 2.2.8, the above entries are already added to

View File

@ -10,6 +10,7 @@ user_RSTFILES = \
doc/user/bugs.rst \
doc/user/conf.py \
doc/user/eigrpd.rst \
doc/user/fabricd.rst \
doc/user/filter.rst \
doc/user/glossary.rst \
doc/user/index.rst \

1
isisd/.gitignore vendored
View File

@ -2,6 +2,7 @@
Makefile.in
*.o
isisd
fabricd
.deps
isisd.conf
.nfs*

717
isisd/fabricd.c Normal file
View File

@ -0,0 +1,717 @@
/*
* IS-IS Rout(e)ing protocol - OpenFabric extensions
*
* Copyright (C) 2018 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "isisd/fabricd.h"
#include "isisd/isisd.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_tlvs.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_spf_private.h"
#include "isisd/isis_tx_queue.h"
DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry")
/* Tracks initial synchronization as per section 2.4
*
* We declare the sync complete once we have seen at least one
* CSNP and there are no more LSPs with SSN or SRM set.
*/
enum fabricd_sync_state {
FABRICD_SYNC_PENDING,
FABRICD_SYNC_STARTED,
FABRICD_SYNC_COMPLETE
};
struct fabricd {
struct isis_area *area;
enum fabricd_sync_state initial_sync_state;
time_t initial_sync_start;
struct isis_circuit *initial_sync_circuit;
struct thread *initial_sync_timeout;
struct isis_spftree *spftree;
struct skiplist *neighbors;
struct hash *neighbors_neighbors;
uint8_t tier;
uint8_t tier_config;
uint8_t tier_pending;
struct thread *tier_calculation_timer;
struct thread *tier_set_timer;
};
/* Code related to maintaining the neighbor lists */
struct neighbor_entry {
struct isis_vertex *vertex;
bool present;
};
static struct neighbor_entry *neighbor_entry_new(struct isis_vertex *vertex)
{
struct neighbor_entry *rv = XMALLOC(MTYPE_FABRICD_NEIGHBOR, sizeof(*rv));
rv->vertex = vertex;
return rv;
}
static void neighbor_entry_del(struct neighbor_entry *neighbor)
{
XFREE(MTYPE_FABRICD_NEIGHBOR, neighbor);
}
static void neighbor_entry_del_void(void *arg)
{
neighbor_entry_del((struct neighbor_entry *)arg);
}
static void neighbor_lists_clear(struct fabricd *f)
{
while (!skiplist_empty(f->neighbors))
skiplist_delete_first(f->neighbors);
hash_clean(f->neighbors_neighbors, neighbor_entry_del_void);
}
static unsigned neighbor_entry_hash_key(void *np)
{
struct neighbor_entry *n = np;
return jhash(n->vertex->N.id, ISIS_SYS_ID_LEN, 0x55aa5a5a);
}
static int neighbor_entry_hash_cmp(const void *a, const void *b)
{
const struct neighbor_entry *na = a, *nb = b;
return memcmp(na->vertex->N.id, nb->vertex->N.id, ISIS_SYS_ID_LEN) == 0;
}
static int neighbor_entry_list_cmp(void *a, void *b)
{
struct neighbor_entry *na = a, *nb = b;
return -memcmp(na->vertex->N.id, nb->vertex->N.id, ISIS_SYS_ID_LEN);
}
static struct neighbor_entry *neighbor_entry_lookup_list(struct skiplist *list,
const uint8_t *id)
{
struct isis_vertex querier;
isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
struct neighbor_entry n = {
.vertex = &querier
};
struct neighbor_entry *rv;
if (skiplist_search(list, &n, (void**)&rv))
return NULL;
if (!rv->present)
return NULL;
return rv;
}
static struct neighbor_entry *neighbor_entry_lookup_hash(struct hash *hash,
const uint8_t *id)
{
struct isis_vertex querier;
isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
struct neighbor_entry n = {
.vertex = &querier
};
struct neighbor_entry *rv = hash_lookup(hash, &n);
if (!rv || !rv->present)
return NULL;
return rv;
}
static void neighbor_lists_update(struct fabricd *f)
{
neighbor_lists_clear(f);
struct listnode *node;
struct isis_vertex *v;
for (ALL_QUEUE_ELEMENTS_RO(&f->spftree->paths, node, v)) {
if (!v->d_N || !VTYPE_IS(v->type))
continue;
if (v->d_N > 2)
break;
struct neighbor_entry *n = neighbor_entry_new(v);
if (v->d_N == 1) {
skiplist_insert(f->neighbors, n, n);
} else {
struct neighbor_entry *inserted;
inserted = hash_get(f->neighbors_neighbors, n, hash_alloc_intern);
assert(inserted == n);
}
}
}
struct fabricd *fabricd_new(struct isis_area *area)
{
struct fabricd *rv = XCALLOC(MTYPE_FABRICD_STATE, sizeof(*rv));
rv->area = area;
rv->initial_sync_state = FABRICD_SYNC_PENDING;
rv->spftree = isis_spftree_new(area);
rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp,
neighbor_entry_del_void);
rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key,
neighbor_entry_hash_cmp,
"Fabricd Neighbors");
rv->tier = rv->tier_config = ISIS_TIER_UNDEFINED;
return rv;
};
void fabricd_finish(struct fabricd *f)
{
if (f->initial_sync_timeout)
thread_cancel(f->initial_sync_timeout);
if (f->tier_calculation_timer)
thread_cancel(f->tier_calculation_timer);
if (f->tier_set_timer)
thread_cancel(f->tier_set_timer);
isis_spftree_del(f->spftree);
neighbor_lists_clear(f);
skiplist_free(f->neighbors);
hash_free(f->neighbors_neighbors);
}
static int fabricd_initial_sync_timeout(struct thread *thread)
{
struct fabricd *f = THREAD_ARG(thread);
zlog_info("OpenFabric: Initial synchronization on %s timed out!",
f->initial_sync_circuit->interface->name);
f->initial_sync_state = FABRICD_SYNC_PENDING;
f->initial_sync_circuit = NULL;
f->initial_sync_timeout = NULL;
return 0;
}
void fabricd_initial_sync_hello(struct isis_circuit *circuit)
{
struct fabricd *f = circuit->area->fabricd;
if (!f)
return;
if (f->initial_sync_state > FABRICD_SYNC_PENDING)
return;
f->initial_sync_state = FABRICD_SYNC_STARTED;
long timeout = 2 * circuit->hello_interval[1] * circuit->hello_multiplier[1];
f->initial_sync_circuit = circuit;
if (f->initial_sync_timeout)
return;
thread_add_timer(master, fabricd_initial_sync_timeout, f,
timeout, &f->initial_sync_timeout);
f->initial_sync_start = monotime(NULL);
zlog_info("OpenFabric: Started initial synchronization with %s on %s",
sysid_print(circuit->u.p2p.neighbor->sysid),
circuit->interface->name);
}
bool fabricd_initial_sync_is_in_progress(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return false;
if (f->initial_sync_state > FABRICD_SYNC_PENDING
&& f->initial_sync_state < FABRICD_SYNC_COMPLETE)
return true;
return false;
}
bool fabricd_initial_sync_is_complete(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return false;
return f->initial_sync_state == FABRICD_SYNC_COMPLETE;
}
struct isis_circuit *fabricd_initial_sync_circuit(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return NULL;
return f->initial_sync_circuit;
}
void fabricd_initial_sync_finish(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return;
if (monotime(NULL) - f->initial_sync_start < 5)
return;
zlog_info("OpenFabric: Initial synchronization on %s complete.",
f->initial_sync_circuit->interface->name);
f->initial_sync_state = FABRICD_SYNC_COMPLETE;
f->initial_sync_circuit = NULL;
thread_cancel(f->initial_sync_timeout);
f->initial_sync_timeout = NULL;
}
static void fabricd_bump_tier_calculation_timer(struct fabricd *f);
static void fabricd_set_tier(struct fabricd *f, uint8_t tier);
static uint8_t fabricd_calculate_fabric_tier(struct isis_area *area)
{
struct isis_spftree *local_tree = fabricd_spftree(area);
struct listnode *node;
struct isis_vertex *furthest_t0 = NULL,
*second_furthest_t0 = NULL;
struct isis_vertex *v;
for (ALL_QUEUE_ELEMENTS_RO(&local_tree->paths, node, v)) {
struct isis_lsp *lsp = lsp_for_vertex(local_tree, v);
if (!lsp || !lsp->tlvs
|| !lsp->tlvs->spine_leaf
|| !lsp->tlvs->spine_leaf->has_tier
|| lsp->tlvs->spine_leaf->tier != 0)
continue;
second_furthest_t0 = furthest_t0;
furthest_t0 = v;
}
if (!second_furthest_t0) {
zlog_info("OpenFabric: Could not find two T0 routers");
return ISIS_TIER_UNDEFINED;
}
zlog_info("OpenFabric: Found %s as furthest t0 from local system, dist == %"
PRIu32, rawlspid_print(furthest_t0->N.id), furthest_t0->d_N);
struct isis_spftree *remote_tree =
isis_run_hopcount_spf(area, furthest_t0->N.id, NULL);
struct isis_vertex *furthest_from_remote =
isis_vertex_queue_last(&remote_tree->paths);
if (!furthest_from_remote) {
zlog_info("OpenFabric: Found no furthest node in remote spf");
isis_spftree_del(remote_tree);
return ISIS_TIER_UNDEFINED;
} else {
zlog_info("OpenFabric: Found %s as furthest from remote dist == %"
PRIu32, rawlspid_print(furthest_from_remote->N.id),
furthest_from_remote->d_N);
}
int64_t tier = furthest_from_remote->d_N - furthest_t0->d_N;
isis_spftree_del(remote_tree);
if (tier < 0 || tier >= ISIS_TIER_UNDEFINED) {
zlog_info("OpenFabric: Calculated tier %" PRId64 " seems implausible",
tier);
return ISIS_TIER_UNDEFINED;
}
zlog_info("OpenFabric: Calculated %" PRId64 " as tier", tier);
return tier;
}
static int fabricd_tier_set_timer(struct thread *thread)
{
struct fabricd *f = THREAD_ARG(thread);
f->tier_set_timer = NULL;
fabricd_set_tier(f, f->tier_pending);
return 0;
}
static int fabricd_tier_calculation_cb(struct thread *thread)
{
struct fabricd *f = THREAD_ARG(thread);
uint8_t tier = ISIS_TIER_UNDEFINED;
f->tier_calculation_timer = NULL;
tier = fabricd_calculate_fabric_tier(f->area);
if (tier == ISIS_TIER_UNDEFINED)
return 0;
zlog_info("OpenFabric: Got tier %" PRIu8 " from algorithm. Arming timer.",
tier);
f->tier_pending = tier;
thread_add_timer(master, fabricd_tier_set_timer, f,
f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
&f->tier_set_timer);
return 0;
}
static void fabricd_bump_tier_calculation_timer(struct fabricd *f)
{
/* Cancel timer if we already know our tier */
if (f->tier != ISIS_TIER_UNDEFINED
|| f->tier_set_timer) {
if (f->tier_calculation_timer) {
thread_cancel(f->tier_calculation_timer);
f->tier_calculation_timer = NULL;
}
return;
}
/* If we need to calculate the tier, wait some
* time for the topology to settle before running
* the calculation */
if (f->tier_calculation_timer) {
thread_cancel(f->tier_calculation_timer);
f->tier_calculation_timer = NULL;
}
thread_add_timer(master, fabricd_tier_calculation_cb, f,
2 * f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
&f->tier_calculation_timer);
}
static void fabricd_set_tier(struct fabricd *f, uint8_t tier)
{
if (f->tier == tier)
return;
zlog_info("OpenFabric: Set own tier to %" PRIu8, tier);
f->tier = tier;
fabricd_bump_tier_calculation_timer(f);
lsp_regenerate_schedule(f->area, ISIS_LEVEL2, 0);
}
void fabricd_run_spf(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return;
isis_run_hopcount_spf(area, isis->sysid, f->spftree);
neighbor_lists_update(f);
fabricd_bump_tier_calculation_timer(f);
}
struct isis_spftree *fabricd_spftree(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return NULL;
return f->spftree;
}
void fabricd_configure_tier(struct isis_area *area, uint8_t tier)
{
struct fabricd *f = area->fabricd;
if (!f || f->tier_config == tier)
return;
f->tier_config = tier;
fabricd_set_tier(f, tier);
}
uint8_t fabricd_tier(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return ISIS_TIER_UNDEFINED;
return f->tier;
}
int fabricd_write_settings(struct isis_area *area, struct vty *vty)
{
struct fabricd *f = area->fabricd;
int written = 0;
if (!f)
return written;
if (f->tier_config != ISIS_TIER_UNDEFINED) {
vty_out(vty, " fabric-tier %" PRIu8 "\n", f->tier_config);
written++;
}
return written;
}
static void move_to_dnr(struct isis_lsp *lsp, struct neighbor_entry *n)
{
struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
n->present = false;
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("OpenFabric: Adding %s to DNR",
vid2string(n->vertex, buff, sizeof(buff)));
}
if (adj) {
isis_tx_queue_add(adj->circuit->tx_queue, lsp,
TX_LSP_CIRCUIT_SCOPED);
}
}
static void move_to_rf(struct isis_lsp *lsp, struct neighbor_entry *n)
{
struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
n->present = false;
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("OpenFabric: Adding %s to RF",
vid2string(n->vertex, buff, sizeof(buff)));
}
if (adj) {
isis_tx_queue_add(adj->circuit->tx_queue, lsp,
TX_LSP_NORMAL);
}
}
static void mark_neighbor_as_present(struct hash_backet *backet, void *arg)
{
struct neighbor_entry *n = backet->data;
n->present = true;
}
static void handle_firsthops(struct hash_backet *backet, void *arg)
{
struct isis_lsp *lsp = arg;
struct fabricd *f = lsp->area->fabricd;
struct isis_vertex *vertex = backet->data;
struct neighbor_entry *n;
n = neighbor_entry_lookup_list(f->neighbors, vertex->N.id);
if (n) {
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("Removing %s from NL as its in the reverse path",
vid2string(vertex, buff, sizeof(buff)));
}
n->present = false;
}
n = neighbor_entry_lookup_hash(f->neighbors_neighbors, vertex->N.id);
if (n) {
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("Removing %s from NN as its in the reverse path",
vid2string(vertex, buff, sizeof(buff)));
}
n->present = false;
}
}
void fabricd_lsp_flood(struct isis_lsp *lsp)
{
struct fabricd *f = lsp->area->fabricd;
assert(f);
void *cursor = NULL;
struct neighbor_entry *n;
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
zlog_debug("OpenFabric: Flooding LSP %s",
rawlspid_print(lsp->hdr.lsp_id));
}
/* Mark all elements in NL as present and move T0s into DNR */
while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
n->present = true;
struct isis_lsp *lsp = lsp_for_vertex(f->spftree, n->vertex);
if (!lsp || !lsp->tlvs || !lsp->tlvs->spine_leaf)
continue;
if (!lsp->tlvs->spine_leaf->has_tier
|| lsp->tlvs->spine_leaf->tier != 0)
continue;
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
zlog_debug("Moving %s to DNR because it's T0",
rawlspid_print(lsp->hdr.lsp_id));
}
move_to_dnr(lsp, n);
}
/* Mark all elements in NN as present */
hash_iterate(f->neighbors_neighbors, mark_neighbor_as_present, NULL);
struct isis_vertex *originator = isis_find_vertex(&f->spftree->paths,
lsp->hdr.lsp_id,
VTYPE_NONPSEUDO_TE_IS);
/* Remove all IS from NL and NN in the shortest path
* to the IS that originated the LSP */
if (originator)
hash_iterate(originator->firsthops, handle_firsthops, lsp);
/* Iterate over all remaining IS in NL */
cursor = NULL;
while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
if (!n->present)
continue;
struct isis_lsp *nlsp = lsp_for_vertex(f->spftree, n->vertex);
if (!nlsp || !nlsp->tlvs) {
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("Moving %s to DNR as it has no LSP",
vid2string(n->vertex, buff, sizeof(buff)));
}
move_to_dnr(lsp, n);
continue;
}
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("Considering %s from NL...",
vid2string(n->vertex, buff, sizeof(buff)));
}
/* For all neighbors of the NL IS check whether they are present
* in NN. If yes, remove from NN and set need_reflood. */
bool need_reflood = false;
struct isis_extended_reach *er;
for (er = (struct isis_extended_reach *)nlsp->tlvs->extended_reach.head;
er; er = er->next) {
struct neighbor_entry *nn;
nn = neighbor_entry_lookup_hash(f->neighbors_neighbors,
er->id);
if (nn) {
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
char buff[PREFIX2STR_BUFFER];
zlog_debug("Found neighbor %s in NN, removing it from NN and setting reflood.",
vid2string(nn->vertex, buff, sizeof(buff)));
}
nn->present = false;
need_reflood = true;
}
}
if (need_reflood)
move_to_rf(lsp, n);
else
move_to_dnr(lsp, n);
}
if (isis->debugs & DEBUG_FABRICD_FLOODING) {
zlog_debug("OpenFabric: Flooding algorithm complete.");
}
}
void fabricd_trigger_csnp(struct isis_area *area)
{
struct fabricd *f = area->fabricd;
if (!f)
return;
struct listnode *node;
struct isis_circuit *circuit;
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if (!circuit->t_send_csnp[1])
continue;
thread_cancel(circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
thread_add_timer_msec(master, send_l2_csnp, circuit,
isis_jitter(500, CSNP_JITTER),
&circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
}
}
struct list *fabricd_ip_addrs(struct isis_circuit *circuit)
{
if (circuit->ip_addrs && listcount(circuit->ip_addrs))
return circuit->ip_addrs;
if (!fabricd || !circuit->area || !circuit->area->circuit_list)
return NULL;
struct listnode *node;
struct isis_circuit *c;
for (ALL_LIST_ELEMENTS_RO(circuit->area->circuit_list, node, c)) {
if (c->circ_type != CIRCUIT_T_LOOPBACK)
continue;
if (!c->ip_addrs || !listcount(c->ip_addrs))
return NULL;
return c->ip_addrs;
}
return NULL;
}

27
isisd/fabricd.conf.sample Normal file
View File

@ -0,0 +1,27 @@
! -*- openfabric -*-
!
! fabricd sample configuration file
!
hostname fabricd
password foo
enable password foo
log stdout
!log file /tmp/fabricd.log
!
!
router openfabric DEAD
net 47.0023.0000.0003.0300.0100.0102.0304.0506.00
! lsp-lifetime 65535
! hostname isisd-router
! domain-password foobar
interface eth0
ip router openfabric DEAD
! openfabric hello-interval 5
! openfabric lsp-interval 1000
! -- optional
! openfabric retransmit-interval 10
! openfabric retransmit-throttle-interval
!

49
isisd/fabricd.h Normal file
View File

@ -0,0 +1,49 @@
/*
* IS-IS Rout(e)ing protocol - OpenFabric extensions
*
* Copyright (C) 2018 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FABRICD_H
#define FABRICD_H
struct fabricd;
struct isis_circuit;
struct isis_area;
struct isis_spftree;
struct isis_lsp;
struct vty;
struct fabricd *fabricd_new(struct isis_area *area);
void fabricd_finish(struct fabricd *f);
void fabricd_initial_sync_hello(struct isis_circuit *circuit);
bool fabricd_initial_sync_is_complete(struct isis_area *area);
bool fabricd_initial_sync_is_in_progress(struct isis_area *area);
struct isis_circuit *fabricd_initial_sync_circuit(struct isis_area *area);
void fabricd_initial_sync_finish(struct isis_area *area);
void fabricd_run_spf(struct isis_area *area);
struct isis_spftree *fabricd_spftree(struct isis_area *area);
void fabricd_configure_tier(struct isis_area *area, uint8_t tier);
uint8_t fabricd_tier(struct isis_area *area);
int fabricd_write_settings(struct isis_area *area, struct vty *vty);
void fabricd_lsp_flood(struct isis_lsp *lsp);
void fabricd_trigger_csnp(struct isis_area *area);
struct list *fabricd_ip_addrs(struct isis_circuit *circuit);
#endif

View File

@ -48,6 +48,7 @@
#include "isisd/isis_events.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/fabricd.h"
extern struct isis *isis;
@ -193,6 +194,9 @@ void isis_adj_process_threeway(struct isis_adjacency *adj,
}
}
if (next_tw_state != ISIS_THREEWAY_DOWN)
fabricd_initial_sync_hello(adj->circuit);
if (next_tw_state == ISIS_THREEWAY_DOWN) {
isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Neighbor restarted");
return;
@ -264,7 +268,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
circuit->upadjcount[level - 1]--;
if (circuit->upadjcount[level - 1] == 0)
isis_circuit_lsp_queue_clean(circuit);
isis_tx_queue_clean(circuit->tx_queue);
isis_event_adjacency_state_change(adj,
new_state);
@ -306,16 +310,21 @@ void isis_adj_state_change(struct isis_adjacency *adj,
adj->last_flap = time(NULL);
adj->flaps++;
/* 7.3.17 - going up on P2P -> send CSNP */
/* FIXME: yup, I know its wrong... but i will do
* it! (for now) */
send_csnp(circuit, level);
if (level == IS_LEVEL_1) {
thread_add_timer(master, send_l1_csnp,
circuit, 0,
&circuit->t_send_csnp[0]);
} else {
thread_add_timer(master, send_l2_csnp,
circuit, 0,
&circuit->t_send_csnp[1]);
}
} else if (new_state == ISIS_ADJ_DOWN) {
if (adj->circuit->u.p2p.neighbor == adj)
adj->circuit->u.p2p.neighbor = NULL;
circuit->upadjcount[level - 1]--;
if (circuit->upadjcount[level - 1] == 0)
isis_circuit_lsp_queue_clean(circuit);
isis_tx_queue_clean(circuit->tx_queue);
isis_event_adjacency_state_change(adj,
new_state);

View File

@ -45,7 +45,6 @@
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_lsp_hash.h"
#include "isisd/isis_pdu.h"
#include "isisd/isis_network.h"
#include "isisd/isis_misc.h"
@ -58,6 +57,7 @@
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@ -412,7 +412,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
isis_circuit_if_bind(circuit, ifp);
if (if_is_broadcast(ifp)) {
if (circuit->circ_type_config == CIRCUIT_T_P2P)
if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P)
circuit->circ_type = CIRCUIT_T_P2P;
else
circuit->circ_type = CIRCUIT_T_BROADCAST;
@ -495,29 +495,29 @@ static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit,
{
struct isis_area *area;
struct isis_lsp *lsp;
dnode_t *dnode, *dnode_next;
dnode_t *dnode;
int level;
assert(circuit);
area = circuit->area;
assert(area);
for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
if (level & circuit->is_type) {
if (area->lspdb[level - 1]
&& dict_count(area->lspdb[level - 1]) > 0) {
for (dnode = dict_first(area->lspdb[level - 1]);
dnode != NULL; dnode = dnode_next) {
dnode_next = dict_next(
area->lspdb[level - 1], dnode);
lsp = dnode_get(dnode);
if (is_set) {
ISIS_SET_FLAG(lsp->SRMflags,
circuit);
} else {
ISIS_CLEAR_FLAG(lsp->SRMflags,
circuit);
}
}
if (!(level & circuit->is_type))
continue;
if (!area->lspdb[level - 1]
|| !dict_count(area->lspdb[level - 1]))
continue;
for (dnode = dict_first(area->lspdb[level - 1]);
dnode != NULL;
dnode = dict_next(area->lspdb[level - 1], dnode)) {
lsp = dnode_get(dnode);
if (is_set) {
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
} else {
isis_tx_queue_del(circuit->tx_queue, lsp);
}
}
}
@ -672,10 +672,7 @@ int isis_circuit_up(struct isis_circuit *circuit)
isis_circuit_prepare(circuit);
circuit->lsp_queue = list_new();
circuit->lsp_hash = isis_lsp_hash_new();
circuit->lsp_queue_last_push[0] = circuit->lsp_queue_last_push[1] =
monotime(NULL);
circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp);
return ISIS_OK;
}
@ -743,13 +740,9 @@ void isis_circuit_down(struct isis_circuit *circuit)
THREAD_OFF(circuit->t_send_lsp);
THREAD_OFF(circuit->t_read);
if (circuit->lsp_queue) {
list_delete_and_null(&circuit->lsp_queue);
}
if (circuit->lsp_hash) {
isis_lsp_hash_free(circuit->lsp_hash);
circuit->lsp_hash = NULL;
if (circuit->tx_queue) {
isis_tx_queue_free(circuit->tx_queue);
circuit->tx_queue = NULL;
}
/* send one gratuitous hello to spead up convergence */
@ -957,33 +950,35 @@ int isis_interface_config_write(struct vty *vty)
if (circuit == NULL)
continue;
if (circuit->ip_router) {
vty_out(vty, " ip router isis %s\n",
vty_out(vty, " ip router " PROTO_NAME " %s\n",
area->area_tag);
write++;
}
if (circuit->is_passive) {
vty_out(vty, " isis passive\n");
vty_out(vty, " " PROTO_NAME " passive\n");
write++;
}
if (circuit->circ_type_config == CIRCUIT_T_P2P) {
vty_out(vty, " isis network point-to-point\n");
vty_out(vty, " " PROTO_NAME " network point-to-point\n");
write++;
}
if (circuit->ipv6_router) {
vty_out(vty, " ipv6 router isis %s\n",
vty_out(vty, " ipv6 router " PROTO_NAME " %s\n",
area->area_tag);
write++;
}
/* ISIS - circuit type */
if (circuit->is_type == IS_LEVEL_1) {
vty_out(vty, " isis circuit-type level-1\n");
write++;
} else {
if (circuit->is_type == IS_LEVEL_2) {
vty_out(vty,
" isis circuit-type level-2-only\n");
if (!fabricd) {
if (circuit->is_type == IS_LEVEL_1) {
vty_out(vty, " " PROTO_NAME " circuit-type level-1\n");
write++;
} else {
if (circuit->is_type == IS_LEVEL_2) {
vty_out(vty,
" " PROTO_NAME " circuit-type level-2-only\n");
write++;
}
}
}
@ -992,7 +987,7 @@ int isis_interface_config_write(struct vty *vty)
== circuit->csnp_interval[1]) {
if (circuit->csnp_interval[0]
!= DEFAULT_CSNP_INTERVAL) {
vty_out(vty, " isis csnp-interval %d\n",
vty_out(vty, " " PROTO_NAME " csnp-interval %d\n",
circuit->csnp_interval[0]);
write++;
}
@ -1001,7 +996,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->csnp_interval[i]
!= DEFAULT_CSNP_INTERVAL) {
vty_out(vty,
" isis csnp-interval %d level-%d\n",
" " PROTO_NAME " csnp-interval %d level-%d\n",
circuit->csnp_interval
[i],
i + 1);
@ -1015,7 +1010,7 @@ int isis_interface_config_write(struct vty *vty)
== circuit->psnp_interval[1]) {
if (circuit->psnp_interval[0]
!= DEFAULT_PSNP_INTERVAL) {
vty_out(vty, " isis psnp-interval %d\n",
vty_out(vty, " " PROTO_NAME " psnp-interval %d\n",
circuit->psnp_interval[0]);
write++;
}
@ -1024,7 +1019,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->psnp_interval[i]
!= DEFAULT_PSNP_INTERVAL) {
vty_out(vty,
" isis psnp-interval %d level-%d\n",
" " PROTO_NAME " psnp-interval %d level-%d\n",
circuit->psnp_interval
[i],
i + 1);
@ -1036,7 +1031,7 @@ int isis_interface_config_write(struct vty *vty)
/* ISIS - Hello padding - Defaults to true so only
* display if false */
if (circuit->pad_hellos == 0) {
vty_out(vty, " no isis hello padding\n");
vty_out(vty, " no " PROTO_NAME " hello padding\n");
write++;
}
@ -1051,7 +1046,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->hello_interval[0]
!= DEFAULT_HELLO_INTERVAL) {
vty_out(vty,
" isis hello-interval %d\n",
" " PROTO_NAME " hello-interval %d\n",
circuit->hello_interval[0]);
write++;
}
@ -1060,7 +1055,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->hello_interval[i]
!= DEFAULT_HELLO_INTERVAL) {
vty_out(vty,
" isis hello-interval %d level-%d\n",
" " PROTO_NAME " hello-interval %d level-%d\n",
circuit->hello_interval
[i],
i + 1);
@ -1075,7 +1070,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->hello_multiplier[0]
!= DEFAULT_HELLO_MULTIPLIER) {
vty_out(vty,
" isis hello-multiplier %d\n",
" " PROTO_NAME " hello-multiplier %d\n",
circuit->hello_multiplier[0]);
write++;
}
@ -1084,7 +1079,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->hello_multiplier[i]
!= DEFAULT_HELLO_MULTIPLIER) {
vty_out(vty,
" isis hello-multiplier %d level-%d\n",
" " PROTO_NAME " hello-multiplier %d level-%d\n",
circuit->hello_multiplier
[i],
i + 1);
@ -1096,7 +1091,7 @@ int isis_interface_config_write(struct vty *vty)
/* ISIS - Priority */
if (circuit->priority[0] == circuit->priority[1]) {
if (circuit->priority[0] != DEFAULT_PRIORITY) {
vty_out(vty, " isis priority %d\n",
vty_out(vty, " " PROTO_NAME " priority %d\n",
circuit->priority[0]);
write++;
}
@ -1105,7 +1100,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->priority[i]
!= DEFAULT_PRIORITY) {
vty_out(vty,
" isis priority %d level-%d\n",
" " PROTO_NAME " priority %d level-%d\n",
circuit->priority[i],
i + 1);
write++;
@ -1117,7 +1112,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->te_metric[0] == circuit->te_metric[1]) {
if (circuit->te_metric[0]
!= DEFAULT_CIRCUIT_METRIC) {
vty_out(vty, " isis metric %d\n",
vty_out(vty, " " PROTO_NAME " metric %d\n",
circuit->te_metric[0]);
write++;
}
@ -1126,7 +1121,7 @@ int isis_interface_config_write(struct vty *vty)
if (circuit->te_metric[i]
!= DEFAULT_CIRCUIT_METRIC) {
vty_out(vty,
" isis metric %d level-%d\n",
" " PROTO_NAME " metric %d level-%d\n",
circuit->te_metric[i],
i + 1);
write++;
@ -1134,12 +1129,12 @@ int isis_interface_config_write(struct vty *vty)
}
}
if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) {
vty_out(vty, " isis password md5 %s\n",
vty_out(vty, " " PROTO_NAME " password md5 %s\n",
circuit->passwd.passwd);
write++;
} else if (circuit->passwd.type
== ISIS_PASSWD_TYPE_CLEARTXT) {
vty_out(vty, " isis password clear %s\n",
vty_out(vty, " " PROTO_NAME " password clear %s\n",
circuit->passwd.passwd);
write++;
}
@ -1343,60 +1338,4 @@ void isis_circuit_init()
/* Install interface node */
install_node(&interface_node, isis_interface_config_write);
if_cmd_init();
isis_vty_init();
}
void isis_circuit_schedule_lsp_send(struct isis_circuit *circuit)
{
if (circuit->t_send_lsp)
return;
circuit->t_send_lsp =
thread_add_event(master, send_lsp, circuit, 0, NULL);
}
void isis_circuit_queue_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp)
{
if (isis_lsp_hash_lookup(circuit->lsp_hash, lsp))
return;
listnode_add(circuit->lsp_queue, lsp);
isis_lsp_hash_add(circuit->lsp_hash, lsp);
isis_circuit_schedule_lsp_send(circuit);
}
void isis_circuit_lsp_queue_clean(struct isis_circuit *circuit)
{
if (!circuit->lsp_queue)
return;
list_delete_all_node(circuit->lsp_queue);
isis_lsp_hash_clean(circuit->lsp_hash);
}
void isis_circuit_cancel_queued_lsp(struct isis_circuit *circuit,
struct isis_lsp *lsp)
{
if (!circuit->lsp_queue)
return;
listnode_delete(circuit->lsp_queue, lsp);
isis_lsp_hash_release(circuit->lsp_hash, lsp);
}
struct isis_lsp *isis_circuit_lsp_queue_pop(struct isis_circuit *circuit)
{
if (!circuit->lsp_queue)
return NULL;
struct listnode *node = listhead(circuit->lsp_queue);
if (!node)
return NULL;
struct isis_lsp *rv = listgetdata(node);
list_delete_node(circuit->lsp_queue, node);
isis_lsp_hash_release(circuit->lsp_hash, rv);
return rv;
}

View File

@ -80,14 +80,8 @@ struct isis_circuit {
struct thread *t_send_csnp[2];
struct thread *t_send_psnp[2];
struct thread *t_send_lsp;
struct list *lsp_queue; /* LSPs to be txed (both levels) */
struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit
* interval;
* for scalability, use one timestamp per
* circuit, instead of one per lsp per
* circuit
*/
struct isis_tx_queue *tx_queue;
/* there is no real point in two streams, just for programming kicker */
int (*rx)(struct isis_circuit *circuit, uint8_t *ssnpa);
struct stream *rcv_stream; /* Stream for receiving */
@ -114,10 +108,10 @@ struct isis_circuit {
struct isis_passwd passwd; /* Circuit rx/tx password */
int is_type; /* circuit is type == level of circuit
* differentiated from circuit type (media) */
uint32_t hello_interval[2]; /* l1HelloInterval in msecs */
uint16_t hello_multiplier[2]; /* l1HelloMultiplier */
uint16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */
uint16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */
uint32_t hello_interval[2]; /* hello-interval in seconds */
uint16_t hello_multiplier[2]; /* hello-multiplier */
uint16_t csnp_interval[2]; /* csnp-interval in seconds */
uint16_t psnp_interval[2]; /* psnp-interval in seconds */
uint8_t metric[2];
uint32_t te_metric[2];
struct mpls_te_circuit
@ -196,10 +190,4 @@ ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit,
int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid,
bool enabled);
void isis_circuit_schedule_lsp_send(struct isis_circuit *circuit);
void isis_circuit_queue_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp);
void isis_circuit_lsp_queue_clean(struct isis_circuit *circuit);
void isis_circuit_cancel_queued_lsp(struct isis_circuit *circuit,
struct isis_lsp *lsp);
struct isis_lsp *isis_circuit_lsp_queue_pop(struct isis_circuit *circuit);
#endif /* _ZEBRA_ISIS_CIRCUIT_H */

View File

@ -56,6 +56,8 @@
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/fabricd.h"
#include "isisd/isis_tx_queue.h"
static int lsp_l1_refresh(struct thread *thread);
static int lsp_l2_refresh(struct thread *thread);
@ -117,10 +119,9 @@ static void lsp_destroy(struct isis_lsp *lsp)
return;
for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
isis_circuit_cancel_queued_lsp(circuit, lsp);
isis_tx_queue_del(circuit->tx_queue, lsp);
ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
lsp_clear_data(lsp);
@ -352,7 +353,21 @@ void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
isis_spf_schedule(lsp->area, lsp->level);
}
static void lsp_purge(struct isis_lsp *lsp, int level)
static void lsp_purge_add_poi(struct isis_lsp *lsp,
const uint8_t *sender)
{
if (!lsp->area->purge_originator)
return;
/* add purge originator identification */
if (!lsp->tlvs)
lsp->tlvs = isis_alloc_tlvs();
isis_tlvs_set_purge_originator(lsp->tlvs, isis->sysid, sender);
isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
}
static void lsp_purge(struct isis_lsp *lsp, int level,
const uint8_t *sender)
{
/* reset stream */
lsp_clear_data(lsp);
@ -364,8 +379,10 @@ static void lsp_purge(struct isis_lsp *lsp, int level)
lsp->level = level;
lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
lsp_purge_add_poi(lsp, sender);
lsp_pack_pdu(lsp);
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
}
/*
@ -385,7 +402,7 @@ static void lsp_seqno_update(struct isis_lsp *lsp0)
if (lsp->tlvs)
lsp_inc_seqno(lsp, 0);
else
lsp_purge(lsp, lsp0->level);
lsp_purge(lsp, lsp0->level, NULL);
}
return;
@ -425,7 +442,8 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
lsp->tlvs = tlvs;
if (area->dynhostname && lsp->tlvs->hostname) {
if (area->dynhostname && lsp->tlvs->hostname
&& lsp->hdr.rem_lifetime) {
isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
(lsp->hdr.lsp_bits & LSPBIT_IST)
== IS_LEVEL_1_AND_2
@ -462,10 +480,10 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
lsp->own_lsp = 0;
}
lsp_update_data(lsp, hdr, tlvs, stream, area, level);
if (confusion) {
lsp->hdr.rem_lifetime = hdr->rem_lifetime = 0;
put_lsp_hdr(lsp, NULL, true);
lsp_purge(lsp, level, NULL);
} else {
lsp_update_data(lsp, hdr, tlvs, stream, area, level);
}
if (LSP_FRAGMENT(lsp->hdr.lsp_id) && !lsp->lspu.zero_lsp) {
@ -928,6 +946,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
lsp_debug("ISIS (%s): Adding circuit specific information.",
area->area_tag);
if (fabricd) {
lsp_debug(
"ISIS (%s): Adding tier %" PRIu8 " spine-leaf-extension tlv.",
area->area_tag, fabricd_tier(area));
isis_tlvs_add_spine_leaf(lsp->tlvs, fabricd_tier(area), true,
false, false, false);
}
struct isis_circuit *circuit;
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if (!circuit->interface)
@ -1091,9 +1117,16 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
*/
subtlv_len = 0;
uint32_t neighbor_metric;
if (fabricd_tier(area) == 0) {
neighbor_metric = 0xffe;
} else {
neighbor_metric = metric;
}
tlvs_add_mt_p2p(lsp->tlvs, circuit,
ne_id, metric, subtlvs,
subtlv_len);
ne_id, neighbor_metric,
subtlvs, subtlv_len);
}
} else {
lsp_debug(
@ -1192,7 +1225,7 @@ int lsp_generate(struct isis_area *area, int level)
/* time to calculate our checksum */
lsp_seqno_update(newlsp);
newlsp->last_generated = time(NULL);
lsp_set_all_srmflags(newlsp);
lsp_flood(newlsp, NULL);
refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
@ -1223,7 +1256,7 @@ int lsp_generate(struct isis_area *area, int level)
}
/*
* Search own LSPs, update holding time and set SRM
* Search own LSPs, update holding time and flood
*/
static int lsp_regenerate(struct isis_area *area, int level)
{
@ -1255,7 +1288,7 @@ static int lsp_regenerate(struct isis_area *area, int level)
rem_lifetime = lsp_rem_lifetime(area, level);
lsp->hdr.rem_lifetime = rem_lifetime;
lsp->last_generated = time(NULL);
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
frag->hdr.lsp_bits = lsp_bits_generate(
level, area->overload_bit, area->attached_bit);
@ -1265,7 +1298,7 @@ static int lsp_regenerate(struct isis_area *area, int level)
*/
frag->hdr.rem_lifetime = rem_lifetime;
frag->age_out = ZERO_AGE_LIFETIME;
lsp_set_all_srmflags(frag);
lsp_flood(frag, NULL);
}
lsp_seqno_update(lsp);
@ -1565,7 +1598,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
lsp_pack_pdu(lsp);
lsp->own_lsp = 1;
lsp_insert(lsp, lspdb);
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
@ -1624,7 +1657,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
lsp_build_pseudo(lsp, circuit, level);
lsp_inc_seqno(lsp, 0);
lsp->last_generated = time(NULL);
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
if (level == IS_LEVEL_1)
@ -1800,30 +1833,25 @@ int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
/*
* Walk through LSPs for an area
* - set remaining lifetime
* - set LSPs with SRMflag set for sending
*/
int lsp_tick(struct thread *thread)
{
struct isis_area *area;
struct isis_circuit *circuit;
struct isis_lsp *lsp;
struct list *lsp_list;
struct listnode *lspnode, *cnode;
dnode_t *dnode, *dnode_next;
int level;
uint16_t rem_lifetime;
time_t now = monotime(NULL);
lsp_list = list_new();
bool fabricd_sync_incomplete = false;
area = THREAD_ARG(thread);
assert(area);
area->t_tick = NULL;
thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
/*
* Build a list of LSPs with (any) SRMflag set
* and removed the ones that have aged out
* Remove LSPs which have aged out
*/
for (level = 0; level < ISIS_LEVELS; level++) {
if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
@ -1854,17 +1882,14 @@ int lsp_tick(struct thread *thread)
*/
if (rem_lifetime == 1 && lsp->hdr.seqno != 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 b) retain only the header */
if (lsp->area->purge_originator)
lsp_purge(lsp, lsp->level, NULL);
else
lsp_flood(lsp, NULL);
/* 7.3.16.4 c) record the time to purge
* FIXME */
/* 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); */
isis_spf_schedule(lsp->area, lsp->level);
}
if (lsp->age_out == 0) {
@ -1878,44 +1903,22 @@ int lsp_tick(struct thread *thread)
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) {
for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
cnode, circuit)) {
if (!circuit->lsp_queue)
continue;
if (now - circuit->lsp_queue_last_push[level]
< MIN_LSP_RETRANS_INTERVAL) {
continue;
}
circuit->lsp_queue_last_push[level] = now;
for (ALL_LIST_ELEMENTS_RO(
lsp_list, lspnode, lsp)) {
if (circuit->upadjcount
[lsp->level - 1]
&& ISIS_CHECK_FLAG(
lsp->SRMflags,
circuit)) {
isis_circuit_queue_lsp(
circuit, lsp);
}
}
}
list_delete_all_node(lsp_list);
if (fabricd_init_c) {
fabricd_sync_incomplete |=
ISIS_CHECK_FLAG(lsp->SSNflags,
fabricd_init_c);
}
}
}
}
list_delete_and_null(&lsp_list);
if (fabricd_init_c
&& !fabricd_sync_incomplete
&& !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
fabricd_initial_sync_finish(area);
}
return ISIS_OK;
}
@ -1928,7 +1931,7 @@ void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
if (!lsp)
return;
lsp_purge(lsp, level);
lsp_purge(lsp, level, NULL);
}
/*
@ -1952,27 +1955,44 @@ void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
lsp->hdr.rem_lifetime = 0;
lsp_purge_add_poi(lsp, NULL);
lsp_pack_pdu(lsp);
lsp_insert(lsp, area->lspdb[lsp->level - 1]);
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
return;
}
void lsp_set_all_srmflags(struct isis_lsp *lsp)
void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
{
struct listnode *node;
struct isis_circuit *circuit;
assert(lsp);
ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
if (!lsp->area)
return;
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);
struct list *circuit_list = lsp->area->circuit_list;
for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
if (set) {
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
} else {
isis_tx_queue_del(circuit->tx_queue, lsp);
}
}
}
void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit)
{
if (!fabricd) {
lsp_set_all_srmflags(lsp, true);
if (circuit)
isis_tx_queue_del(circuit->tx_queue, lsp);
} else {
fabricd_lsp_flood(lsp);
}
}

View File

@ -37,7 +37,6 @@ struct isis_lsp {
struct list *frags;
struct isis_lsp *zero_lsp;
} lspu;
uint32_t SRMflags[ISIS_MAX_CIRCUITS];
uint32_t SSNflags[ISIS_MAX_CIRCUITS];
int level; /* L1 or L2? */
int scheduled; /* scheduled for sending */
@ -100,6 +99,7 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost);
void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost);
int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost);
/* sets SRMflags for all active circuits of an lsp */
void lsp_set_all_srmflags(struct isis_lsp *lsp);
void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set);
void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit);
#endif /* ISIS_LSP */

View File

@ -1,89 +0,0 @@
/*
* IS-IS Rout(e)ing protocol - LSP Hash
*
* Copyright (C) 2017 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "hash.h"
#include "jhash.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_flags.h"
#include "dict.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_lsp_hash.h"
DEFINE_MTYPE_STATIC(ISISD, LSP_HASH, "ISIS LSP Hash")
struct isis_lsp_hash {
struct hash *h;
};
static unsigned lsp_hash_key(void *lp)
{
struct isis_lsp *lsp = lp;
return jhash(lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
}
static int lsp_hash_cmp(const void *a, const void *b)
{
const struct isis_lsp *la = a, *lb = b;
return 0 == memcmp(la->hdr.lsp_id, lb->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
}
struct isis_lsp_hash *isis_lsp_hash_new(void)
{
struct isis_lsp_hash *rv = XCALLOC(MTYPE_LSP_HASH, sizeof(*rv));
rv->h = hash_create(lsp_hash_key, lsp_hash_cmp, NULL);
return rv;
}
void isis_lsp_hash_clean(struct isis_lsp_hash *ih)
{
hash_clean(ih->h, NULL);
}
void isis_lsp_hash_free(struct isis_lsp_hash *ih)
{
isis_lsp_hash_clean(ih);
hash_free(ih->h);
}
struct isis_lsp *isis_lsp_hash_lookup(struct isis_lsp_hash *ih,
struct isis_lsp *lsp)
{
return hash_lookup(ih->h, lsp);
}
void isis_lsp_hash_add(struct isis_lsp_hash *ih, struct isis_lsp *lsp)
{
struct isis_lsp *inserted;
inserted = hash_get(ih->h, lsp, hash_alloc_intern);
assert(inserted == lsp);
}
void isis_lsp_hash_release(struct isis_lsp_hash *ih, struct isis_lsp *lsp)
{
hash_release(ih->h, lsp);
}

View File

@ -54,11 +54,13 @@
#include "isisd/isis_zebra.h"
#include "isisd/isis_te.h"
#include "isisd/isis_errors.h"
#include "isisd/isis_vty_common.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
/* Default vty port */
#define ISISD_VTY_PORT 2608
#define FABRICD_VTY_PORT 2618
/* isisd privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND};
@ -145,9 +147,15 @@ struct quagga_signal_t isisd_signals[] = {
},
};
#ifdef FABRICD
FRR_DAEMON_INFO(fabricd, OPEN_FABRIC, .vty_port = FABRICD_VTY_PORT,
.proghelp = "Implementation of the OpenFabric routing protocol.",
#else
FRR_DAEMON_INFO(isisd, ISIS, .vty_port = ISISD_VTY_PORT,
.proghelp = "Implementation of the IS-IS routing protocol.",
#endif
.copyright =
"Copyright (c) 2001-2002 Sampo Saaristo,"
" Ofer Wald and Hannes Gredler",
@ -164,7 +172,11 @@ int main(int argc, char **argv, char **envp)
{
int opt;
#ifdef FABRICD
frr_preinit(&fabricd_di, argc, argv);
#else
frr_preinit(&isisd_di, argc, argv);
#endif
frr_opt_add("", longopts, "");
/* Command line argument treatment. */
@ -196,6 +208,7 @@ int main(int argc, char **argv, char **envp)
prefix_list_init();
isis_init();
isis_circuit_init();
isis_vty_init();
isis_spf_cmds_init();
isis_redist_init();
isis_route_map_init();

View File

@ -311,7 +311,7 @@ int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting)) {
const char *name = isis_mtid2str(setting->mtid);
if (name && !setting->enabled) {
vty_out(vty, " no isis topology %s\n", name);
vty_out(vty, " no " PROTO_NAME " topology %s\n", name);
written++;
}
}

View File

@ -56,6 +56,8 @@
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/isis_errors.h"
#include "isisd/fabricd.h"
#include "isisd/isis_tx_queue.h"
static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
int level)
@ -207,6 +209,12 @@ static int process_p2p_hello(struct iih_info *iih)
thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
&adj->t_expire);
/* While fabricds initial sync is in progress, ignore hellos from other
* interfaces than the one we are performing the initial sync on. */
if (fabricd_initial_sync_is_in_progress(iih->circuit->area)
&& fabricd_initial_sync_circuit(iih->circuit->area) != iih->circuit)
return ISIS_OK;
/* 8.2.5.2 a) a match was detected */
if (isis_tlvs_area_addresses_match(iih->tlvs,
iih->circuit->area->area_addrs)) {
@ -671,7 +679,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
goto out;
}
iih.v4_usable = (circuit->ip_addrs && listcount(circuit->ip_addrs)
iih.v4_usable = (fabricd_ip_addrs(circuit)
&& iih.tlvs->ipv4_address.count);
iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link)
@ -700,14 +708,37 @@ out:
* Section 7.3.15.1 - Action on receipt of a link state PDU
*/
static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
const uint8_t *ssnpa)
const uint8_t *ssnpa, uint8_t max_area_addrs)
{
int level = (pdu_type == L1_LINK_STATE) ? ISIS_LEVEL1 : ISIS_LEVEL2;
int level;
bool circuit_scoped;
if (pdu_type == FS_LINK_STATE) {
if (!fabricd)
return ISIS_ERROR;
if (max_area_addrs != L2_CIRCUIT_FLOODING_SCOPE)
return ISIS_ERROR;
level = ISIS_LEVEL2;
circuit_scoped = true;
/* The stream is used verbatim for sending out new LSPDUs.
* So make sure we store it as an L2 LSPDU internally.
* (compare for the reverse in `send_lsp`) */
stream_putc_at(circuit->rcv_stream, 4, L2_LINK_STATE);
stream_putc_at(circuit->rcv_stream, 7, 0);
} else {
if (pdu_type == L1_LINK_STATE)
level = ISIS_LEVEL1;
else
level = ISIS_LEVEL2;
circuit_scoped = false;
}
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
zlog_debug(
"ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
circuit->area->area_tag, level,
"ISIS-Upd (%s): Rcvd %sL%d LSP on %s, cirType %s, cirID %u",
circuit->area->area_tag,
circuit_scoped ? "Circuit scoped " : "", level,
circuit->interface->name,
circuit_t2string(circuit->is_type),
circuit->circuit_id);
@ -869,7 +900,8 @@ dontcheckadj:
* but
* wrong checksum, initiate a purge. */
if (lsp && (lsp->hdr.seqno == hdr.seqno)
&& (lsp->hdr.checksum != hdr.checksum)) {
&& (lsp->hdr.checksum != hdr.checksum)
&& hdr.rem_lifetime) {
zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08" PRIx32
" with confused checksum received.",
circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
@ -899,7 +931,8 @@ dontcheckadj:
lsp_confusion);
tlvs = NULL;
/* ii */
lsp_set_all_srmflags(lsp);
if (!circuit_scoped)
lsp_flood(lsp, NULL);
/* v */
ISIS_FLAGS_CLEAR_ALL(
lsp->SSNflags); /* FIXME:
@ -913,9 +946,10 @@ dontcheckadj:
* Otherwise, don't reflood
* through incoming circuit as usual */
if (!lsp_confusion) {
/* iii */
ISIS_CLEAR_FLAG(lsp->SRMflags,
circuit);
isis_tx_queue_del(
circuit->tx_queue,
lsp);
/* iv */
if (circuit->circ_type
!= CIRCUIT_T_BROADCAST)
@ -926,7 +960,8 @@ dontcheckadj:
} /* 7.3.16.4 b) 2) */
else if (comp == LSP_EQUAL) {
/* i */
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_del(circuit->tx_queue,
lsp);
/* ii */
if (circuit->circ_type
!= CIRCUIT_T_BROADCAST)
@ -934,16 +969,19 @@ dontcheckadj:
circuit);
} /* 7.3.16.4 b) 3) */
else {
ISIS_SET_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_add(circuit->tx_queue,
lsp, TX_LSP_NORMAL);
ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
}
} else if (lsp->hdr.rem_lifetime != 0) {
/* our own LSP -> 7.3.16.4 c) */
if (comp == LSP_NEWER) {
lsp_inc_seqno(lsp, hdr.seqno);
lsp_set_all_srmflags(lsp);
if (!circuit_scoped)
lsp_flood(lsp, NULL);
} else {
ISIS_SET_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_add(circuit->tx_queue,
lsp, TX_LSP_NORMAL);
ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
}
if (isis->debugs & DEBUG_UPDATE_PACKETS)
@ -985,7 +1023,7 @@ dontcheckadj:
}
/* If the received LSP is older or equal,
* resend the LSP which will act as ACK */
lsp_set_all_srmflags(lsp);
lsp_flood(lsp, NULL);
} else {
/* 7.3.15.1 e) - This lsp originated on another system */
@ -1006,7 +1044,7 @@ dontcheckadj:
if (!lsp0) {
zlog_debug(
"Got lsp frag, while zero lsp not in database");
return ISIS_OK;
goto out;
}
}
/* i */
@ -1023,10 +1061,8 @@ dontcheckadj:
circuit->area, level, false);
tlvs = NULL;
}
/* ii */
lsp_set_all_srmflags(lsp);
/* iii */
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
if (!circuit_scoped)
lsp_flood(lsp, circuit);
/* iv */
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
@ -1035,7 +1071,7 @@ dontcheckadj:
}
/* 7.3.15.1 e) 2) LSP equal to the one in db */
else if (comp == LSP_EQUAL) {
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_del(circuit->tx_queue, lsp);
lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
circuit->area, level, false);
tlvs = NULL;
@ -1044,7 +1080,8 @@ dontcheckadj:
}
/* 7.3.15.1 e) 3) LSP older than the one in db */
else {
ISIS_SET_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
}
}
@ -1052,6 +1089,10 @@ dontcheckadj:
retval = ISIS_OK;
out:
if (circuit_scoped) {
fabricd_trigger_csnp(circuit->area);
}
isis_free_tlvs(tlvs);
return retval;
}
@ -1157,7 +1198,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
circuit->u.bc.adjdb[level - 1]))
return ISIS_OK; /* Silently discard */
} else {
if (!circuit->u.p2p.neighbor) {
if (!fabricd && !circuit->u.p2p.neighbor) {
zlog_warn("no p2p neighbor on circuit %s",
circuit->interface->name);
return ISIS_OK; /* Silently discard */
@ -1206,6 +1247,8 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
}
}
bool resync_needed = false;
/* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
for (struct isis_lsp_entry *entry = entry_head; entry;
entry = entry->next) {
@ -1221,25 +1264,28 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
if (cmp == LSP_EQUAL) {
/* if (circuit->circ_type !=
* CIRCUIT_T_BROADCAST) */
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_del(circuit->tx_queue, lsp);
}
/* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM
*/
else if (cmp == LSP_OLDER) {
ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
ISIS_SET_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
}
/* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
on p2p */
else {
if (own_lsp) {
lsp_inc_seqno(lsp, entry->seqno);
ISIS_SET_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
} else {
ISIS_SET_FLAG(lsp->SSNflags, circuit);
/* if (circuit->circ_type !=
* CIRCUIT_T_BROADCAST) */
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_del(circuit->tx_queue, lsp);
resync_needed = true;
}
}
} else {
@ -1271,8 +1317,10 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
entry->checksum, lsp0, level);
lsp_insert(lsp,
circuit->area->lspdb[level - 1]);
ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
lsp_set_all_srmflags(lsp, false);
ISIS_SET_FLAG(lsp->SSNflags, circuit);
resync_needed = true;
}
}
}
@ -1303,12 +1351,18 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
}
/* on remaining LSPs we set SRM (neighbor knew not of) */
for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
ISIS_SET_FLAG(lsp->SRMflags, circuit);
for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
isis_tx_queue_add(circuit->tx_queue, lsp, TX_LSP_NORMAL);
resync_needed = true;
}
/* lets free it */
list_delete_and_null(&lsp_list);
}
if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n");
retval = ISIS_OK;
out:
isis_free_tlvs(tlvs);
@ -1327,6 +1381,7 @@ static int pdu_size(uint8_t pdu_type, uint8_t *size)
break;
case L1_LINK_STATE:
case L2_LINK_STATE:
case FS_LINK_STATE:
*size = ISIS_LSP_HDR_LEN;
break;
case L1_COMPLETE_SEQ_NUM:
@ -1427,7 +1482,9 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
}
/* either 3 or 0 */
if (max_area_addrs != 0 && max_area_addrs != isis->max_area_addrs) {
if (pdu_type != FS_LINK_STATE /* FS PDU doesn't contain max area addr field */
&& max_area_addrs != 0
&& max_area_addrs != isis->max_area_addrs) {
flog_err(
ISIS_ERR_PACKET,
"maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8
@ -1440,11 +1497,18 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
case L1_LAN_HELLO:
case L2_LAN_HELLO:
case P2P_HELLO:
if (fabricd && pdu_type != P2P_HELLO)
return ISIS_ERROR;
retval = process_hello(pdu_type, circuit, ssnpa);
break;
case L1_LINK_STATE:
case L2_LINK_STATE:
retval = process_lsp(pdu_type, circuit, ssnpa);
case FS_LINK_STATE:
if (fabricd
&& pdu_type != L2_LINK_STATE
&& pdu_type != FS_LINK_STATE)
return ISIS_ERROR;
retval = process_lsp(pdu_type, circuit, ssnpa, max_area_addrs);
break;
case L1_COMPLETE_SEQ_NUM:
case L2_COMPLETE_SEQ_NUM:
@ -1582,8 +1646,15 @@ int send_hello(struct isis_circuit *circuit, int level)
&& !circuit->disable_threeway_adj) {
uint32_t ext_circuit_id = circuit->idx;
if (circuit->u.p2p.neighbor) {
uint8_t threeway_state;
if (fabricd_initial_sync_is_in_progress(circuit->area)
&& fabricd_initial_sync_circuit(circuit->area) != circuit)
threeway_state = ISIS_THREEWAY_DOWN;
else
threeway_state = circuit->u.p2p.neighbor->threeway_state;
isis_tlvs_add_threeway_adj(tlvs,
circuit->u.p2p.neighbor->threeway_state,
threeway_state,
ext_circuit_id,
circuit->u.p2p.neighbor->sysid,
circuit->u.p2p.neighbor->ext_circuit_id);
@ -1618,8 +1689,12 @@ int send_hello(struct isis_circuit *circuit, int level)
false, false);
}
if (circuit->ip_router && circuit->ip_addrs)
isis_tlvs_add_ipv4_addresses(tlvs, circuit->ip_addrs);
if (circuit->ip_router) {
struct list *circuit_ip_addrs = fabricd_ip_addrs(circuit);
if (circuit_ip_addrs)
isis_tlvs_add_ipv4_addresses(tlvs, circuit_ip_addrs);
}
if (circuit->ipv6_router && circuit->ipv6_link)
isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link);
@ -1889,8 +1964,9 @@ int send_l1_csnp(struct thread *thread)
circuit->t_send_csnp[0] = NULL;
if (circuit->circ_type == CIRCUIT_T_BROADCAST
&& circuit->u.bc.is_dr[0]) {
if ((circuit->circ_type == CIRCUIT_T_BROADCAST
&& circuit->u.bc.is_dr[0])
|| circuit->circ_type == CIRCUIT_T_P2P) {
send_csnp(circuit, 1);
}
/* set next timer thread */
@ -1911,8 +1987,9 @@ int send_l2_csnp(struct thread *thread)
circuit->t_send_csnp[1] = NULL;
if (circuit->circ_type == CIRCUIT_T_BROADCAST
&& circuit->u.bc.is_dr[1]) {
if ((circuit->circ_type == CIRCUIT_T_BROADCAST
&& circuit->u.bc.is_dr[1])
|| circuit->circ_type == CIRCUIT_T_P2P) {
send_csnp(circuit, 2);
}
/* set next timer thread */
@ -2086,25 +2163,12 @@ int send_l2_psnp(struct thread *thread)
/*
* ISO 10589 - 7.3.14.3
*/
int send_lsp(struct thread *thread)
void send_lsp(void *arg, struct isis_lsp *lsp, enum isis_tx_type tx_type)
{
struct isis_circuit *circuit;
struct isis_lsp *lsp;
struct isis_circuit *circuit = arg;
int clear_srm = 1;
int retval = ISIS_OK;
circuit = THREAD_ARG(thread);
assert(circuit);
circuit->t_send_lsp = NULL;
lsp = isis_circuit_lsp_queue_pop(circuit);
if (!lsp)
return ISIS_OK;
if (!list_isempty(circuit->lsp_queue)) {
isis_circuit_schedule_lsp_send(circuit);
}
if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
goto out;
@ -2144,6 +2208,11 @@ int send_lsp(struct thread *thread)
/* copy our lsp to the send buffer */
stream_copy(circuit->snd_stream, lsp->pdu);
if (tx_type == TX_LSP_CIRCUIT_SCOPED) {
stream_putc_at(circuit->snd_stream, 4, FS_LINK_STATE);
stream_putc_at(circuit->snd_stream, 7, L2_CIRCUIT_FLOODING_SCOPE);
}
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
zlog_debug("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
@ -2181,8 +2250,6 @@ out:
* to clear
* the fag.
*/
ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
isis_tx_queue_del(circuit->tx_queue, lsp);
}
return retval;
}

View File

@ -24,6 +24,8 @@
#ifndef _ZEBRA_ISIS_PDU_H
#define _ZEBRA_ISIS_PDU_H
#include "isisd/isis_tx_queue.h"
#ifdef __SUNPRO_C
#pragma pack(1)
#endif
@ -125,6 +127,8 @@ struct isis_p2p_hello_hdr {
#define L1_LINK_STATE 18
#define L2_LINK_STATE 20
#define FS_LINK_STATE 10
#define L2_CIRCUIT_FLOODING_SCOPE 2
struct isis_lsp_hdr {
uint16_t pdu_len;
uint16_t rem_lifetime;
@ -212,7 +216,7 @@ int send_l1_csnp(struct thread *thread);
int send_l2_csnp(struct thread *thread);
int send_l1_psnp(struct thread *thread);
int send_l2_psnp(struct thread *thread);
int send_lsp(struct thread *thread);
void send_lsp(void *arg, struct isis_lsp *lsp, enum isis_tx_type tx_type);
void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream);
int send_hello(struct isis_circuit *circuit, int level);
int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa);

View File

@ -377,7 +377,7 @@ static void isis_redist_update_zebra_subscriptions(struct isis *isis)
* routes to Zebra and has nothing to do with
* redistribution,
* so skip it. */
if (type == ZEBRA_ROUTE_ISIS)
if (type == PROTO_TYPE)
continue;
afi_t afi = afi_for_redist_protocol(protocol);
@ -515,13 +515,19 @@ void isis_redist_area_finish(struct isis_area *area)
DEFUN (isis_redistribute,
isis_redistribute_cmd,
"redistribute <ipv4|ipv6> " FRR_REDIST_STR_ISISD " <level-1|level-2> [<metric (0-16777215)|route-map WORD>]",
"redistribute <ipv4|ipv6> " PROTO_REDIST_STR
#ifndef FABRICD
" <level-1|level-2>"
#endif
" [<metric (0-16777215)|route-map WORD>]",
REDIST_STR
"Redistribute IPv4 routes\n"
"Redistribute IPv6 routes\n"
FRR_REDIST_HELP_STR_ISISD
PROTO_REDIST_HELP
#ifndef FABRICD
"Redistribute into level-1\n"
"Redistribute into level-2\n"
#endif
"Metric for redistributed routes\n"
"ISIS default metric\n"
"Route map reference\n"
@ -530,7 +536,7 @@ DEFUN (isis_redistribute,
int idx_afi = 1;
int idx_protocol = 2;
int idx_level = 3;
int idx_metric_rmap = 4;
int idx_metric_rmap = fabricd ? 3 : 4;
VTY_DECLVAR_CONTEXT(isis_area, area);
int family;
int afi;
@ -551,7 +557,9 @@ DEFUN (isis_redistribute,
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
if (!strcmp("level-1", argv[idx_level]->arg))
if (fabricd)
level = 2;
else if (!strcmp("level-1", argv[idx_level]->arg))
level = 1;
else if (!strcmp("level-2", argv[idx_level]->arg))
level = 2;
@ -585,14 +593,20 @@ DEFUN (isis_redistribute,
DEFUN (no_isis_redistribute,
no_isis_redistribute_cmd,
"no redistribute <ipv4|ipv6> " FRR_REDIST_STR_ISISD " <level-1|level-2>",
NO_STR
"no redistribute <ipv4|ipv6> " PROTO_REDIST_STR
#ifndef FABRICD
" <level-1|level-2>"
#endif
, NO_STR
REDIST_STR
"Redistribute IPv4 routes\n"
"Redistribute IPv6 routes\n"
FRR_REDIST_HELP_STR_ISISD
PROTO_REDIST_HELP
#ifndef FABRICD
"Redistribute into level-1\n"
"Redistribute into level-2\n")
"Redistribute into level-2\n"
#endif
)
{
int idx_afi = 2;
int idx_protocol = 3;
@ -615,7 +629,10 @@ DEFUN (no_isis_redistribute,
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
level = strmatch("level-1", argv[idx_level]->text) ? 1 : 2;
if (fabricd)
level = 2;
else
level = strmatch("level-1", argv[idx_level]->text) ? 1 : 2;
isis_redist_unset(area, level, family, type);
return 0;
@ -623,13 +640,19 @@ DEFUN (no_isis_redistribute,
DEFUN (isis_default_originate,
isis_default_originate_cmd,
"default-information originate <ipv4|ipv6> <level-1|level-2> [always] [<metric (0-16777215)|route-map WORD>]",
"default-information originate <ipv4|ipv6>"
#ifndef FABRICD
" <level-1|level-2>"
#endif
" [always] [<metric (0-16777215)|route-map WORD>]",
"Control distribution of default information\n"
"Distribute a default route\n"
"Distribute default route for IPv4\n"
"Distribute default route for IPv6\n"
#ifndef FABRICD
"Distribute default route into level-1\n"
"Distribute default route into level-2\n"
#endif
"Always advertise default route\n"
"Metric for default route\n"
"ISIS default metric\n"
@ -638,8 +661,8 @@ DEFUN (isis_default_originate,
{
int idx_afi = 2;
int idx_level = 3;
int idx_always = 4;
int idx_metric_rmap = 4;
int idx_always = fabricd ? 3 : 4;
int idx_metric_rmap = fabricd ? 3 : 4;
VTY_DECLVAR_CONTEXT(isis_area, area);
int family;
int originate_type = DEFAULT_ORIGINATE;
@ -651,7 +674,10 @@ DEFUN (isis_default_originate,
if (family < 0)
return CMD_WARNING_CONFIG_FAILED;
level = strmatch("level-1", argv[idx_level]->text) ? 1 : 2;
if (fabricd)
level = 2;
else
level = strmatch("level-1", argv[idx_level]->text) ? 1 : 2;
if ((area->is_type & level) != level) {
vty_out(vty, "Node is not a level-%d IS\n", level);
@ -685,14 +711,20 @@ DEFUN (isis_default_originate,
DEFUN (no_isis_default_originate,
no_isis_default_originate_cmd,
"no default-information originate <ipv4|ipv6> <level-1|level-2>",
NO_STR
"no default-information originate <ipv4|ipv6>"
#ifndef FABRICD
" <level-1|level-2>"
#endif
, NO_STR
"Control distribution of default information\n"
"Distribute a default route\n"
"Distribute default route for IPv4\n"
"Distribute default route for IPv6\n"
#ifndef FABRICD
"Distribute default route into level-1\n"
"Distribute default route into level-2\n")
"Distribute default route into level-2\n"
#endif
)
{
int idx_afi = 3;
int idx_level = 4;
@ -704,7 +736,9 @@ DEFUN (no_isis_default_originate,
if (family < 0)
return CMD_WARNING_CONFIG_FAILED;
if (strmatch("level-1", argv[idx_level]->text))
if (fabricd)
level = 2;
else if (strmatch("level-1", argv[idx_level]->text))
level = 1;
else if (strmatch("level-2", argv[idx_level]->text))
level = 2;
@ -732,15 +766,17 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area,
return 0;
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
if (type == ZEBRA_ROUTE_ISIS)
if (type == PROTO_TYPE)
continue;
for (level = 1; level <= ISIS_LEVELS; level++) {
redist = get_redist_settings(area, family, type, level);
if (!redist->redist)
continue;
vty_out(vty, " redistribute %s %s level-%d", family_str,
zebra_route_string(type), level);
vty_out(vty, " redistribute %s %s", family_str,
zebra_route_string(type));
if (!fabricd)
vty_out(vty, " level-%d", level);
if (redist->metric)
vty_out(vty, " metric %u", redist->metric);
if (redist->map_name)
@ -755,8 +791,10 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area,
get_redist_settings(area, family, DEFAULT_ROUTE, level);
if (!redist->redist)
continue;
vty_out(vty, " default-information originate %s level-%d",
family_str, level);
vty_out(vty, " default-information originate %s",
family_str);
if (!fabricd)
vty_out(vty, " level-%d", level);
if (redist->redist == DEFAULT_ORIGINATE_ALWAYS)
vty_out(vty, " always");
if (redist->metric)
@ -772,8 +810,8 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area,
void isis_redist_init(void)
{
install_element(ISIS_NODE, &isis_redistribute_cmd);
install_element(ISIS_NODE, &no_isis_redistribute_cmd);
install_element(ISIS_NODE, &isis_default_originate_cmd);
install_element(ISIS_NODE, &no_isis_default_originate_cmd);
install_element(ROUTER_NODE, &isis_redistribute_cmd);
install_element(ROUTER_NODE, &no_isis_redistribute_cmd);
install_element(ROUTER_NODE, &isis_default_originate_cmd);
install_element(ROUTER_NODE, &no_isis_default_originate_cmd);
}

View File

@ -31,14 +31,10 @@
#include "command.h"
#include "memory.h"
#include "prefix.h"
#include "hash.h"
#include "if.h"
#include "table.h"
#include "spf_backoff.h"
#include "jhash.h"
#include "skiplist.h"
#include "srcdest_table.h"
#include "lib_errors.h"
#include "isis_constants.h"
#include "isis_common.h"
@ -56,256 +52,11 @@
#include "isis_csm.h"
#include "isis_mt.h"
#include "isis_tlvs.h"
#include "fabricd.h"
#include "isis_spf_private.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
enum vertextype {
VTYPE_PSEUDO_IS = 1,
VTYPE_PSEUDO_TE_IS,
VTYPE_NONPSEUDO_IS,
VTYPE_NONPSEUDO_TE_IS,
VTYPE_ES,
VTYPE_IPREACH_INTERNAL,
VTYPE_IPREACH_EXTERNAL,
VTYPE_IPREACH_TE,
VTYPE_IP6REACH_INTERNAL,
VTYPE_IP6REACH_EXTERNAL
};
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
#define VTYPE_ES(t) ((t) == VTYPE_ES)
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
struct prefix_pair {
struct prefix dest;
struct prefix_ipv6 src;
};
/*
* Triple <N, d(N), {Adj(N)}>
*/
union isis_N {
uint8_t id[ISIS_SYS_ID_LEN + 1];
struct prefix_pair ip;
};
struct isis_vertex {
enum vertextype type;
union isis_N N;
uint32_t d_N; /* d(N) Distance from this IS */
uint16_t depth; /* The depth in the imaginary tree */
struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
struct list *parents; /* list of parents for ECMP */
uint64_t insert_counter;
};
/* Vertex Queue and associated functions */
struct isis_vertex_queue {
union {
struct skiplist *slist;
struct list *list;
} l;
struct hash *hash;
uint64_t insert_counter;
};
static unsigned isis_vertex_queue_hash_key(void *vp)
{
struct isis_vertex *vertex = vp;
if (VTYPE_IP(vertex->type)) {
uint32_t key;
key = prefix_hash_key(&vertex->N.ip.dest);
key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key);
return key;
}
return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
}
static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
{
const struct isis_vertex *va = a, *vb = b;
if (va->type != vb->type)
return 0;
if (VTYPE_IP(va->type)) {
if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest))
return 0;
return prefix_cmp((struct prefix *)&va->N.ip.src,
(struct prefix *)&vb->N.ip.src) == 0;
}
return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
}
/*
* Compares vertizes for sorting in the TENT list. Returns true
* if candidate should be considered before current, false otherwise.
*/
static int isis_vertex_queue_tent_cmp(void *a, void *b)
{
struct isis_vertex *va = a;
struct isis_vertex *vb = b;
if (va->d_N < vb->d_N)
return -1;
if (va->d_N > vb->d_N)
return 1;
if (va->type < vb->type)
return -1;
if (va->type > vb->type)
return 1;
if (va->insert_counter < vb->insert_counter)
return -1;
if (va->insert_counter > vb->insert_counter)
return 1;
return 0;
}
static struct skiplist *isis_vertex_queue_skiplist(void)
{
return skiplist_new(0, isis_vertex_queue_tent_cmp, NULL);
}
static void isis_vertex_queue_init(struct isis_vertex_queue *queue,
const char *name, bool ordered)
{
if (ordered) {
queue->insert_counter = 1;
queue->l.slist = isis_vertex_queue_skiplist();
} else {
queue->insert_counter = 0;
queue->l.list = list_new();
}
queue->hash = hash_create(isis_vertex_queue_hash_key,
isis_vertex_queue_hash_cmp, name);
}
static void isis_vertex_del(struct isis_vertex *vertex);
static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
{
hash_clean(queue->hash, NULL);
if (queue->insert_counter) {
struct isis_vertex *vertex;
while (0 == skiplist_first(queue->l.slist, NULL,
(void **)&vertex)) {
isis_vertex_del(vertex);
skiplist_delete_first(queue->l.slist);
}
queue->insert_counter = 1;
} else {
queue->l.list->del = (void (*)(void *))isis_vertex_del;
list_delete_all_node(queue->l.list);
queue->l.list->del = NULL;
}
}
static void isis_vertex_queue_free(struct isis_vertex_queue *queue)
{
isis_vertex_queue_clear(queue);
hash_free(queue->hash);
queue->hash = NULL;
if (queue->insert_counter) {
skiplist_free(queue->l.slist);
queue->l.slist = NULL;
} else
list_delete_and_null(&queue->l.list);
}
static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue)
{
return hashcount(queue->hash);
}
static void isis_vertex_queue_append(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(!queue->insert_counter);
listnode_add(queue->l.list, vertex);
struct isis_vertex *inserted;
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
assert(inserted == vertex);
}
static void isis_vertex_queue_insert(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(queue->insert_counter);
vertex->insert_counter = queue->insert_counter++;
assert(queue->insert_counter != (uint64_t)-1);
skiplist_insert(queue->l.slist, vertex, vertex);
struct isis_vertex *inserted;
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
assert(inserted == vertex);
}
static struct isis_vertex *
isis_vertex_queue_pop(struct isis_vertex_queue *queue)
{
assert(queue->insert_counter);
struct isis_vertex *rv;
if (skiplist_first(queue->l.slist, NULL, (void **)&rv))
return NULL;
skiplist_delete_first(queue->l.slist);
hash_release(queue->hash, rv);
return rv;
}
static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(queue->insert_counter);
skiplist_delete(queue->l.slist, vertex, vertex);
hash_release(queue->hash, vertex);
}
#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \
ALL_LIST_ELEMENTS_RO((queue)->l.list, node, data)
/* End of vertex queue definitions */
struct isis_spftree {
struct isis_vertex_queue paths; /* the SPT */
struct isis_vertex_queue tents; /* TENT */
struct route_table *route_table;
struct isis_area *area; /* back pointer to area */
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp as wall time for display */
time_t last_run_monotime; /* last run as monotime for scheduling */
time_t last_run_duration; /* last run duration in msec */
uint16_t mtid;
int family;
int level;
enum spf_tree_id tree_id;
};
/*
* supports the given af ?
*/
@ -411,8 +162,7 @@ static const char *vtype2string(enum vertextype vtype)
return NULL; /* Not reached */
}
#define VID2STR_BUFFER SRCDEST2STR_BUFFER
static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
{
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
return print_sys_hostname(vertex->N.id);
@ -428,46 +178,28 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
return "UNKNOWN";
}
static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
enum vertextype vtype)
{
vertex->type = vtype;
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1);
} else if (VTYPE_IP(vtype)) {
memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip));
} else {
flog_err(LIB_ERR_DEVELOPMENT, "Unknown Vertex Type");
}
}
static struct isis_vertex *isis_vertex_new(union isis_N *n,
static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
void *id,
enum vertextype vtype)
{
struct isis_vertex *vertex;
vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
isis_vertex_id_init(vertex, n, vtype);
isis_vertex_id_init(vertex, id, vtype);
vertex->Adj_N = list_new();
vertex->parents = list_new();
if (spftree->hopcount_metric) {
vertex->firsthops = hash_create(isis_vertex_queue_hash_key,
isis_vertex_queue_hash_cmp,
NULL);
}
return vertex;
}
static void isis_vertex_del(struct isis_vertex *vertex)
{
list_delete_and_null(&vertex->Adj_N);
list_delete_and_null(&vertex->parents);
memset(vertex, 0, sizeof(struct isis_vertex));
XFREE(MTYPE_ISIS_VERTEX, vertex);
return;
}
static void isis_vertex_adj_del(struct isis_vertex *vertex,
struct isis_adjacency *adj)
{
@ -563,6 +295,9 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
adj);
}
}
if (fabricd_spftree(area) != NULL)
isis_spftree_adj_del(fabricd_spftree(area), adj);
}
/*
@ -595,17 +330,13 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
#ifdef EXTREME_DEBUG
char buff[VID2STR_BUFFER];
#endif /* EXTREME_DEBUG */
union isis_N n;
memcpy(n.id, sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(n.id) = 0;
lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
if (lsp == NULL)
zlog_warn("ISIS-Spf: could not find own l%d LSP!",
spftree->level);
vertex = isis_vertex_new(&n,
vertex = isis_vertex_new(spftree, sysid,
spftree->area->oldmetric
? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS);
@ -621,14 +352,24 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
return vertex;
}
static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
union isis_N *n,
enum vertextype vtype)
static void vertex_add_parent_firsthop(struct hash_backet *backet, void *arg)
{
struct isis_vertex querier;
struct isis_vertex *vertex = arg;
struct isis_vertex *hop = backet->data;
isis_vertex_id_init(&querier, n, vtype);
return hash_lookup(queue->hash, &querier);
hash_get(vertex->firsthops, hop, hash_alloc_intern);
}
static void vertex_update_firsthops(struct isis_vertex *vertex,
struct isis_vertex *parent)
{
if (vertex->d_N <= 2)
hash_get(vertex->firsthops, vertex, hash_alloc_intern);
if (vertex->d_N < 2 || !parent)
return;
hash_iterate(parent->firsthops, vertex_add_parent_firsthop, vertex);
}
/*
@ -649,7 +390,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL);
assert(isis_find_vertex(&spftree->tents, id, vtype) == NULL);
vertex = isis_vertex_new(id, vtype);
vertex = isis_vertex_new(spftree, id, vtype);
vertex->d_N = cost;
vertex->depth = depth;
@ -657,6 +398,9 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
listnode_add(vertex->parents, parent);
}
if (spftree->hopcount_metric)
vertex_update_firsthops(vertex, parent);
if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_adj))
listnode_add(vertex->Adj_N, parent_adj);
@ -722,6 +466,10 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
assert(spftree && parent);
if (spftree->hopcount_metric
&& !VTYPE_IS(vtype))
return;
struct prefix_pair p;
if (vtype >= VTYPE_IPREACH_INTERNAL) {
memcpy(&p, id, sizeof(p));
@ -774,6 +522,8 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
if (listnode_lookup(vertex->Adj_N, parent_adj)
== NULL)
listnode_add(vertex->Adj_N, parent_adj);
if (spftree->hopcount_metric)
vertex_update_firsthops(vertex, parent);
/* 2) */
if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
remove_excess_adjs(vertex->Adj_N);
@ -853,6 +603,9 @@ lspfragloop:
for (r = (struct isis_oldstyle_reach *)
lsp->tlvs->oldstyle_reach.head;
r; r = r->next) {
if (fabricd)
continue;
/* C.2.6 a) */
/* Two way connectivity */
if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN))
@ -889,7 +642,7 @@ lspfragloop:
if (!pseudo_lsp
&& !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
continue;
dist = cost + er->metric;
dist = cost + (spftree->hopcount_metric ? 1 : er->metric);
process_N(spftree,
LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
: VTYPE_NONPSEUDO_TE_IS,
@ -897,7 +650,7 @@ lspfragloop:
}
}
if (!pseudo_lsp && spftree->family == AF_INET
if (!fabricd && !pseudo_lsp && spftree->family == AF_INET
&& spftree->mtid == ISIS_MT_IPV4_UNICAST) {
struct isis_item_list *reachs[] = {
&lsp->tlvs->oldstyle_ip_reach,
@ -1037,7 +790,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
/*
* Add IP(v6) addresses of this circuit
*/
if (spftree->family == AF_INET) {
if (spftree->family == AF_INET && !spftree->hopcount_metric) {
memset(&ip_info, 0, sizeof(ip_info));
ip_info.dest.family = AF_INET;
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
@ -1050,7 +803,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
&ip_info, NULL, 0, parent);
}
}
if (spftree->family == AF_INET6) {
if (spftree->family == AF_INET6 && !spftree->hopcount_metric) {
memset(&ip_info, 0, sizeof(ip_info));
ip_info.dest.family = AF_INET6;
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
@ -1094,6 +847,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
LSP_PSEUDO_ID(lsp_id) = 0;
isis_spf_add_local(
spftree, VTYPE_ES, lsp_id, adj,
spftree->hopcount_metric ? 1 :
circuit->te_metric
[spftree->level - 1],
parent);
@ -1111,6 +865,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS,
lsp_id, adj,
spftree->hopcount_metric ? 1 :
circuit->te_metric
[spftree->level - 1],
parent);
@ -1180,10 +935,10 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
circuit->circuit_id);
continue;
}
isis_spf_process_lsp(
spftree, lsp,
circuit->te_metric[spftree->level - 1], 0,
root_sysid, parent);
isis_spf_process_lsp(spftree, lsp,
spftree->hopcount_metric ?
1 : circuit->te_metric[spftree->level - 1],
0, root_sysid, parent);
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
adj = circuit->u.p2p.neighbor;
if (!adj || adj->adj_state != ISIS_ADJ_UP)
@ -1196,6 +951,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
LSP_PSEUDO_ID(lsp_id) = 0;
isis_spf_add_local(
spftree, VTYPE_ES, lsp_id, adj,
spftree->hopcount_metric ? 1 :
circuit->te_metric[spftree->level - 1],
parent);
break;
@ -1215,6 +971,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS,
lsp_id, adj,
spftree->hopcount_metric ? 1 :
circuit->te_metric
[spftree->level - 1],
parent);
@ -1275,7 +1032,8 @@ static void add_to_paths(struct isis_spftree *spftree,
}
static void init_spt(struct isis_spftree *spftree, int mtid, int level,
int family, enum spf_tree_id tree_id)
int family, enum spf_tree_id tree_id,
bool hopcount_metric)
{
isis_vertex_queue_clear(&spftree->tents);
isis_vertex_queue_clear(&spftree->paths);
@ -1284,7 +1042,63 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
spftree->level = level;
spftree->family = family;
spftree->tree_id = tree_id;
return;
spftree->hopcount_metric = hopcount_metric;
}
static void isis_spf_loop(struct isis_spftree *spftree,
uint8_t *root_sysid)
{
struct isis_vertex *vertex;
struct isis_lsp *lsp;
while (isis_vertex_queue_count(&spftree->tents)) {
vertex = isis_vertex_queue_pop(&spftree->tents);
#ifdef EXTREME_DEBUG
zlog_debug(
"ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
print_sys_hostname(vertex->N.id),
vtype2string(vertex->type), vertex->depth, vertex->d_N);
#endif /* EXTREME_DEBUG */
add_to_paths(spftree, vertex);
if (!VTYPE_IS(vertex->type))
continue;
lsp = lsp_for_vertex(spftree, vertex);
if (!lsp) {
zlog_warn("ISIS-Spf: No LSP found for %s",
rawlspid_print(vertex->N.id)); /* FIXME */
continue;
}
isis_spf_process_lsp(spftree, lsp, vertex->d_N, vertex->depth,
root_sysid, vertex);
}
}
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
uint8_t *sysid,
struct isis_spftree *spftree)
{
if (!spftree)
spftree = isis_spftree_new(area);
init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2,
AF_INET, SPFTREE_IPV4, true);
if (!memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN)) {
/* If we are running locally, initialize with information from adjacencies */
struct isis_vertex *root = isis_spf_add_root(spftree, sysid);
isis_spf_preload_tent(spftree, sysid, root);
} else {
isis_vertex_queue_insert(&spftree->tents, isis_vertex_new(
spftree, sysid,
VTYPE_NONPSEUDO_TE_IS));
}
isis_spf_loop(spftree, sysid);
return spftree;
}
static int isis_run_spf(struct isis_area *area, int level,
@ -1292,11 +1106,8 @@ static int isis_run_spf(struct isis_area *area, int level,
uint8_t *sysid, struct timeval *nowtv)
{
int retval = ISIS_OK;
struct isis_vertex *vertex;
struct isis_vertex *root_vertex;
struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
struct isis_lsp *lsp;
struct timeval time_now;
unsigned long long start_time, end_time;
uint16_t mtid = 0;
@ -1330,7 +1141,7 @@ static int isis_run_spf(struct isis_area *area, int level,
/*
* C.2.5 Step 0
*/
init_spt(spftree, mtid, level, family, tree_id);
init_spt(spftree, mtid, level, family, tree_id, false);
/* a) */
root_vertex = isis_spf_add_root(spftree, sysid);
/* b) */
@ -1350,32 +1161,7 @@ static int isis_run_spf(struct isis_area *area, int level,
print_sys_hostname(sysid));
}
while (isis_vertex_queue_count(&spftree->tents)) {
vertex = isis_vertex_queue_pop(&spftree->tents);
#ifdef EXTREME_DEBUG
zlog_debug(
"ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
print_sys_hostname(vertex->N.id),
vtype2string(vertex->type), vertex->depth, vertex->d_N);
#endif /* EXTREME_DEBUG */
add_to_paths(spftree, vertex);
if (VTYPE_IS(vertex->type)) {
memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT(lsp_id) = 0;
lsp = lsp_search(lsp_id, area->lspdb[level - 1]);
if (lsp && lsp->hdr.rem_lifetime != 0) {
isis_spf_process_lsp(spftree, lsp, vertex->d_N,
vertex->depth, sysid,
vertex);
} else {
zlog_warn("ISIS-Spf: No LSP found for %s",
rawlspid_print(lsp_id));
}
}
}
isis_spf_loop(spftree, sysid);
out:
spftree->runcount++;
spftree->last_run_timestamp = time(NULL);
@ -1446,6 +1232,8 @@ static int isis_run_spf_cb(struct thread *thread)
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
fabricd_run_spf(area);
return retval;
}
@ -1617,12 +1405,18 @@ static void isis_print_spftree(struct vty *vty, int level,
DEFUN (show_isis_topology,
show_isis_topology_cmd,
"show isis topology [<level-1|level-2>]",
SHOW_STR
"IS-IS information\n"
"show " PROTO_NAME " topology"
#ifndef FABRICD
" [<level-1|level-2>]"
#endif
, SHOW_STR
PROTO_HELP
"IS-IS paths to Intermediate Systems\n"
#ifndef FABRICD
"Paths to all level-1 routers in the area\n"
"Paths to all level-2 routers in the domain\n")
"Paths to all level-2 routers in the domain\n"
#endif
)
{
int levels;
struct listnode *node;
@ -1660,6 +1454,13 @@ DEFUN (show_isis_topology,
}
}
if (fabricd_spftree(area)) {
vty_out(vty,
"IS-IS paths to level-2 routers with hop-by-hop metric\n");
isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid);
vty_out(vty, "\n");
}
vty_out(vty, "\n");
}

View File

@ -37,4 +37,7 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj);
int isis_spf_schedule(struct isis_area *area, int level);
void isis_spf_cmds_init(void);
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
uint8_t *sysid,
struct isis_spftree *spftree);
#endif /* _ZEBRA_ISIS_SPF_H */

362
isisd/isis_spf_private.h Normal file
View File

@ -0,0 +1,362 @@
/*
* IS-IS Rout(e)ing protocol - isis_spf_private.h
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
* Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ISIS_SPF_PRIVATE_H
#define ISIS_SPF_PRIVATE_H
#include "hash.h"
#include "jhash.h"
#include "skiplist.h"
#include "lib_errors.h"
enum vertextype {
VTYPE_PSEUDO_IS = 1,
VTYPE_PSEUDO_TE_IS,
VTYPE_NONPSEUDO_IS,
VTYPE_NONPSEUDO_TE_IS,
VTYPE_ES,
VTYPE_IPREACH_INTERNAL,
VTYPE_IPREACH_EXTERNAL,
VTYPE_IPREACH_TE,
VTYPE_IP6REACH_INTERNAL,
VTYPE_IP6REACH_EXTERNAL
};
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
#define VTYPE_ES(t) ((t) == VTYPE_ES)
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
struct prefix_pair {
struct prefix dest;
struct prefix_ipv6 src;
};
/*
* Triple <N, d(N), {Adj(N)}>
*/
struct isis_vertex {
enum vertextype type;
union {
uint8_t id[ISIS_SYS_ID_LEN + 1];
struct prefix_pair ip;
} N;
uint32_t d_N; /* d(N) Distance from this IS */
uint16_t depth; /* The depth in the imaginary tree */
struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
struct list *parents; /* list of parents for ECMP */
struct hash *firsthops; /* first two hops to neighbor */
uint64_t insert_counter;
};
/* Vertex Queue and associated functions */
struct isis_vertex_queue {
union {
struct skiplist *slist;
struct list *list;
} l;
struct hash *hash;
uint64_t insert_counter;
};
__attribute__((__unused__))
static unsigned isis_vertex_queue_hash_key(void *vp)
{
struct isis_vertex *vertex = vp;
if (VTYPE_IP(vertex->type)) {
uint32_t key;
key = prefix_hash_key(&vertex->N.ip.dest);
key = jhash_1word(prefix_hash_key(&vertex->N.ip.src), key);
return key;
}
return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
}
__attribute__((__unused__))
static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
{
const struct isis_vertex *va = a, *vb = b;
if (va->type != vb->type)
return 0;
if (VTYPE_IP(va->type)) {
if (prefix_cmp(&va->N.ip.dest, &vb->N.ip.dest))
return 0;
return prefix_cmp((struct prefix *)&va->N.ip.src,
(struct prefix *)&vb->N.ip.src) == 0;
}
return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
}
/*
* Compares vertizes for sorting in the TENT list. Returns true
* if candidate should be considered before current, false otherwise.
*/
__attribute__((__unused__))
static int isis_vertex_queue_tent_cmp(void *a, void *b)
{
struct isis_vertex *va = a;
struct isis_vertex *vb = b;
if (va->d_N < vb->d_N)
return -1;
if (va->d_N > vb->d_N)
return 1;
if (va->type < vb->type)
return -1;
if (va->type > vb->type)
return 1;
if (va->insert_counter < vb->insert_counter)
return -1;
if (va->insert_counter > vb->insert_counter)
return 1;
return 0;
}
__attribute__((__unused__))
static struct skiplist *isis_vertex_queue_skiplist(void)
{
return skiplist_new(0, isis_vertex_queue_tent_cmp, NULL);
}
__attribute__((__unused__))
static void isis_vertex_queue_init(struct isis_vertex_queue *queue,
const char *name, bool ordered)
{
if (ordered) {
queue->insert_counter = 1;
queue->l.slist = isis_vertex_queue_skiplist();
} else {
queue->insert_counter = 0;
queue->l.list = list_new();
}
queue->hash = hash_create(isis_vertex_queue_hash_key,
isis_vertex_queue_hash_cmp, name);
}
__attribute__((__unused__))
static void isis_vertex_del(struct isis_vertex *vertex)
{
list_delete_and_null(&vertex->Adj_N);
list_delete_and_null(&vertex->parents);
if (vertex->firsthops) {
hash_clean(vertex->firsthops, NULL);
hash_free(vertex->firsthops);
vertex->firsthops = NULL;
}
memset(vertex, 0, sizeof(struct isis_vertex));
XFREE(MTYPE_ISIS_VERTEX, vertex);
}
__attribute__((__unused__))
static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
{
hash_clean(queue->hash, NULL);
if (queue->insert_counter) {
struct isis_vertex *vertex;
while (0 == skiplist_first(queue->l.slist, NULL,
(void **)&vertex)) {
isis_vertex_del(vertex);
skiplist_delete_first(queue->l.slist);
}
queue->insert_counter = 1;
} else {
queue->l.list->del = (void (*)(void *))isis_vertex_del;
list_delete_all_node(queue->l.list);
queue->l.list->del = NULL;
}
}
__attribute__((__unused__))
static void isis_vertex_queue_free(struct isis_vertex_queue *queue)
{
isis_vertex_queue_clear(queue);
hash_free(queue->hash);
queue->hash = NULL;
if (queue->insert_counter) {
skiplist_free(queue->l.slist);
queue->l.slist = NULL;
} else
list_delete_and_null(&queue->l.list);
}
__attribute__((__unused__))
static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue)
{
return hashcount(queue->hash);
}
__attribute__((__unused__))
static void isis_vertex_queue_append(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(!queue->insert_counter);
listnode_add(queue->l.list, vertex);
struct isis_vertex *inserted;
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
assert(inserted == vertex);
}
__attribute__((__unused__))
static struct isis_vertex *isis_vertex_queue_last(struct isis_vertex_queue *queue)
{
struct listnode *tail;
assert(!queue->insert_counter);
tail = listtail(queue->l.list);
assert(tail);
return listgetdata(tail);
}
__attribute__((__unused__))
static void isis_vertex_queue_insert(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(queue->insert_counter);
vertex->insert_counter = queue->insert_counter++;
assert(queue->insert_counter != (uint64_t)-1);
skiplist_insert(queue->l.slist, vertex, vertex);
struct isis_vertex *inserted;
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
assert(inserted == vertex);
}
__attribute__((__unused__))
static struct isis_vertex *
isis_vertex_queue_pop(struct isis_vertex_queue *queue)
{
assert(queue->insert_counter);
struct isis_vertex *rv;
if (skiplist_first(queue->l.slist, NULL, (void **)&rv))
return NULL;
skiplist_delete_first(queue->l.slist);
hash_release(queue->hash, rv);
return rv;
}
__attribute__((__unused__))
static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
struct isis_vertex *vertex)
{
assert(queue->insert_counter);
skiplist_delete(queue->l.slist, vertex, vertex);
hash_release(queue->hash, vertex);
}
#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \
ALL_LIST_ELEMENTS_RO((queue)->l.list, node, data)
/* End of vertex queue definitions */
struct isis_spftree {
struct isis_vertex_queue paths; /* the SPT */
struct isis_vertex_queue tents; /* TENT */
struct route_table *route_table;
struct isis_area *area; /* back pointer to area */
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp as wall time for display */
time_t last_run_monotime; /* last run as monotime for scheduling */
time_t last_run_duration; /* last run duration in msec */
uint16_t mtid;
int family;
int level;
enum spf_tree_id tree_id;
bool hopcount_metric;
};
__attribute__((__unused__))
static void isis_vertex_id_init(struct isis_vertex *vertex, const void *id,
enum vertextype vtype)
{
vertex->type = vtype;
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
memcpy(vertex->N.id, id, ISIS_SYS_ID_LEN + 1);
} else if (VTYPE_IP(vtype)) {
memcpy(&vertex->N.ip, id, sizeof(vertex->N.ip));
} else {
flog_err(LIB_ERR_DEVELOPMENT, "Unknown Vertex Type");
}
}
__attribute__((__unused__))
static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
const void *id,
enum vertextype vtype)
{
struct isis_vertex querier;
isis_vertex_id_init(&querier, id, vtype);
return hash_lookup(queue->hash, &querier);
}
__attribute__((__unused__))
static struct isis_lsp *lsp_for_vertex(struct isis_spftree *spftree,
struct isis_vertex *vertex)
{
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
assert(VTYPE_IS(vertex->type));
memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT(lsp_id) = 0;
dict_t *lspdb = spftree->area->lspdb[spftree->level - 1];
struct isis_lsp *lsp = lsp_search(lsp_id, lspdb);
if (lsp && lsp->hdr.rem_lifetime != 0)
return lsp;
return NULL;
}
#define VID2STR_BUFFER SRCDEST2STR_BUFFER
const char *vid2string(struct isis_vertex *vertex, char *buff, int size);
#endif

View File

@ -67,17 +67,6 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
* Followings are control functions for MPLS-TE parameters management.
*------------------------------------------------------------------------*/
/* Search MPLS TE Circuit context from Interface */
static struct mpls_te_circuit *lookup_mpls_params_by_ifp(struct interface *ifp)
{
struct isis_circuit *circuit;
if ((circuit = circuit_scan_by_ifp(ifp)) == NULL)
return NULL;
return circuit->mtc;
}
/* Create new MPLS TE Circuit context */
struct mpls_te_circuit *mpls_te_circuit_new()
{
@ -1085,6 +1074,18 @@ void isis_mpls_te_config_write_router(struct vty *vty)
/*------------------------------------------------------------------------*
* Followings are vty command functions.
*------------------------------------------------------------------------*/
#ifndef FABRICD
/* Search MPLS TE Circuit context from Interface */
static struct mpls_te_circuit *lookup_mpls_params_by_ifp(struct interface *ifp)
{
struct isis_circuit *circuit;
if ((circuit = circuit_scan_by_ifp(ifp)) == NULL)
return NULL;
return circuit->mtc;
}
DEFUN (isis_mpls_te_on,
isis_mpls_te_on_cmd,
@ -1223,9 +1224,9 @@ DEFUN (no_isis_mpls_te_inter_as,
DEFUN (show_isis_mpls_te_router,
show_isis_mpls_te_router_cmd,
"show isis mpls-te router",
"show " PROTO_NAME " mpls-te router",
SHOW_STR
ISIS_STR
PROTO_HELP
MPLS_TE_STR
"Router information\n")
{
@ -1314,9 +1315,9 @@ static void show_mpls_te_sub(struct vty *vty, struct interface *ifp)
DEFUN (show_isis_mpls_te_interface,
show_isis_mpls_te_interface_cmd,
"show isis mpls-te interface [INTERFACE]",
"show " PROTO_NAME " mpls-te interface [INTERFACE]",
SHOW_STR
ISIS_STR
PROTO_HELP
MPLS_TE_STR
"Interface information\n"
"Interface name\n")
@ -1342,6 +1343,7 @@ DEFUN (show_isis_mpls_te_interface,
return CMD_SUCCESS;
}
#endif
/* Initialize MPLS_TE */
void isis_mpls_te_init(void)
@ -1357,15 +1359,17 @@ void isis_mpls_te_init(void)
isisMplsTE.cir_list = list_new();
isisMplsTE.router_id.s_addr = 0;
#ifndef FABRICD
/* Register new VTY commands */
install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
install_element(VIEW_NODE, &show_isis_mpls_te_interface_cmd);
install_element(ISIS_NODE, &isis_mpls_te_on_cmd);
install_element(ISIS_NODE, &no_isis_mpls_te_on_cmd);
install_element(ISIS_NODE, &isis_mpls_te_router_addr_cmd);
install_element(ISIS_NODE, &isis_mpls_te_inter_as_cmd);
install_element(ISIS_NODE, &no_isis_mpls_te_inter_as_cmd);
install_element(ROUTER_NODE, &isis_mpls_te_on_cmd);
install_element(ROUTER_NODE, &no_isis_mpls_te_on_cmd);
install_element(ROUTER_NODE, &isis_mpls_te_router_addr_cmd);
install_element(ROUTER_NODE, &isis_mpls_te_inter_as_cmd);
install_element(ROUTER_NODE, &no_isis_mpls_te_inter_as_cmd);
#endif
return;
}

View File

@ -107,6 +107,111 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
/* Prototypes */
static void append_item(struct isis_item_list *dest, struct isis_item *item);
/* Functions for Sub-TLV 3 SR Prefix-SID */
static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
struct isis_prefix_sid *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
rv->flags = sid->flags;
rv->algorithm = sid->algorithm;
rv->value = sid->value;
return (struct isis_item *)rv;
}
static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
struct sbuf *buf, int indent)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
sbuf_push(buf, indent, "SR Prefix-SID:\n");
sbuf_push(buf, indent, " Flags:%s%s%s%s%s%s\n",
sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "",
sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "",
sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "",
sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
sbuf_push(buf, indent, " Algorithm: %" PRIu8 "\n", sid->algorithm);
if (sid->flags & ISIS_PREFIX_SID_VALUE) {
sbuf_push(buf, indent, "Label: %" PRIu32 "\n", sid->value);
} else {
sbuf_push(buf, indent, "Index: %" PRIu32 "\n", sid->value);
}
}
static void free_item_prefix_sid(struct isis_item *i)
{
XFREE(MTYPE_ISIS_SUBTLV, i);
}
static int pack_item_prefix_sid(struct isis_item *i, struct stream *s)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
if (STREAM_WRITEABLE(s) < size)
return 1;
stream_putc(s, sid->flags);
stream_putc(s, sid->algorithm);
if (sid->flags & ISIS_PREFIX_SID_VALUE) {
stream_put3(s, sid->value);
} else {
stream_putl(s, sid->value);
}
return 0;
}
static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
struct sbuf *log, void *dest, int indent)
{
struct isis_subtlvs *subtlvs = dest;
struct isis_prefix_sid sid = {
};
sbuf_push(log, indent, "Unpacking SR Prefix-SID...\n");
if (len < 5) {
sbuf_push(log, indent,
"Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
len);
return 1;
}
sid.flags = stream_getc(s);
if ((sid.flags & ISIS_PREFIX_SID_VALUE)
!= (sid.flags & ISIS_PREFIX_SID_LOCAL)) {
sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n");
return 0;
}
sid.algorithm = stream_getc(s);
uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
if (len != expected_size) {
sbuf_push(log, indent,
"TLV size differs from expected size. "
"(expected %u but got %" PRIu8 ")\n",
expected_size, len);
return 1;
}
if (sid.flags & ISIS_PREFIX_SID_VALUE) {
sid.value = stream_get3(s);
} else {
sid.value = stream_getl(s);
}
format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
return 0;
}
/* Functions for Sub-TVL ??? IPv6 Source Prefix */
static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
@ -198,14 +303,36 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
memcpy(subtlvs->source_prefix, &p, sizeof(p));
return 0;
}
static void init_item_list(struct isis_item_list *items);
static struct isis_item *copy_item(enum isis_tlv_context context,
enum isis_tlv_type type,
struct isis_item *item);
static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
struct isis_item_list *src, struct isis_item_list *dest);
static void format_items_(uint16_t mtid, enum isis_tlv_context context,
enum isis_tlv_type type, struct isis_item_list *items,
struct sbuf *buf, int indent);
#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
struct isis_item_list *items);
static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
enum isis_tlv_type type, struct isis_item_list *items,
struct stream *s, struct isis_tlvs **fragment_tlvs,
struct pack_order_entry *pe,
struct isis_tlvs *(*new_fragment)(struct list *l),
struct list *new_fragment_arg);
#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
/* Functions related to subtlvs */
static struct isis_subtlvs *isis_alloc_subtlvs(void)
static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context)
{
struct isis_subtlvs *result;
result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
result->context = context;
init_item_list(&result->prefix_sids);
return result;
}
@ -217,6 +344,11 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
rv->context = subtlvs->context;
copy_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
&subtlvs->prefix_sids, &rv->prefix_sids);
rv->source_prefix =
copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
return rv;
@ -225,6 +357,9 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
int indent)
{
format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
&subtlvs->prefix_sids, buf, indent);
format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
}
@ -233,6 +368,9 @@ static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
if (!subtlvs)
return;
free_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
&subtlvs->prefix_sids);
XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
@ -248,6 +386,11 @@ static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
rv = pack_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
&subtlvs->prefix_sids, s, NULL, NULL, NULL, NULL);
if (rv)
return rv;
rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
if (rv)
return rv;
@ -1135,6 +1278,7 @@ static void free_item_extended_ip_reach(struct isis_item *i)
{
struct isis_extended_ip_reach *item =
(struct isis_extended_ip_reach *)i;
isis_free_subtlvs(item->subtlvs);
XFREE(MTYPE_ISIS_TLV, item);
}
@ -1149,11 +1293,16 @@ static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
control |= r->prefix.prefixlen;
control |= r->subtlvs ? ISIS_EXTENDED_IP_REACH_SUBTLV : 0;
stream_putc(s, control);
if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
return 1;
stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
if (r->subtlvs)
return pack_subtlvs(r->subtlvs, s);
return 0;
}
@ -1235,9 +1384,12 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
len - 6 - PSIZE(rv->prefix.prefixlen));
goto out;
}
sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls",
subtlv_len);
stream_forward_getp(s, subtlv_len);
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
log, rv->subtlvs, indent + 4)) {
goto out;
}
}
append_item(items, (struct isis_item *)rv);
@ -1329,6 +1481,126 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
return 0;
}
/* Functions related to TLV 150 Spine-Leaf-Extension */
static struct isis_spine_leaf *copy_tlv_spine_leaf(
const struct isis_spine_leaf *spine_leaf)
{
if (!spine_leaf)
return NULL;
struct isis_spine_leaf *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
memcpy(rv, spine_leaf, sizeof(*rv));
return rv;
}
static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
struct sbuf *buf, int indent)
{
if (!spine_leaf)
return;
sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
if (spine_leaf->has_tier) {
if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
sbuf_push(buf, indent, " Tier: undefined\n");
} else {
sbuf_push(buf, indent, " Tier: %" PRIu8 "\n",
spine_leaf->tier);
}
}
sbuf_push(buf, indent, " Flags:%s%s%s\n",
spine_leaf->is_leaf ? " LEAF" : "",
spine_leaf->is_spine ? " SPINE" : "",
spine_leaf->is_backup ? " BACKUP" : "");
}
static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
{
XFREE(MTYPE_ISIS_TLV, spine_leaf);
}
#define ISIS_SPINE_LEAF_FLAG_TIER 0x08
#define ISIS_SPINE_LEAF_FLAG_BACKUP 0x04
#define ISIS_SPINE_LEAF_FLAG_SPINE 0x02
#define ISIS_SPINE_LEAF_FLAG_LEAF 0x01
static int pack_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
struct stream *s)
{
if (!spine_leaf)
return 0;
uint8_t tlv_len = 2;
if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
return 1;
stream_putc(s, ISIS_TLV_SPINE_LEAF_EXT);
stream_putc(s, tlv_len);
uint16_t spine_leaf_flags = 0;
if (spine_leaf->has_tier) {
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_TIER;
spine_leaf_flags |= spine_leaf->tier << 12;
}
if (spine_leaf->is_leaf)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_LEAF;
if (spine_leaf->is_spine)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_SPINE;
if (spine_leaf->is_backup)
spine_leaf_flags |= ISIS_SPINE_LEAF_FLAG_BACKUP;
stream_putw(s, spine_leaf_flags);
return 0;
}
static int unpack_tlv_spine_leaf(enum isis_tlv_context context,
uint8_t tlv_type, uint8_t tlv_len,
struct stream *s, struct sbuf *log,
void *dest, int indent)
{
struct isis_tlvs *tlvs = dest;
sbuf_push(log, indent, "Unpacking Spine Leaf Extension TLV...\n");
if (tlv_len < 2) {
sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
stream_forward_getp(s, tlv_len);
return 0;
}
if (tlvs->spine_leaf) {
sbuf_push(log, indent,
"WARNING: Spine Leaf Extension TLV present multiple times.\n");
stream_forward_getp(s, tlv_len);
return 0;
}
tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
uint16_t spine_leaf_flags = stream_getw(s);
if (spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_TIER) {
tlvs->spine_leaf->has_tier = true;
tlvs->spine_leaf->tier = spine_leaf_flags >> 12;
}
tlvs->spine_leaf->is_leaf = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_LEAF;
tlvs->spine_leaf->is_spine = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_SPINE;
tlvs->spine_leaf->is_backup = spine_leaf_flags & ISIS_SPINE_LEAF_FLAG_BACKUP;
stream_forward_getp(s, tlv_len - 2);
return 0;
}
/* Functions related to TLV 240 P2P Three-Way Adjacency */
const char *isis_threeway_state_name(enum isis_threeway_state state)
@ -1592,7 +1864,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
goto out;
}
rv->subtlvs = isis_alloc_subtlvs();
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
log, rv->subtlvs, indent + 4)) {
goto out;
@ -1713,6 +1985,114 @@ static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
return 0;
}
/* Functions related to TLV 13 Purge Originator */
static struct isis_purge_originator *copy_tlv_purge_originator(
struct isis_purge_originator *poi)
{
if (!poi)
return NULL;
struct isis_purge_originator *rv;
rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
rv->sender_set = poi->sender_set;
memcpy(rv->generator, poi->generator, sizeof(rv->generator));
if (poi->sender_set)
memcpy(rv->sender, poi->sender, sizeof(rv->sender));
return rv;
}
static void format_tlv_purge_originator(struct isis_purge_originator *poi,
struct sbuf *buf, int indent)
{
if (!poi)
return;
sbuf_push(buf, indent, "Purge Originator Identification:\n");
sbuf_push(buf, indent, " Generator: %s\n",
isis_format_id(poi->generator, sizeof(poi->generator)));
if (poi->sender_set) {
sbuf_push(buf, indent, " Received-From: %s\n",
isis_format_id(poi->sender, sizeof(poi->sender)));
}
}
static void free_tlv_purge_originator(struct isis_purge_originator *poi)
{
XFREE(MTYPE_ISIS_TLV, poi);
}
static int pack_tlv_purge_originator(struct isis_purge_originator *poi,
struct stream *s)
{
if (!poi)
return 0;
uint8_t data_len = 1 + sizeof(poi->generator);
if (poi->sender_set)
data_len += sizeof(poi->sender);
if (STREAM_WRITEABLE(s) < (unsigned)(2 + data_len))
return 1;
stream_putc(s, ISIS_TLV_PURGE_ORIGINATOR);
stream_putc(s, data_len);
stream_putc(s, poi->sender_set ? 2 : 1);
stream_put(s, poi->generator, sizeof(poi->generator));
if (poi->sender_set)
stream_put(s, poi->sender, sizeof(poi->sender));
return 0;
}
static int unpack_tlv_purge_originator(enum isis_tlv_context context,
uint8_t tlv_type, uint8_t tlv_len,
struct stream *s, struct sbuf *log,
void *dest, int indent)
{
struct isis_tlvs *tlvs = dest;
struct isis_purge_originator poi = {};
sbuf_push(log, indent, "Unpacking Purge Originator Identification TLV...\n");
if (tlv_len < 7) {
sbuf_push(log, indent, "Not enough data left. (Expected at least 7 bytes, got %"
PRIu8 ")\n", tlv_len);
return 1;
}
uint8_t number_of_ids = stream_getc(s);
if (number_of_ids == 1) {
poi.sender_set = false;
} else if (number_of_ids == 2) {
poi.sender_set = true;
} else {
sbuf_push(log, indent, "Got invalid value for number of system IDs: %"
PRIu8 ")\n", number_of_ids);
return 1;
}
if (tlv_len != 1 + 6 * number_of_ids) {
sbuf_push(log, indent, "Incorrect tlv len for number of IDs.\n");
return 1;
}
stream_get(poi.generator, s, sizeof(poi.generator));
if (poi.sender_set)
stream_get(poi.sender, s, sizeof(poi.sender));
if (tlvs->purge_originator) {
sbuf_push(log, indent,
"WARNING: Purge originator present multiple times, ignoring.\n");
return 0;
}
tlvs->purge_originator = copy_tlv_purge_originator(&poi);
return 0;
}
/* Functions relating to item TLVs */
static void init_item_list(struct isis_item_list *items)
@ -1770,7 +2150,6 @@ static void format_items_(uint16_t mtid, enum isis_tlv_context context,
for (i = items->head; i; i = i->next)
format_item(mtid, context, type, i, buf, indent);
}
#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
static void free_item(enum isis_tlv_context tlv_context,
enum isis_tlv_type tlv_type, struct isis_item *item)
@ -1876,6 +2255,14 @@ top:
break;
}
/* Multiple prefix-sids don't go into one TLV, so always break */
if (type == ISIS_SUBTLV_PREFIX_SID
&& (context == ISIS_CONTEXT_SUBTLV_IP_REACH
|| context == ISIS_CONTEXT_SUBTLV_IPV6_REACH)) {
item = item->next;
break;
}
if (len > 255) {
if (!last_len) /* strange, not a single item fit */
return 1;
@ -2131,6 +2518,9 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
&rv->isis_auth);
rv->purge_originator =
copy_tlv_purge_originator(tlvs->purge_originator);
copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
&tlvs->area_addresses, &rv->area_addresses);
@ -2187,6 +2577,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
return rv;
}
@ -2197,6 +2589,8 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
indent);
format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
&tlvs->area_addresses, buf, indent);
@ -2250,6 +2644,8 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
&tlvs->mt_ipv6_reach, buf, indent);
format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
}
const char *isis_format_tlvs(struct isis_tlvs *tlvs)
@ -2270,6 +2666,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
return;
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
free_tlv_purge_originator(tlvs->purge_originator);
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
&tlvs->area_addresses);
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
@ -2301,6 +2698,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
&tlvs->mt_ipv6_reach);
free_tlv_threeway_adj(tlvs->threeway_adj);
free_tlv_spine_leaf(tlvs->spine_leaf);
XFREE(MTYPE_ISIS_TLV, tlvs);
}
@ -2417,6 +2815,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
return rv;
}
rv = pack_tlv_purge_originator(tlvs->purge_originator, stream);
if (rv)
return rv;
if (fragment_tlvs) {
fragment_tlvs->purge_originator =
copy_tlv_purge_originator(tlvs->purge_originator);
}
rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
if (rv)
return rv;
@ -2480,6 +2886,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
copy_tlv_threeway_adj(tlvs->threeway_adj);
}
rv = pack_tlv_spine_leaf(tlvs->spine_leaf, stream);
if (rv)
return rv;
if (fragment_tlvs) {
fragment_tlvs->spine_leaf =
copy_tlv_spine_leaf(tlvs->spine_leaf);
}
for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
pack_idx++) {
rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
@ -2667,11 +3081,15 @@ int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
.name = _desc_, .unpack = unpack_subtlv_##_name_, \
}
#define ITEM_SUBTLV_OPS(_name_, _desc_) \
ITEM_TLV_OPS(_name_, _desc_)
ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
TLV_OPS(purge_originator, "TLV 13 Purge Originator Identification");
ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
@ -2679,11 +3097,13 @@ ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
TLV_OPS(te_router_id, "TLV 134 TE Router ID");
ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
TLV_OPS(spine_leaf, "TLV 150 Spine Leaf Extensions");
ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
@ -2693,6 +3113,7 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
[ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
[ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
[ISIS_TLV_AUTH] = &tlv_auth_ops,
[ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
[ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
[ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
[ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
@ -2703,6 +3124,7 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
[ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
[ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
[ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
[ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
[ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
[ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
@ -2710,8 +3132,11 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
[ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
},
[ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
[ISIS_CONTEXT_SUBTLV_IP_REACH] = {},
[ISIS_CONTEXT_SUBTLV_IP_REACH] = {
[ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
},
[ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
[ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops,
[ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
}
};
@ -3183,7 +3608,7 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
mtid);
struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
r->subtlvs = isis_alloc_subtlvs();
r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
}
@ -3239,6 +3664,24 @@ void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
}
}
void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
bool has_tier, bool is_leaf, bool is_spine,
bool is_backup)
{
assert(!tlvs->spine_leaf);
tlvs->spine_leaf = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->spine_leaf));
if (has_tier) {
tlvs->spine_leaf->tier = tier;
}
tlvs->spine_leaf->has_tier = has_tier;
tlvs->spine_leaf->is_leaf = is_leaf;
tlvs->spine_leaf->is_spine = is_spine;
tlvs->spine_leaf->is_backup = is_backup;
}
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
{
@ -3254,3 +3697,20 @@ isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
return NULL;
}
void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
const uint8_t *generator,
const uint8_t *sender)
{
assert(!tlvs->purge_originator);
tlvs->purge_originator = XCALLOC(MTYPE_ISIS_TLV,
sizeof(*tlvs->purge_originator));
memcpy(tlvs->purge_originator->generator, generator,
sizeof(tlvs->purge_originator->generator));
if (sender) {
tlvs->purge_originator->sender_set = true;
memcpy(tlvs->purge_originator->sender, sender,
sizeof(tlvs->purge_originator->sender));
}
}

View File

@ -83,6 +83,8 @@ struct isis_extended_ip_reach {
uint32_t metric;
bool down;
struct prefix_ipv4 prefix;
struct isis_subtlvs *subtlvs;
};
struct isis_ipv6_reach;
@ -103,6 +105,17 @@ struct isis_protocols_supported {
uint8_t *protocols;
};
#define ISIS_TIER_UNDEFINED 15
struct isis_spine_leaf {
uint8_t tier;
bool has_tier;
bool is_leaf;
bool is_spine;
bool is_backup;
};
enum isis_threeway_state {
ISIS_THREEWAY_DOWN = 2,
ISIS_THREEWAY_INITIALIZING = 1,
@ -176,6 +189,13 @@ struct isis_item_list {
unsigned int count;
};
struct isis_purge_originator {
bool sender_set;
uint8_t generator[6];
uint8_t sender[6];
};
RB_HEAD(isis_mt_item_list, isis_item_list);
struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
@ -185,6 +205,7 @@ struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
struct isis_tlvs {
struct isis_item_list isis_auth;
struct isis_purge_originator *purge_originator;
struct isis_item_list area_addresses;
struct isis_item_list oldstyle_reach;
struct isis_item_list lan_neighbor;
@ -205,11 +226,24 @@ struct isis_tlvs {
struct isis_item_list ipv6_reach;
struct isis_mt_item_list mt_ipv6_reach;
struct isis_threeway_adj *threeway_adj;
struct isis_spine_leaf *spine_leaf;
};
struct isis_subtlvs {
/* draft-baker-ipv6-isis-dst-src-routing-06 */
struct prefix_ipv6 *source_prefix;
#define ISIS_PREFIX_SID_READVERTISED 0x80
#define ISIS_PREFIX_SID_NODE 0x40
#define ISIS_PREFIX_SID_NO_PHP 0x20
#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
#define ISIS_PREFIX_SID_VALUE 0x08
#define ISIS_PREFIX_SID_LOCAL 0x04
struct isis_prefix_sid;
struct isis_prefix_sid {
struct isis_prefix_sid *next;
uint8_t flags;
uint8_t algorithm;
uint32_t value;
};
enum isis_tlv_context {
@ -220,6 +254,15 @@ enum isis_tlv_context {
ISIS_CONTEXT_MAX
};
struct isis_subtlvs {
enum isis_tlv_context context;
/* draft-baker-ipv6-isis-dst-src-routing-06 */
struct prefix_ipv6 *source_prefix;
/* draft-ietf-isis-segment-routing-extensions-16 */
struct isis_item_list prefix_sids;
};
enum isis_tlv_type {
ISIS_TLV_AREA_ADDRESSES = 1,
ISIS_TLV_OLDSTYLE_REACH = 2,
@ -227,6 +270,7 @@ enum isis_tlv_type {
ISIS_TLV_PADDING = 8,
ISIS_TLV_LSP_ENTRY = 9,
ISIS_TLV_AUTH = 10,
ISIS_TLV_PURGE_ORIGINATOR = 13,
ISIS_TLV_EXTENDED_REACH = 22,
ISIS_TLV_OLDSTYLE_IP_REACH = 128,
@ -236,6 +280,7 @@ enum isis_tlv_type {
ISIS_TLV_TE_ROUTER_ID = 134,
ISIS_TLV_EXTENDED_IP_REACH = 135,
ISIS_TLV_DYNAMIC_HOSTNAME = 137,
ISIS_TLV_SPINE_LEAF_EXT = 150,
ISIS_TLV_MT_REACH = 222,
ISIS_TLV_MT_ROUTER_INFO = 229,
ISIS_TLV_IPV6_ADDRESS = 232,
@ -245,6 +290,7 @@ enum isis_tlv_type {
ISIS_TLV_THREE_WAY_ADJ = 240,
ISIS_TLV_MAX = 256,
ISIS_SUBTLV_PREFIX_SID = 3,
ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
};
@ -331,6 +377,14 @@ void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
const uint8_t *neighbor_id,
uint32_t neighbor_circuit_id);
void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
bool has_tier, bool is_leaf, bool is_spine,
bool is_backup);
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid);
void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs,
const uint8_t *generator,
const uint8_t *sender);
#endif

182
isisd/isis_tx_queue.c Normal file
View File

@ -0,0 +1,182 @@
/*
* IS-IS Rout(e)ing protocol - LSP TX Queuing logic
*
* Copyright (C) 2018 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "hash.h"
#include "jhash.h"
#include "isisd/isisd.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_flags.h"
#include "dict.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_tx_queue.h"
DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue")
DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry")
struct isis_tx_queue {
void *arg;
void (*send_event)(void *arg, struct isis_lsp *, enum isis_tx_type);
struct hash *hash;
};
struct isis_tx_queue_entry {
struct isis_lsp *lsp;
enum isis_tx_type type;
struct thread *retry;
struct isis_tx_queue *queue;
};
static unsigned tx_queue_hash_key(void *p)
{
struct isis_tx_queue_entry *e = p;
uint32_t id_key = jhash(e->lsp->hdr.lsp_id,
ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
return jhash_1word(e->lsp->level, id_key);
}
static int tx_queue_hash_cmp(const void *a, const void *b)
{
const struct isis_tx_queue_entry *ea = a, *eb = b;
if (ea->lsp->level != eb->lsp->level)
return 0;
if (memcmp(ea->lsp->hdr.lsp_id, eb->lsp->hdr.lsp_id,
ISIS_SYS_ID_LEN + 2))
return 0;
return 1;
}
struct isis_tx_queue *isis_tx_queue_new(void *arg,
void(*send_event)(void *arg,
struct isis_lsp *,
enum isis_tx_type))
{
struct isis_tx_queue *rv = XCALLOC(MTYPE_TX_QUEUE, sizeof(*rv));
rv->arg = arg;
rv->send_event = send_event;
rv->hash = hash_create(tx_queue_hash_key, tx_queue_hash_cmp, NULL);
return rv;
}
static void tx_queue_element_free(void *element)
{
struct isis_tx_queue_entry *e = element;
if (e->retry)
thread_cancel(e->retry);
XFREE(MTYPE_TX_QUEUE_ENTRY, e);
}
void isis_tx_queue_free(struct isis_tx_queue *queue)
{
hash_clean(queue->hash, tx_queue_element_free);
hash_free(queue->hash);
XFREE(MTYPE_TX_QUEUE, queue);
}
static struct isis_tx_queue_entry *tx_queue_find(struct isis_tx_queue *queue,
struct isis_lsp *lsp)
{
struct isis_tx_queue_entry e = {
.lsp = lsp
};
return hash_lookup(queue->hash, &e);
}
static int tx_queue_send_event(struct thread *thread)
{
struct isis_tx_queue_entry *e = THREAD_ARG(thread);
struct isis_tx_queue *queue = e->queue;
e->retry = NULL;
thread_add_timer(master, tx_queue_send_event, e, 5, &e->retry);
queue->send_event(queue->arg, e->lsp, e->type);
/* Don't access e here anymore, send_event might have destroyed it */
return 0;
}
void isis_tx_queue_add(struct isis_tx_queue *queue,
struct isis_lsp *lsp,
enum isis_tx_type type)
{
if (!queue)
return;
struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
if (!e) {
e = XCALLOC(MTYPE_TX_QUEUE_ENTRY, sizeof(*e));
e->lsp = lsp;
e->queue = queue;
struct isis_tx_queue_entry *inserted;
inserted = hash_get(queue->hash, e, hash_alloc_intern);
assert(inserted == e);
}
e->type = type;
if (e->retry)
thread_cancel(e->retry);
thread_add_event(master, tx_queue_send_event, e, 0, &e->retry);
}
void isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp)
{
if (!queue)
return;
struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
if (!e)
return;
if (e->retry)
thread_cancel(e->retry);
hash_release(queue->hash, e);
XFREE(MTYPE_TX_QUEUE_ENTRY, e);
}
unsigned long isis_tx_queue_len(struct isis_tx_queue *queue)
{
if (!queue)
return 0;
return hashcount(queue->hash);
}
void isis_tx_queue_clean(struct isis_tx_queue *queue)
{
hash_clean(queue->hash, tx_queue_element_free);
}

View File

@ -1,7 +1,7 @@
/*
* IS-IS Rout(e)ing protocol - LSP Hash
* IS-IS Rout(e)ing protocol - LSP TX Queuing logic
*
* Copyright (C) 2017 Christian Franke
* Copyright (C) 2018 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
@ -19,16 +19,31 @@
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ISIS_LSP_HASH_H
#define ISIS_LSP_HASH_H
#ifndef ISIS_TX_QUEUE_H
#define ISIS_TX_QUEUE_H
struct isis_lsp_hash;
enum isis_tx_type {
TX_LSP_NORMAL = 0,
TX_LSP_CIRCUIT_SCOPED
};
struct isis_tx_queue;
struct isis_tx_queue *isis_tx_queue_new(void *arg,
void(*send_event)(void *arg,
struct isis_lsp *,
enum isis_tx_type));
void isis_tx_queue_free(struct isis_tx_queue *queue);
void isis_tx_queue_add(struct isis_tx_queue *queue,
struct isis_lsp *lsp,
enum isis_tx_type type);
void isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp);
unsigned long isis_tx_queue_len(struct isis_tx_queue *queue);
void isis_tx_queue_clean(struct isis_tx_queue *queue);
struct isis_lsp_hash *isis_lsp_hash_new(void);
void isis_lsp_hash_clean(struct isis_lsp_hash *ih);
void isis_lsp_hash_free(struct isis_lsp_hash *ih);
struct isis_lsp *isis_lsp_hash_lookup(struct isis_lsp_hash *ih,
struct isis_lsp *lsp);
void isis_lsp_hash_add(struct isis_lsp_hash *ih, struct isis_lsp *lsp);
void isis_lsp_hash_release(struct isis_lsp_hash *ih, struct isis_lsp *lsp);
#endif

File diff suppressed because it is too large Load Diff

960
isisd/isis_vty_common.c Normal file
View File

@ -0,0 +1,960 @@
/*
* IS-IS Rout(e)ing protocol - isis_vty_common.c
*
* This file contains the CLI that is shared between OpenFabric and IS-IS
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
* Copyright (C) 2016 David Lamparter, for NetDEF, Inc.
* Copyright (C) 2018 Christian Franke, for NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "command.h"
#include "spf_backoff.h"
#include "isis_circuit.h"
#include "isis_csm.h"
#include "isis_misc.h"
#include "isis_mt.h"
#include "isisd.h"
#include "isis_vty_common.h"
struct isis_circuit *isis_circuit_lookup(struct vty *vty)
{
struct interface *ifp = VTY_GET_CONTEXT(interface);
struct isis_circuit *circuit;
if (!ifp) {
vty_out(vty, "Invalid interface \n");
return NULL;
}
circuit = circuit_scan_by_ifp(ifp);
if (!circuit) {
vty_out(vty, "ISIS is not enabled on circuit %s\n", ifp->name);
return NULL;
}
return circuit;
}
DEFUN (ip_router_isis,
ip_router_isis_cmd,
"ip router " PROTO_NAME " WORD",
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
PROTO_HELP
"Routing process tag\n")
{
int idx_afi = 0;
int idx_word = 3;
VTY_DECLVAR_CONTEXT(interface, ifp);
struct isis_circuit *circuit;
struct isis_area *area;
const char *af = argv[idx_afi]->arg;
const char *area_tag = argv[idx_word]->arg;
/* Prevent more than one area per circuit */
circuit = circuit_scan_by_ifp(ifp);
if (circuit && circuit->area) {
if (strcmp(circuit->area->area_tag, area_tag)) {
vty_out(vty, "ISIS circuit is already defined on %s\n",
circuit->area->area_tag);
return CMD_ERR_NOTHING_TODO;
}
}
area = isis_area_lookup(area_tag);
if (!area)
area = isis_area_create(area_tag);
if (!circuit || !circuit->area) {
circuit = isis_circuit_create(area, ifp);
if (circuit->state != C_STATE_CONF
&& circuit->state != C_STATE_UP) {
vty_out(vty,
"Couldn't bring up interface, please check log.\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router;
if (af[2] != '\0')
ipv6 = true;
else
ip = true;
isis_circuit_af_set(circuit, ip, ipv6);
return CMD_SUCCESS;
}
DEFUN (ip6_router_isis,
ip6_router_isis_cmd,
"ipv6 router " PROTO_NAME " WORD",
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
PROTO_HELP
"Routing process tag\n")
{
return ip_router_isis(self, vty, argc, argv);
}
DEFUN (no_ip_router_isis,
no_ip_router_isis_cmd,
"no <ip|ipv6> router " PROTO_NAME " WORD",
NO_STR
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
"IP router interface commands\n"
PROTO_HELP
"Routing process tag\n")
{
int idx_afi = 1;
int idx_word = 4;
VTY_DECLVAR_CONTEXT(interface, ifp);
struct isis_area *area;
struct isis_circuit *circuit;
const char *af = argv[idx_afi]->arg;
const char *area_tag = argv[idx_word]->arg;
area = isis_area_lookup(area_tag);
if (!area) {
vty_out(vty, "Can't find ISIS instance %s\n",
area_tag);
return CMD_ERR_NO_MATCH;
}
circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
if (!circuit) {
vty_out(vty, "ISIS is not enabled on circuit %s\n", ifp->name);
return CMD_ERR_NO_MATCH;
}
bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router;
if (af[2] != '\0')
ipv6 = false;
else
ip = false;
isis_circuit_af_set(circuit, ip, ipv6);
return CMD_SUCCESS;
}
DEFUN (isis_passive,
isis_passive_cmd,
PROTO_NAME " passive",
PROTO_HELP
"Configure the passive mode for interface\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_passive_set(circuit, 1),
"Cannot set passive: $ERR");
return CMD_SUCCESS;
}
DEFUN (no_isis_passive,
no_isis_passive_cmd,
"no " PROTO_NAME " passive",
NO_STR
PROTO_HELP
"Configure the passive mode for interface\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_passive_set(circuit, 0),
"Cannot set no passive: $ERR");
return CMD_SUCCESS;
}
DEFUN (isis_passwd,
isis_passwd_cmd,
PROTO_NAME " password <md5|clear> WORD",
PROTO_HELP
"Configure the authentication password for a circuit\n"
"HMAC-MD5 authentication\n"
"Cleartext password\n"
"Circuit password\n")
{
int idx_encryption = 2;
int idx_word = 3;
struct isis_circuit *circuit = isis_circuit_lookup(vty);
ferr_r rv;
if (!circuit)
return CMD_ERR_NO_MATCH;
if (argv[idx_encryption]->arg[0] == 'm')
rv = isis_circuit_passwd_hmac_md5_set(circuit,
argv[idx_word]->arg);
else
rv = isis_circuit_passwd_cleartext_set(circuit,
argv[idx_word]->arg);
CMD_FERR_RETURN(rv, "Failed to set circuit password: $ERR");
return CMD_SUCCESS;
}
DEFUN (no_isis_passwd,
no_isis_passwd_cmd,
"no " PROTO_NAME " password [<md5|clear> WORD]",
NO_STR
PROTO_HELP
"Configure the authentication password for a circuit\n"
"HMAC-MD5 authentication\n"
"Cleartext password\n"
"Circuit password\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_passwd_unset(circuit),
"Failed to unset circuit password: $ERR");
return CMD_SUCCESS;
}
DEFUN (isis_metric,
isis_metric_cmd,
PROTO_NAME " metric (0-16777215)",
PROTO_HELP
"Set default metric for circuit\n"
"Default metric value\n")
{
int idx_number = 2;
int met;
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
met = atoi(argv[idx_number]->arg);
/* RFC3787 section 5.1 */
if (circuit->area && circuit->area->oldmetric == 1
&& met > MAX_NARROW_LINK_METRIC) {
vty_out(vty,
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
if (circuit->area && circuit->area->newmetric == 1
&& met > MAX_WIDE_LINK_METRIC) {
vty_out(vty,
"Invalid metric %d - should be <0-16777215> "
"when wide metric type enabled\n",
met);
return CMD_WARNING_CONFIG_FAILED;
}
CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1, met),
"Failed to set L1 metric: $ERR");
CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2, met),
"Failed to set L2 metric: $ERR");
return CMD_SUCCESS;
}
DEFUN (no_isis_metric,
no_isis_metric_cmd,
"no " PROTO_NAME " metric [(0-16777215)]",
NO_STR
PROTO_HELP
"Set default metric for circuit\n"
"Default metric value\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_1,
DEFAULT_CIRCUIT_METRIC),
"Failed to set L1 metric: $ERR");
CMD_FERR_RETURN(isis_circuit_metric_set(circuit, IS_LEVEL_2,
DEFAULT_CIRCUIT_METRIC),
"Failed to set L2 metric: $ERR");
return CMD_SUCCESS;
}
DEFUN (isis_hello_interval,
isis_hello_interval_cmd,
PROTO_NAME " hello-interval (1-600)",
PROTO_HELP
"Set Hello interval\n"
"Holdtime 1 seconds, interval depends on multiplier\n")
{
uint32_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_interval[0] = interval;
circuit->hello_interval[1] = interval;
return CMD_SUCCESS;
}
DEFUN (no_isis_hello_interval,
no_isis_hello_interval_cmd,
"no " PROTO_NAME " hello-interval [(1-600)]",
NO_STR
PROTO_HELP
"Set Hello interval\n"
"Holdtime 1 second, interval depends on multiplier\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL;
circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (isis_hello_multiplier,
isis_hello_multiplier_cmd,
PROTO_NAME " hello-multiplier (2-100)",
PROTO_HELP
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n")
{
uint16_t mult = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_multiplier[0] = mult;
circuit->hello_multiplier[1] = mult;
return CMD_SUCCESS;
}
DEFUN (no_isis_hello_multiplier,
no_isis_hello_multiplier_cmd,
"no " PROTO_NAME " hello-multiplier [(2-100)]",
NO_STR
PROTO_HELP
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER;
circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER;
return CMD_SUCCESS;
}
DEFUN (csnp_interval,
csnp_interval_cmd,
PROTO_NAME " csnp-interval (1-600)",
PROTO_HELP
"Set CSNP interval in seconds\n"
"CSNP interval value\n")
{
uint16_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->csnp_interval[0] = interval;
circuit->csnp_interval[1] = interval;
return CMD_SUCCESS;
}
DEFUN (no_csnp_interval,
no_csnp_interval_cmd,
"no " PROTO_NAME " csnp-interval [(1-600)]",
NO_STR
PROTO_HELP
"Set CSNP interval in seconds\n"
"CSNP interval value\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL;
circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (psnp_interval,
psnp_interval_cmd,
PROTO_NAME " psnp-interval (1-120)",
PROTO_HELP
"Set PSNP interval in seconds\n"
"PSNP interval value\n")
{
uint16_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->psnp_interval[0] = interval;
circuit->psnp_interval[1] = interval;
return CMD_SUCCESS;
}
DEFUN (no_psnp_interval,
no_psnp_interval_cmd,
"no " PROTO_NAME " psnp-interval [(1-120)]",
NO_STR
PROTO_HELP
"Set PSNP interval in seconds\n"
"PSNP interval value\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL;
circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (circuit_topology,
circuit_topology_cmd,
PROTO_NAME " topology " ISIS_MT_NAMES,
PROTO_HELP
"Configure interface IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS)
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
const char *arg = argv[2]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (circuit->area && circuit->area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_WARNING_CONFIG_FAILED;
}
return isis_circuit_mt_enabled_set(circuit, mtid, true);
}
DEFUN (no_circuit_topology,
no_circuit_topology_cmd,
"no " PROTO_NAME " topology " ISIS_MT_NAMES,
NO_STR
PROTO_HELP
"Configure interface IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS)
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
const char *arg = argv[3]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (circuit->area && circuit->area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_WARNING_CONFIG_FAILED;
}
return isis_circuit_mt_enabled_set(circuit, mtid, false);
}
DEFUN (set_overload_bit,
set_overload_bit_cmd,
"set-overload-bit",
"Set overload bit to avoid any transit traffic\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_overload_bit_set(area, true);
return CMD_SUCCESS;
}
DEFUN (no_set_overload_bit,
no_set_overload_bit_cmd,
"no set-overload-bit",
"Reset overload bit to accept transit traffic\n"
"Reset overload bit\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_overload_bit_set(area, false);
return CMD_SUCCESS;
}
static int isis_vty_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu)
{
VTY_DECLVAR_CONTEXT(isis_area, area);
struct listnode *node;
struct isis_circuit *circuit;
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if (circuit->state != C_STATE_INIT
&& circuit->state != C_STATE_UP)
continue;
if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
vty_out(vty,
"ISIS area contains circuit %s, which has a maximum PDU size of %zu.\n",
circuit->interface->name,
isis_circuit_pdu_size(circuit));
return CMD_WARNING_CONFIG_FAILED;
}
}
isis_area_lsp_mtu_set(area, lsp_mtu);
return CMD_SUCCESS;
}
DEFUN (area_lsp_mtu,
area_lsp_mtu_cmd,
"lsp-mtu (128-4352)",
"Configure the maximum size of generated LSPs\n"
"Maximum size of generated LSPs\n")
{
int idx_number = 1;
unsigned int lsp_mtu;
lsp_mtu = strtoul(argv[idx_number]->arg, NULL, 10);
return isis_vty_lsp_mtu_set(vty, lsp_mtu);
}
DEFUN (no_area_lsp_mtu,
no_area_lsp_mtu_cmd,
"no lsp-mtu [(128-4352)]",
NO_STR
"Configure the maximum size of generated LSPs\n"
"Maximum size of generated LSPs\n")
{
return isis_vty_lsp_mtu_set(vty, DEFAULT_LSP_MTU);
}
DEFUN (area_purge_originator,
area_purge_originator_cmd,
"[no] purge-originator",
NO_STR
"Use the RFC 6232 purge-originator\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
area->purge_originator = !!strcmp(argv[0]->text, "no");
return CMD_SUCCESS;
}
int isis_vty_lsp_gen_interval_set(struct vty *vty, int level, uint16_t interval)
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int lvl;
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
if (!(lvl & level))
continue;
if (interval >= area->lsp_refresh[lvl - 1]) {
vty_out(vty,
"LSP gen interval %us must be less than "
"the LSP refresh interval %us\n",
interval, area->lsp_refresh[lvl - 1]);
return CMD_WARNING_CONFIG_FAILED;
}
}
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
if (!(lvl & level))
continue;
area->lsp_gen_interval[lvl - 1] = interval;
}
return CMD_SUCCESS;
}
DEFUN (lsp_gen_interval,
lsp_gen_interval_cmd,
"lsp-gen-interval (1-120)",
"Minimum interval between regenerating same LSP\n"
"Minimum interval in seconds\n")
{
uint16_t interval = atoi(argv[1]->arg);
return isis_vty_lsp_gen_interval_set(vty, IS_LEVEL_1_AND_2, interval);
}
DEFUN (no_lsp_gen_interval,
no_lsp_gen_interval_cmd,
"no lsp-gen-interval [(1-120)]",
NO_STR
"Minimum interval between regenerating same LSP\n"
"Minimum interval in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
return isis_vty_lsp_gen_interval_set(vty, IS_LEVEL_1_AND_2,
DEFAULT_MIN_LSP_GEN_INTERVAL);
}
DEFUN (spf_interval,
spf_interval_cmd,
"spf-interval (1-120)",
"Minimum interval between SPF calculations\n"
"Minimum interval between consecutive SPFs in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
uint16_t interval = atoi(argv[1]->arg);
area->min_spf_interval[0] = interval;
area->min_spf_interval[1] = interval;
return CMD_SUCCESS;
}
DEFUN (no_spf_interval,
no_spf_interval_cmd,
"no spf-interval [(1-120)]",
NO_STR
"Minimum interval between SPF calculations\n"
"Minimum interval between consecutive SPFs in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (no_spf_delay_ietf,
no_spf_delay_ietf_cmd,
"no spf-delay-ietf",
NO_STR
"IETF SPF delay algorithm\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
spf_backoff_free(area->spf_delay_ietf[0]);
spf_backoff_free(area->spf_delay_ietf[1]);
area->spf_delay_ietf[0] = NULL;
area->spf_delay_ietf[1] = NULL;
return CMD_SUCCESS;
}
DEFUN (spf_delay_ietf,
spf_delay_ietf_cmd,
"spf-delay-ietf init-delay (0-60000) short-delay (0-60000) long-delay (0-60000) holddown (0-60000) time-to-learn (0-60000)",
"IETF SPF delay algorithm\n"
"Delay used while in QUIET state\n"
"Delay used while in QUIET state in milliseconds\n"
"Delay used while in SHORT_WAIT state\n"
"Delay used while in SHORT_WAIT state in milliseconds\n"
"Delay used while in LONG_WAIT\n"
"Delay used while in LONG_WAIT state in milliseconds\n"
"Time with no received IGP events before considering IGP stable\n"
"Time with no received IGP events before considering IGP stable (in milliseconds)\n"
"Maximum duration needed to learn all the events related to a single failure\n"
"Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
long init_delay = atol(argv[2]->arg);
long short_delay = atol(argv[4]->arg);
long long_delay = atol(argv[6]->arg);
long holddown = atol(argv[8]->arg);
long timetolearn = atol(argv[10]->arg);
size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
char *buf = XCALLOC(MTYPE_TMP, bufsiz);
snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
spf_backoff_free(area->spf_delay_ietf[0]);
area->spf_delay_ietf[0] =
spf_backoff_new(master, buf, init_delay, short_delay,
long_delay, holddown, timetolearn);
snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
spf_backoff_free(area->spf_delay_ietf[1]);
area->spf_delay_ietf[1] =
spf_backoff_new(master, buf, init_delay, short_delay,
long_delay, holddown, timetolearn);
XFREE(MTYPE_TMP, buf);
return CMD_SUCCESS;
}
int isis_vty_max_lsp_lifetime_set(struct vty *vty, int level, uint16_t interval)
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int lvl;
uint16_t refresh_interval = interval - 300;
int set_refresh_interval[ISIS_LEVELS] = {0, 0};
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
if (!(lvl & level))
continue;
if (refresh_interval < area->lsp_refresh[lvl - 1]) {
vty_out(vty,
"Level %d Max LSP lifetime %us must be 300s greater than "
"the configured LSP refresh interval %us\n",
lvl, interval, area->lsp_refresh[lvl - 1]);
vty_out(vty,
"Automatically reducing level %d LSP refresh interval "
"to %us\n",
lvl, refresh_interval);
set_refresh_interval[lvl - 1] = 1;
if (refresh_interval
<= area->lsp_gen_interval[lvl - 1]) {
vty_out(vty,
"LSP refresh interval %us must be greater than "
"the configured LSP gen interval %us\n",
refresh_interval,
area->lsp_gen_interval[lvl - 1]);
return CMD_WARNING_CONFIG_FAILED;
}
}
}
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
if (!(lvl & level))
continue;
isis_area_max_lsp_lifetime_set(area, lvl, interval);
if (set_refresh_interval[lvl - 1])
isis_area_lsp_refresh_set(area, lvl, refresh_interval);
}
return CMD_SUCCESS;
}
DEFUN (max_lsp_lifetime,
max_lsp_lifetime_cmd,
"max-lsp-lifetime (350-65535)",
"Maximum LSP lifetime\n"
"LSP lifetime in seconds\n")
{
int lifetime = atoi(argv[1]->arg);
return isis_vty_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, lifetime);
}
DEFUN (no_max_lsp_lifetime,
no_max_lsp_lifetime_cmd,
"no max-lsp-lifetime [(350-65535)]",
NO_STR
"Maximum LSP lifetime\n"
"LSP lifetime in seconds\n")
{
return isis_vty_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2,
DEFAULT_LSP_LIFETIME);
}
int isis_vty_lsp_refresh_set(struct vty *vty, int level, uint16_t interval)
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int lvl;
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
if (!(lvl & level))
continue;
if (interval <= area->lsp_gen_interval[lvl - 1]) {
vty_out(vty,
"LSP refresh interval %us must be greater than "
"the configured LSP gen interval %us\n",
interval, area->lsp_gen_interval[lvl - 1]);
return CMD_WARNING_CONFIG_FAILED;
}
if (interval > (area->max_lsp_lifetime[lvl - 1] - 300)) {
vty_out(vty,
"LSP refresh interval %us must be less than "
"the configured LSP lifetime %us less 300\n",
interval, area->max_lsp_lifetime[lvl - 1]);
return CMD_WARNING_CONFIG_FAILED;
}
}
for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
if (!(lvl & level))
continue;
isis_area_lsp_refresh_set(area, lvl, interval);
}
return CMD_SUCCESS;
}
DEFUN (lsp_refresh_interval,
lsp_refresh_interval_cmd,
"lsp-refresh-interval (1-65235)",
"LSP refresh interval\n"
"LSP refresh interval in seconds\n")
{
unsigned int interval = atoi(argv[1]->arg);
return isis_vty_lsp_refresh_set(vty, IS_LEVEL_1_AND_2, interval);
}
DEFUN (no_lsp_refresh_interval,
no_lsp_refresh_interval_cmd,
"no lsp-refresh-interval [(1-65235)]",
NO_STR
"LSP refresh interval\n"
"LSP refresh interval in seconds\n")
{
return isis_vty_lsp_refresh_set(vty, IS_LEVEL_1_AND_2,
DEFAULT_MAX_LSP_GEN_INTERVAL);
}
int isis_vty_password_set(struct vty *vty, int argc,
struct cmd_token *argv[], int level)
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int idx_algo = 1;
int idx_password = 2;
int idx_snp_auth = 5;
uint8_t snp_auth = 0;
const char *passwd = argv[idx_password]->arg;
if (strlen(passwd) > 254) {
vty_out(vty, "Too long area password (>254)\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (argc > idx_snp_auth) {
snp_auth = SNP_AUTH_SEND;
if (strmatch(argv[idx_snp_auth]->text, "validate"))
snp_auth |= SNP_AUTH_RECV;
}
if (strmatch(argv[idx_algo]->text, "clear")) {
return isis_area_passwd_cleartext_set(area, level,
passwd, snp_auth);
} else if (strmatch(argv[idx_algo]->text, "md5")) {
return isis_area_passwd_hmac_md5_set(area, level,
passwd, snp_auth);
}
return CMD_WARNING_CONFIG_FAILED;
}
DEFUN (domain_passwd,
domain_passwd_cmd,
"domain-password <clear|md5> WORD [authenticate snp <send-only|validate>]",
"Set the authentication password for a routing domain\n"
"Authentication type\n"
"Authentication type\n"
"Level-wide password\n"
"Authentication\n"
"SNP PDUs\n"
"Send but do not check PDUs on receiving\n"
"Send and check PDUs on receiving\n")
{
return isis_vty_password_set(vty, argc, argv, IS_LEVEL_2);
}
DEFUN (no_domain_passwd,
no_domain_passwd_cmd,
"no domain-password",
NO_STR
"Set the authentication password for a routing domain\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
return isis_area_passwd_unset(area, IS_LEVEL_2);
}
void isis_vty_init(void)
{
install_element(INTERFACE_NODE, &ip_router_isis_cmd);
install_element(INTERFACE_NODE, &ip6_router_isis_cmd);
install_element(INTERFACE_NODE, &no_ip_router_isis_cmd);
install_element(INTERFACE_NODE, &isis_passive_cmd);
install_element(INTERFACE_NODE, &no_isis_passive_cmd);
install_element(INTERFACE_NODE, &isis_passwd_cmd);
install_element(INTERFACE_NODE, &no_isis_passwd_cmd);
install_element(INTERFACE_NODE, &isis_metric_cmd);
install_element(INTERFACE_NODE, &no_isis_metric_cmd);
install_element(INTERFACE_NODE, &isis_hello_interval_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_interval_cmd);
install_element(INTERFACE_NODE, &isis_hello_multiplier_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_multiplier_cmd);
install_element(INTERFACE_NODE, &csnp_interval_cmd);
install_element(INTERFACE_NODE, &no_csnp_interval_cmd);
install_element(INTERFACE_NODE, &psnp_interval_cmd);
install_element(INTERFACE_NODE, &no_psnp_interval_cmd);
install_element(INTERFACE_NODE, &circuit_topology_cmd);
install_element(INTERFACE_NODE, &no_circuit_topology_cmd);
install_element(ROUTER_NODE, &set_overload_bit_cmd);
install_element(ROUTER_NODE, &no_set_overload_bit_cmd);
install_element(ROUTER_NODE, &area_lsp_mtu_cmd);
install_element(ROUTER_NODE, &no_area_lsp_mtu_cmd);
install_element(ROUTER_NODE, &area_purge_originator_cmd);
install_element(ROUTER_NODE, &lsp_gen_interval_cmd);
install_element(ROUTER_NODE, &no_lsp_gen_interval_cmd);
install_element(ROUTER_NODE, &spf_interval_cmd);
install_element(ROUTER_NODE, &no_spf_interval_cmd);
install_element(ROUTER_NODE, &max_lsp_lifetime_cmd);
install_element(ROUTER_NODE, &no_max_lsp_lifetime_cmd);
install_element(ROUTER_NODE, &lsp_refresh_interval_cmd);
install_element(ROUTER_NODE, &no_lsp_refresh_interval_cmd);
install_element(ROUTER_NODE, &domain_passwd_cmd);
install_element(ROUTER_NODE, &no_domain_passwd_cmd);
install_element(ROUTER_NODE, &spf_delay_ietf_cmd);
install_element(ROUTER_NODE, &no_spf_delay_ietf_cmd);
isis_vty_daemon_init();
}

38
isisd/isis_vty_common.h Normal file
View File

@ -0,0 +1,38 @@
/*
* IS-IS Rout(e)ing protocol - isis_vty_common.h
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
* Copyright (C) 2016 David Lamparter, for NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ISIS_VTY_COMMON_H
#define ISIS_VTY_COMMON_H
struct isis_circuit *isis_circuit_lookup(struct vty *vty);
int isis_vty_max_lsp_lifetime_set(struct vty *vty, int level, uint16_t interval);
int isis_vty_lsp_refresh_set(struct vty *vty, int level, uint16_t interval);
int isis_vty_lsp_gen_interval_set(struct vty *vty, int level, uint16_t interval);
int isis_vty_password_set(struct vty *vty, int argc,
struct cmd_token *argv[], int level);
void isis_vty_daemon_init(void);
void isis_vty_init(void);
#endif

94
isisd/isis_vty_fabricd.c Normal file
View File

@ -0,0 +1,94 @@
/*
* IS-IS Rout(e)ing protocol - isis_vty_fabricd.c
*
* This file contains the CLI that is specific to OpenFabric
*
* Copyright (C) 2018 Christian Franke, for NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "command.h"
#include "isisd.h"
#include "isis_vty_common.h"
#include "fabricd.h"
#include "isis_tlvs.h"
DEFUN (fabric_tier,
fabric_tier_cmd,
"fabric-tier (0-14)",
"Statically configure the tier to advertise\n"
"Tier to advertise\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
uint8_t tier = atoi(argv[1]->arg);
fabricd_configure_tier(area, tier);
return CMD_SUCCESS;
}
DEFUN (no_fabric_tier,
no_fabric_tier_cmd,
"no fabric-tier [(0-14)]",
NO_STR
"Statically configure the tier to advertise\n"
"Tier to advertise\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
fabricd_configure_tier(area, ISIS_TIER_UNDEFINED);
return CMD_SUCCESS;
}
DEFUN (debug_fabric_flooding,
debug_fabric_flooding_cmd,
"debug openfabric flooding",
DEBUG_STR
PROTO_HELP
"Flooding optimization algorithm\n")
{
isis->debugs |= DEBUG_FABRICD_FLOODING;
print_debug(vty, DEBUG_FABRICD_FLOODING, 1);
return CMD_SUCCESS;
}
DEFUN (no_debug_fabric_flooding,
no_debug_fabric_flooding_cmd,
"no debug openfabric flooding",
NO_STR
UNDEBUG_STR
PROTO_HELP
"Flooding optimization algorithm\n")
{
isis->debugs &= ~DEBUG_FABRICD_FLOODING;
print_debug(vty, DEBUG_FABRICD_FLOODING, 0);
return CMD_SUCCESS;
}
void isis_vty_daemon_init(void)
{
install_element(ROUTER_NODE, &fabric_tier_cmd);
install_element(ROUTER_NODE, &no_fabric_tier_cmd);
install_element(ENABLE_NODE, &debug_fabric_flooding_cmd);
install_element(ENABLE_NODE, &no_debug_fabric_flooding_cmd);
install_element(CONFIG_NODE, &debug_fabric_flooding_cmd);
install_element(CONFIG_NODE, &no_debug_fabric_flooding_cmd);
}

858
isisd/isis_vty_isisd.c Normal file
View File

@ -0,0 +1,858 @@
/*
* IS-IS Rout(e)ing protocol - isis_vty_isisd.c
*
* This file contains the CLI that is specific to IS-IS
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
* Copyright (C) 2016 David Lamparter, for NetDEF, Inc.
* Copyright (C) 2018 Christian Franke, for NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* 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; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "command.h"
#include "isis_circuit.h"
#include "isis_csm.h"
#include "isis_misc.h"
#include "isis_mt.h"
#include "isisd.h"
#include "isis_vty_common.h"
static int level_for_arg(const char *arg)
{
if (!strcmp(arg, "level-1"))
return IS_LEVEL_1;
else
return IS_LEVEL_2;
}
DEFUN (isis_circuit_type,
isis_circuit_type_cmd,
"isis circuit-type <level-1|level-1-2|level-2-only>",
"IS-IS routing protocol\n"
"Configure circuit type for interface\n"
"Level-1 only adjacencies are formed\n"
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
int idx_level = 2;
int is_type;
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
is_type = string2circuit_t(argv[idx_level]->arg);
if (!is_type) {
vty_out(vty, "Unknown circuit-type \n");
return CMD_WARNING_CONFIG_FAILED;
}
if (circuit->state == C_STATE_UP
&& circuit->area->is_type != IS_LEVEL_1_AND_2
&& circuit->area->is_type != is_type) {
vty_out(vty, "Invalid circuit level for area %s.\n",
circuit->area->area_tag);
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_is_type_set(circuit, is_type);
return CMD_SUCCESS;
}
DEFUN (no_isis_circuit_type,
no_isis_circuit_type_cmd,
"no isis circuit-type <level-1|level-1-2|level-2-only>",
NO_STR
"IS-IS routing protocol\n"
"Configure circuit type for interface\n"
"Level-1 only adjacencies are formed\n"
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
int is_type;
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
/*
* Set the circuits level to its default value
*/
if (circuit->state == C_STATE_UP)
is_type = circuit->area->is_type;
else
is_type = IS_LEVEL_1_AND_2;
isis_circuit_is_type_set(circuit, is_type);
return CMD_SUCCESS;
}
DEFUN (isis_network,
isis_network_cmd,
"isis network point-to-point",
"IS-IS routing protocol\n"
"Set network type\n"
"point-to-point network type\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) {
vty_out(vty,
"isis network point-to-point is valid only on broadcast interfaces\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
DEFUN (no_isis_network,
no_isis_network_cmd,
"no isis network point-to-point",
NO_STR
"IS-IS routing protocol\n"
"Set network type for circuit\n"
"point-to-point network type\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) {
vty_out(vty,
"isis network point-to-point is valid only on broadcast interfaces\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
DEFUN (isis_priority,
isis_priority_cmd,
"isis priority (0-127)",
"IS-IS routing protocol\n"
"Set priority for Designated Router election\n"
"Priority value\n")
{
uint8_t prio = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->priority[0] = prio;
circuit->priority[1] = prio;
return CMD_SUCCESS;
}
DEFUN (no_isis_priority,
no_isis_priority_cmd,
"no isis priority [(0-127)]",
NO_STR
"IS-IS routing protocol\n"
"Set priority for Designated Router election\n"
"Priority value\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->priority[0] = DEFAULT_PRIORITY;
circuit->priority[1] = DEFAULT_PRIORITY;
return CMD_SUCCESS;
}
DEFUN (isis_priority_level,
isis_priority_level_cmd,
"isis priority (0-127) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set priority for Designated Router election\n"
"Priority value\n"
"Specify priority for level-1 routing\n"
"Specify priority for level-2 routing\n")
{
uint8_t prio = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->priority[level_for_arg(argv[3]->text)] = prio;
return CMD_SUCCESS;
}
DEFUN (no_isis_priority_level,
no_isis_priority_level_cmd,
"no isis priority [(0-127)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set priority for Designated Router election\n"
"Priority value\n"
"Specify priority for level-1 routing\n"
"Specify priority for level-2 routing\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->priority[level] = DEFAULT_PRIORITY;
return CMD_SUCCESS;
}
DEFUN (isis_metric_level,
isis_metric_level_cmd,
"isis metric (0-16777215) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set default metric for circuit\n"
"Default metric value\n"
"Specify metric for level-1 routing\n"
"Specify metric for level-2 routing\n")
{
uint32_t met = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_metric_set(circuit,
level_for_arg(argv[3]->text),
met),
"Failed to set metric: $ERR");
return CMD_SUCCESS;
}
DEFUN (no_isis_metric_level,
no_isis_metric_level_cmd,
"no isis metric [(0-16777215)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set default metric for circuit\n"
"Default metric value\n"
"Specify metric for level-1 routing\n"
"Specify metric for level-2 routing\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
CMD_FERR_RETURN(isis_circuit_metric_set(circuit, level,
DEFAULT_CIRCUIT_METRIC),
"Failed to set L1 metric: $ERR");
return CMD_SUCCESS;
}
DEFUN (isis_hello_interval_level,
isis_hello_interval_level_cmd,
"isis hello-interval (1-600) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set Hello interval\n"
"Holdtime 1 second, interval depends on multiplier\n"
"Specify hello-interval for level-1 IIHs\n"
"Specify hello-interval for level-2 IIHs\n")
{
uint32_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_interval[level_for_arg(argv[3]->text)] = interval;
return CMD_SUCCESS;
}
DEFUN (no_isis_hello_interval_level,
no_isis_hello_interval_level_cmd,
"no isis hello-interval [(1-600)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set Hello interval\n"
"Holdtime 1 second, interval depends on multiplier\n"
"Specify hello-interval for level-1 IIHs\n"
"Specify hello-interval for level-2 IIHs\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_interval[level] = DEFAULT_HELLO_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (isis_hello_multiplier_level,
isis_hello_multiplier_level_cmd,
"isis hello-multiplier (2-100) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n"
"Specify hello multiplier for level-1 IIHs\n"
"Specify hello multiplier for level-2 IIHs\n")
{
uint16_t mult = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_multiplier[level_for_arg(argv[3]->text)] = mult;
return CMD_SUCCESS;
}
DEFUN (no_isis_hello_multiplier_level,
no_isis_hello_multiplier_level_cmd,
"no isis hello-multiplier [(2-100)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n"
"Specify hello multiplier for level-1 IIHs\n"
"Specify hello multiplier for level-2 IIHs\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->hello_multiplier[level] = DEFAULT_HELLO_MULTIPLIER;
return CMD_SUCCESS;
}
DEFUN (isis_threeway_adj,
isis_threeway_adj_cmd,
"[no] isis three-way-handshake",
NO_STR
"IS-IS commands\n"
"Enable/Disable three-way handshake\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->disable_threeway_adj = !strcmp(argv[0]->text, "no");
return CMD_SUCCESS;
}
DEFUN (isis_hello_padding,
isis_hello_padding_cmd,
"isis hello padding",
"IS-IS routing protocol\n"
"Add padding to IS-IS hello packets\n"
"Pad hello packets\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->pad_hellos = 1;
return CMD_SUCCESS;
}
DEFUN (no_isis_hello_padding,
no_isis_hello_padding_cmd,
"no isis hello padding",
NO_STR
"IS-IS routing protocol\n"
"Add padding to IS-IS hello packets\n"
"Pad hello packets\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->pad_hellos = 0;
return CMD_SUCCESS;
}
DEFUN (csnp_interval_level,
csnp_interval_level_cmd,
"isis csnp-interval (1-600) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n"
"Specify interval for level-1 CSNPs\n"
"Specify interval for level-2 CSNPs\n")
{
uint16_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->csnp_interval[level_for_arg(argv[3]->text)] = interval;
return CMD_SUCCESS;
}
DEFUN (no_csnp_interval_level,
no_csnp_interval_level_cmd,
"no isis csnp-interval [(1-600)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n"
"Specify interval for level-1 CSNPs\n"
"Specify interval for level-2 CSNPs\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->csnp_interval[level] = DEFAULT_CSNP_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (psnp_interval_level,
psnp_interval_level_cmd,
"isis psnp-interval (1-120) <level-1|level-2>",
"IS-IS routing protocol\n"
"Set PSNP interval in seconds\n"
"PSNP interval value\n"
"Specify interval for level-1 PSNPs\n"
"Specify interval for level-2 PSNPs\n")
{
uint16_t interval = atoi(argv[2]->arg);
struct isis_circuit *circuit = isis_circuit_lookup(vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->psnp_interval[level_for_arg(argv[3]->text)] = (uint16_t)interval;
return CMD_SUCCESS;
}
DEFUN (no_psnp_interval_level,
no_psnp_interval_level_cmd,
"no isis psnp-interval [(1-120)] <level-1|level-2>",
NO_STR
"IS-IS routing protocol\n"
"Set PSNP interval in seconds\n"
"PSNP interval value\n"
"Specify interval for level-1 PSNPs\n"
"Specify interval for level-2 PSNPs\n")
{
struct isis_circuit *circuit = isis_circuit_lookup(vty);
int level = level_for_arg(argv[argc - 1]->text);
if (!circuit)
return CMD_ERR_NO_MATCH;
circuit->psnp_interval[level] = DEFAULT_PSNP_INTERVAL;
return CMD_SUCCESS;
}
static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area)
{
struct isis_circuit *circuit;
struct listnode *node;
if (!vty)
return CMD_WARNING_CONFIG_FAILED;
if (!area) {
vty_out(vty, "ISIS area is invalid\n");
return CMD_WARNING_CONFIG_FAILED;
}
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if ((area->is_type & IS_LEVEL_1)
&& (circuit->is_type & IS_LEVEL_1)
&& (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) {
vty_out(vty, "ISIS circuit %s metric is invalid\n",
circuit->interface->name);
return CMD_WARNING_CONFIG_FAILED;
}
if ((area->is_type & IS_LEVEL_2)
&& (circuit->is_type & IS_LEVEL_2)
&& (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) {
vty_out(vty, "ISIS circuit %s metric is invalid\n",
circuit->interface->name);
return CMD_WARNING_CONFIG_FAILED;
}
}
return CMD_SUCCESS;
}
DEFUN (metric_style,
metric_style_cmd,
"metric-style <narrow|transition|wide>",
"Use old-style (ISO 10589) or new-style packet formats\n"
"Use old style of TLVs with narrow metric\n"
"Send and accept both styles of TLVs during transition\n"
"Use new style of TLVs to carry wider metric\n")
{
int idx_metric_style = 1;
VTY_DECLVAR_CONTEXT(isis_area, area);
int ret;
if (strncmp(argv[idx_metric_style]->arg, "w", 1) == 0) {
isis_area_metricstyle_set(area, false, true);
return CMD_SUCCESS;
}
if (area_is_mt(area)) {
vty_out(vty,
"Narrow metrics cannot be used while multi topology IS-IS is active\n");
return CMD_WARNING_CONFIG_FAILED;
}
ret = validate_metric_style_narrow(vty, area);
if (ret != CMD_SUCCESS)
return ret;
if (strncmp(argv[idx_metric_style]->arg, "t", 1) == 0)
isis_area_metricstyle_set(area, true, true);
else if (strncmp(argv[idx_metric_style]->arg, "n", 1) == 0)
isis_area_metricstyle_set(area, true, false);
return CMD_SUCCESS;
return CMD_SUCCESS;
}
DEFUN (no_metric_style,
no_metric_style_cmd,
"no metric-style",
NO_STR
"Use old-style (ISO 10589) or new-style packet formats\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int ret;
if (area_is_mt(area)) {
vty_out(vty,
"Narrow metrics cannot be used while multi topology IS-IS is active\n");
return CMD_WARNING_CONFIG_FAILED;
}
ret = validate_metric_style_narrow(vty, area);
if (ret != CMD_SUCCESS)
return ret;
isis_area_metricstyle_set(area, true, false);
return CMD_SUCCESS;
}
DEFUN (set_attached_bit,
set_attached_bit_cmd,
"set-attached-bit",
"Set attached bit to identify as L1/L2 router for inter-area traffic\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_attached_bit_set(area, true);
return CMD_SUCCESS;
}
DEFUN (no_set_attached_bit,
no_set_attached_bit_cmd,
"no set-attached-bit",
NO_STR
"Reset attached bit\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_attached_bit_set(area, false);
return CMD_SUCCESS;
}
DEFUN (dynamic_hostname,
dynamic_hostname_cmd,
"hostname dynamic",
"Dynamic hostname for IS-IS\n"
"Dynamic hostname\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_dynhostname_set(area, true);
return CMD_SUCCESS;
}
DEFUN (no_dynamic_hostname,
no_dynamic_hostname_cmd,
"no hostname dynamic",
NO_STR
"Dynamic hostname for IS-IS\n"
"Dynamic hostname\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
isis_area_dynhostname_set(area, false);
return CMD_SUCCESS;
}
DEFUN (is_type,
is_type_cmd,
"is-type <level-1|level-1-2|level-2-only>",
"IS Level for this routing process (OSI only)\n"
"Act as a station router only\n"
"Act as both a station router and an area router\n"
"Act as an area router only\n")
{
int idx_level = 1;
VTY_DECLVAR_CONTEXT(isis_area, area);
int type;
type = string2circuit_t(argv[idx_level]->arg);
if (!type) {
vty_out(vty, "Unknown IS level \n");
return CMD_SUCCESS;
}
isis_area_is_type_set(area, type);
return CMD_SUCCESS;
}
DEFUN (no_is_type,
no_is_type_cmd,
"no is-type <level-1|level-1-2|level-2-only>",
NO_STR
"IS Level for this routing process (OSI only)\n"
"Act as a station router only\n"
"Act as both a station router and an area router\n"
"Act as an area router only\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int type;
/*
* Put the is-type back to defaults:
* - level-1-2 on first area
* - level-1 for the rest
*/
if (listgetdata(listhead(isis->area_list)) == area)
type = IS_LEVEL_1_AND_2;
else
type = IS_LEVEL_1;
isis_area_is_type_set(area, type);
return CMD_SUCCESS;
}
DEFUN (lsp_gen_interval_level,
lsp_gen_interval_level_cmd,
"lsp-gen-interval <level-1|level-2> (1-120)",
"Minimum interval between regenerating same LSP\n"
"Set interval for level 1 only\n"
"Set interval for level 2 only\n"
"Minimum interval in seconds\n")
{
uint16_t interval = atoi(argv[2]->arg);
return isis_vty_lsp_gen_interval_set(vty, level_for_arg(argv[1]->text),
interval);
}
DEFUN (no_lsp_gen_interval_level,
no_lsp_gen_interval_level_cmd,
"no lsp-gen-interval <level-1|level-2> [(1-120)]",
NO_STR
"Minimum interval between regenerating same LSP\n"
"Set interval for level 1 only\n"
"Set interval for level 2 only\n"
"Minimum interval in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
return isis_vty_lsp_gen_interval_set(vty, level_for_arg(argv[2]->text),
DEFAULT_MIN_LSP_GEN_INTERVAL);
}
DEFUN (max_lsp_lifetime_level,
max_lsp_lifetime_level_cmd,
"max-lsp-lifetime <level-1|level-2> (350-65535)",
"Maximum LSP lifetime\n"
"Maximum LSP lifetime for Level 1 only\n"
"Maximum LSP lifetime for Level 2 only\n"
"LSP lifetime in seconds\n")
{
uint16_t lifetime = atoi(argv[2]->arg);
return isis_vty_max_lsp_lifetime_set(vty, level_for_arg(argv[1]->text),
lifetime);
}
DEFUN (no_max_lsp_lifetime_level,
no_max_lsp_lifetime_level_cmd,
"no max-lsp-lifetime <level-1|level-2> [(350-65535)]",
NO_STR
"Maximum LSP lifetime\n"
"Maximum LSP lifetime for Level 1 only\n"
"Maximum LSP lifetime for Level 2 only\n"
"LSP lifetime in seconds\n")
{
return isis_vty_max_lsp_lifetime_set(vty, level_for_arg(argv[1]->text),
DEFAULT_LSP_LIFETIME);
}
DEFUN (spf_interval_level,
spf_interval_level_cmd,
"spf-interval <level-1|level-2> (1-120)",
"Minimum interval between SPF calculations\n"
"Set interval for level 1 only\n"
"Set interval for level 2 only\n"
"Minimum interval between consecutive SPFs in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
uint16_t interval = atoi(argv[2]->arg);
area->min_spf_interval[level_for_arg(argv[1]->text)] = interval;
return CMD_SUCCESS;
}
DEFUN (no_spf_interval_level,
no_spf_interval_level_cmd,
"no spf-interval <level-1|level-2> [(1-120)]",
NO_STR
"Minimum interval between SPF calculations\n"
"Set interval for level 1 only\n"
"Set interval for level 2 only\n"
"Minimum interval between consecutive SPFs in seconds\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
int level = level_for_arg(argv[1]->text);
area->min_spf_interval[level] = MINIMUM_SPF_INTERVAL;
return CMD_SUCCESS;
}
DEFUN (lsp_refresh_interval_level,
lsp_refresh_interval_level_cmd,
"lsp-refresh-interval <level-1|level-2> (1-65235)",
"LSP refresh interval\n"
"LSP refresh interval for Level 1 only\n"
"LSP refresh interval for Level 2 only\n"
"LSP refresh interval in seconds\n")
{
uint16_t interval = atoi(argv[2]->arg);
return isis_vty_lsp_refresh_set(vty, level_for_arg(argv[1]->text),
interval);
}
DEFUN (no_lsp_refresh_interval_level,
no_lsp_refresh_interval_level_cmd,
"no lsp-refresh-interval <level-1|level-2> [(1-65235)]",
NO_STR
"LSP refresh interval\n"
"LSP refresh interval for Level 1 only\n"
"LSP refresh interval for Level 2 only\n"
"LSP refresh interval in seconds\n")
{
return isis_vty_lsp_refresh_set(vty, level_for_arg(argv[2]->text),
DEFAULT_MAX_LSP_GEN_INTERVAL);
}
DEFUN (area_passwd,
area_passwd_cmd,
"area-password <clear|md5> WORD [authenticate snp <send-only|validate>]",
"Configure the authentication password for an area\n"
"Authentication type\n"
"Authentication type\n"
"Area password\n"
"Authentication\n"
"SNP PDUs\n"
"Send but do not check PDUs on receiving\n"
"Send and check PDUs on receiving\n")
{
return isis_vty_password_set(vty, argc, argv, IS_LEVEL_1);
}
DEFUN (no_area_passwd,
no_area_passwd_cmd,
"no area-password",
NO_STR
"Configure the authentication password for an area\n")
{
VTY_DECLVAR_CONTEXT(isis_area, area);
return isis_area_passwd_unset(area, IS_LEVEL_1);
}
void isis_vty_daemon_init(void)
{
install_element(INTERFACE_NODE, &isis_circuit_type_cmd);
install_element(INTERFACE_NODE, &no_isis_circuit_type_cmd);
install_element(INTERFACE_NODE, &isis_network_cmd);
install_element(INTERFACE_NODE, &no_isis_network_cmd);
install_element(INTERFACE_NODE, &isis_priority_cmd);
install_element(INTERFACE_NODE, &no_isis_priority_cmd);
install_element(INTERFACE_NODE, &isis_priority_level_cmd);
install_element(INTERFACE_NODE, &no_isis_priority_level_cmd);
install_element(INTERFACE_NODE, &isis_metric_level_cmd);
install_element(INTERFACE_NODE, &no_isis_metric_level_cmd);
install_element(INTERFACE_NODE, &isis_hello_interval_level_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_interval_level_cmd);
install_element(INTERFACE_NODE, &isis_hello_multiplier_level_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_multiplier_level_cmd);
install_element(INTERFACE_NODE, &isis_threeway_adj_cmd);
install_element(INTERFACE_NODE, &isis_hello_padding_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_padding_cmd);
install_element(INTERFACE_NODE, &csnp_interval_level_cmd);
install_element(INTERFACE_NODE, &no_csnp_interval_level_cmd);
install_element(INTERFACE_NODE, &psnp_interval_level_cmd);
install_element(INTERFACE_NODE, &no_psnp_interval_level_cmd);
install_element(ROUTER_NODE, &metric_style_cmd);
install_element(ROUTER_NODE, &no_metric_style_cmd);
install_element(ROUTER_NODE, &set_attached_bit_cmd);
install_element(ROUTER_NODE, &no_set_attached_bit_cmd);
install_element(ROUTER_NODE, &dynamic_hostname_cmd);
install_element(ROUTER_NODE, &no_dynamic_hostname_cmd);
install_element(ROUTER_NODE, &is_type_cmd);
install_element(ROUTER_NODE, &no_is_type_cmd);
install_element(ROUTER_NODE, &lsp_gen_interval_level_cmd);
install_element(ROUTER_NODE, &no_lsp_gen_interval_level_cmd);
install_element(ROUTER_NODE, &max_lsp_lifetime_level_cmd);
install_element(ROUTER_NODE, &no_max_lsp_lifetime_level_cmd);
install_element(ROUTER_NODE, &spf_interval_level_cmd);
install_element(ROUTER_NODE, &no_spf_interval_level_cmd);
install_element(ROUTER_NODE, &lsp_refresh_interval_level_cmd);
install_element(ROUTER_NODE, &no_lsp_refresh_interval_level_cmd);
install_element(ROUTER_NODE, &area_passwd_cmd);
install_element(ROUTER_NODE, &no_area_passwd_cmd);
}

View File

@ -261,8 +261,10 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
return;
memset(&api, 0, sizeof(api));
if (fabricd)
api.flags |= ZEBRA_FLAG_ONLINK;
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.type = PROTO_TYPE;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
if (src_p && src_p->prefixlen) {
@ -337,7 +339,7 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.type = PROTO_TYPE;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
if (src_p && src_p->prefixlen) {
@ -378,7 +380,7 @@ static int isis_zebra_read(int command, struct zclient *zclient,
*/
if (api.prefix.prefixlen == 0
&& api.src_prefix.prefixlen == 0
&& api.type == ZEBRA_ROUTE_ISIS) {
&& api.type == PROTO_TYPE) {
command = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
}
@ -424,7 +426,7 @@ static void isis_zebra_connected(struct zclient *zclient)
void isis_zebra_init(struct thread_master *master)
{
zclient = zclient_new_notify(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_ISIS, 0, &isisd_privs);
zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
zclient->zebra_connected = isis_zebra_connected;
zclient->router_id_update = isis_router_id_update_zebra;
zclient->interface_add = isis_zebra_if_add;

View File

@ -56,6 +56,7 @@
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/fabricd.h"
struct isis *isis = NULL;
@ -95,6 +96,7 @@ void isis_new(unsigned long process_id)
*/
/* isis->debugs = 0xFFFF; */
isisMplsTE.status = disable; /* Only support TE metric */
QOBJ_REG(isis, isis);
}
@ -105,10 +107,13 @@ struct isis_area *isis_area_create(const char *area_tag)
area = XCALLOC(MTYPE_ISIS_AREA, sizeof(struct isis_area));
/*
* The first instance is level-1-2 rest are level-1, unless otherwise
* configured
* Fabricd runs only as level-2.
* For IS-IS, the first instance is level-1-2 rest are level-1,
* unless otherwise configured
*/
if (listcount(isis->area_list) > 0)
if (fabricd) {
area->is_type = IS_LEVEL_2;
} else if (listcount(isis->area_list) > 0)
area->is_type = IS_LEVEL_1;
else
area->is_type = IS_LEVEL_1_AND_2;
@ -153,6 +158,8 @@ struct isis_area *isis_area_create(const char *area_tag)
listnode_add(isis->area_list, area);
area->isis = isis;
if (fabricd)
area->fabricd = fabricd_new(area);
QOBJ_REG(area, isis_area);
return area;
@ -179,7 +186,7 @@ int isis_area_get(struct vty *vty, const char *area_tag)
area = isis_area_lookup(area_tag);
if (area) {
VTY_PUSH_CONTEXT(ISIS_NODE, area);
VTY_PUSH_CONTEXT(ROUTER_NODE, area);
return CMD_SUCCESS;
}
@ -188,7 +195,7 @@ int isis_area_get(struct vty *vty, const char *area_tag)
if (isis->debugs & DEBUG_EVENTS)
zlog_debug("New IS-IS area instance %s", area->area_tag);
VTY_PUSH_CONTEXT(ISIS_NODE, area);
VTY_PUSH_CONTEXT(ROUTER_NODE, area);
return CMD_SUCCESS;
}
@ -209,6 +216,9 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)
QOBJ_UNREG(area);
if (fabricd)
fabricd_finish(area->fabricd);
if (area->circuit_list) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) {
@ -463,9 +473,9 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail)
DEFUN (show_isis_interface,
show_isis_interface_cmd,
"show isis interface",
"show " PROTO_NAME " interface",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS interface\n")
{
return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF);
@ -473,9 +483,9 @@ DEFUN (show_isis_interface,
DEFUN (show_isis_interface_detail,
show_isis_interface_detail_cmd,
"show isis interface detail",
"show " PROTO_NAME " interface detail",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS interface\n"
"show detailed information\n")
{
@ -484,9 +494,9 @@ DEFUN (show_isis_interface_detail,
DEFUN (show_isis_interface_arg,
show_isis_interface_arg_cmd,
"show isis interface WORD",
"show " PROTO_NAME " interface WORD",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS interface\n"
"ISIS interface name\n")
{
@ -634,9 +644,9 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id)
DEFUN (show_isis_neighbor,
show_isis_neighbor_cmd,
"show isis neighbor",
"show " PROTO_NAME " neighbor",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS neighbor adjacencies\n")
{
return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF);
@ -644,9 +654,9 @@ DEFUN (show_isis_neighbor,
DEFUN (show_isis_neighbor_detail,
show_isis_neighbor_detail_cmd,
"show isis neighbor detail",
"show " PROTO_NAME " neighbor detail",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS neighbor adjacencies\n"
"show detailed information\n")
{
@ -655,9 +665,9 @@ DEFUN (show_isis_neighbor_detail,
DEFUN (show_isis_neighbor_arg,
show_isis_neighbor_arg_cmd,
"show isis neighbor WORD",
"show " PROTO_NAME " neighbor WORD",
SHOW_STR
"ISIS network information\n"
PROTO_HELP
"ISIS neighbor adjacencies\n"
"System id\n")
{
@ -668,19 +678,19 @@ DEFUN (show_isis_neighbor_arg,
DEFUN (clear_isis_neighbor,
clear_isis_neighbor_cmd,
"clear isis neighbor",
"clear " PROTO_NAME " neighbor",
CLEAR_STR
"Reset ISIS network information\n"
"Reset ISIS neighbor adjacencies\n")
PROTO_HELP
"ISIS neighbor adjacencies\n")
{
return clear_isis_neighbor_common(vty, NULL);
}
DEFUN (clear_isis_neighbor_arg,
clear_isis_neighbor_arg_cmd,
"clear isis neighbor WORD",
"clear " PROTO_NAME " neighbor WORD",
CLEAR_STR
"ISIS network information\n"
PROTO_HELP
"ISIS neighbor adjacencies\n"
"System id\n")
{
@ -734,16 +744,18 @@ void print_debug(struct vty *vty, int flags, int onoff)
vty_out(vty, "IS-IS LSP generation debugging is %s\n", onoffs);
if (flags & DEBUG_LSP_SCHED)
vty_out(vty, "IS-IS LSP scheduling debugging is %s\n", onoffs);
if (flags & DEBUG_FABRICD_FLOODING)
vty_out(vty, "OpenFabric Flooding debugging is %s\n", onoffs);
}
DEFUN_NOSH (show_debugging,
show_debugging_isis_cmd,
"show debugging [isis]",
"show debugging [" PROTO_NAME "]",
SHOW_STR
"State of each debugging option\n"
ISIS_STR)
PROTO_HELP)
{
vty_out(vty, "IS-IS debugging status:\n");
vty_out(vty, PROTO_NAME " debugging status:\n");
if (isis->debugs)
print_debug(vty, isis->debugs, 1);
@ -760,59 +772,63 @@ static int config_write_debug(struct vty *vty)
int flags = isis->debugs;
if (flags & DEBUG_ADJ_PACKETS) {
vty_out(vty, "debug isis adj-packets\n");
vty_out(vty, "debug " PROTO_NAME " adj-packets\n");
write++;
}
if (flags & DEBUG_CHECKSUM_ERRORS) {
vty_out(vty, "debug isis checksum-errors\n");
vty_out(vty, "debug " PROTO_NAME " checksum-errors\n");
write++;
}
if (flags & DEBUG_LOCAL_UPDATES) {
vty_out(vty, "debug isis local-updates\n");
vty_out(vty, "debug " PROTO_NAME " local-updates\n");
write++;
}
if (flags & DEBUG_PROTOCOL_ERRORS) {
vty_out(vty, "debug isis protocol-errors\n");
vty_out(vty, "debug " PROTO_NAME " protocol-errors\n");
write++;
}
if (flags & DEBUG_SNP_PACKETS) {
vty_out(vty, "debug isis snp-packets\n");
vty_out(vty, "debug " PROTO_NAME " snp-packets\n");
write++;
}
if (flags & DEBUG_SPF_EVENTS) {
vty_out(vty, "debug isis spf-events\n");
vty_out(vty, "debug " PROTO_NAME " spf-events\n");
write++;
}
if (flags & DEBUG_SPF_STATS) {
vty_out(vty, "debug isis spf-statistics\n");
vty_out(vty, "debug " PROTO_NAME " spf-statistics\n");
write++;
}
if (flags & DEBUG_SPF_TRIGGERS) {
vty_out(vty, "debug isis spf-triggers\n");
vty_out(vty, "debug " PROTO_NAME " spf-triggers\n");
write++;
}
if (flags & DEBUG_UPDATE_PACKETS) {
vty_out(vty, "debug isis update-packets\n");
vty_out(vty, "debug " PROTO_NAME " update-packets\n");
write++;
}
if (flags & DEBUG_RTE_EVENTS) {
vty_out(vty, "debug isis route-events\n");
vty_out(vty, "debug " PROTO_NAME " route-events\n");
write++;
}
if (flags & DEBUG_EVENTS) {
vty_out(vty, "debug isis events\n");
vty_out(vty, "debug " PROTO_NAME " events\n");
write++;
}
if (flags & DEBUG_PACKET_DUMP) {
vty_out(vty, "debug isis packet-dump\n");
vty_out(vty, "debug " PROTO_NAME " packet-dump\n");
write++;
}
if (flags & DEBUG_LSP_GEN) {
vty_out(vty, "debug isis lsp-gen\n");
vty_out(vty, "debug " PROTO_NAME " lsp-gen\n");
write++;
}
if (flags & DEBUG_LSP_SCHED) {
vty_out(vty, "debug isis lsp-sched\n");
vty_out(vty, "debug " PROTO_NAME " lsp-sched\n");
write++;
}
if (flags & DEBUG_FABRICD_FLOODING) {
vty_out(vty, "debug " PROTO_NAME " flooding\n");
write++;
}
write += spf_backoff_write_config(vty);
@ -822,9 +838,9 @@ static int config_write_debug(struct vty *vty)
DEFUN (debug_isis_adj,
debug_isis_adj_cmd,
"debug isis adj-packets",
"debug " PROTO_NAME " adj-packets",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Adjacency related packets\n")
{
isis->debugs |= DEBUG_ADJ_PACKETS;
@ -835,10 +851,10 @@ DEFUN (debug_isis_adj,
DEFUN (no_debug_isis_adj,
no_debug_isis_adj_cmd,
"no debug isis adj-packets",
"no debug " PROTO_NAME " adj-packets",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Adjacency related packets\n")
{
isis->debugs &= ~DEBUG_ADJ_PACKETS;
@ -849,9 +865,9 @@ DEFUN (no_debug_isis_adj,
DEFUN (debug_isis_csum,
debug_isis_csum_cmd,
"debug isis checksum-errors",
"debug " PROTO_NAME " checksum-errors",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS LSP checksum errors\n")
{
isis->debugs |= DEBUG_CHECKSUM_ERRORS;
@ -862,10 +878,10 @@ DEFUN (debug_isis_csum,
DEFUN (no_debug_isis_csum,
no_debug_isis_csum_cmd,
"no debug isis checksum-errors",
"no debug " PROTO_NAME " checksum-errors",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS LSP checksum errors\n")
{
isis->debugs &= ~DEBUG_CHECKSUM_ERRORS;
@ -876,9 +892,9 @@ DEFUN (no_debug_isis_csum,
DEFUN (debug_isis_lupd,
debug_isis_lupd_cmd,
"debug isis local-updates",
"debug " PROTO_NAME " local-updates",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS local update packets\n")
{
isis->debugs |= DEBUG_LOCAL_UPDATES;
@ -889,10 +905,10 @@ DEFUN (debug_isis_lupd,
DEFUN (no_debug_isis_lupd,
no_debug_isis_lupd_cmd,
"no debug isis local-updates",
"no debug " PROTO_NAME " local-updates",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS local update packets\n")
{
isis->debugs &= ~DEBUG_LOCAL_UPDATES;
@ -903,9 +919,9 @@ DEFUN (no_debug_isis_lupd,
DEFUN (debug_isis_err,
debug_isis_err_cmd,
"debug isis protocol-errors",
"debug " PROTO_NAME " protocol-errors",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS LSP protocol errors\n")
{
isis->debugs |= DEBUG_PROTOCOL_ERRORS;
@ -916,10 +932,10 @@ DEFUN (debug_isis_err,
DEFUN (no_debug_isis_err,
no_debug_isis_err_cmd,
"no debug isis protocol-errors",
"no debug " PROTO_NAME " protocol-errors",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS LSP protocol errors\n")
{
isis->debugs &= ~DEBUG_PROTOCOL_ERRORS;
@ -930,9 +946,9 @@ DEFUN (no_debug_isis_err,
DEFUN (debug_isis_snp,
debug_isis_snp_cmd,
"debug isis snp-packets",
"debug " PROTO_NAME " snp-packets",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS CSNP/PSNP packets\n")
{
isis->debugs |= DEBUG_SNP_PACKETS;
@ -943,10 +959,10 @@ DEFUN (debug_isis_snp,
DEFUN (no_debug_isis_snp,
no_debug_isis_snp_cmd,
"no debug isis snp-packets",
"no debug " PROTO_NAME " snp-packets",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS CSNP/PSNP packets\n")
{
isis->debugs &= ~DEBUG_SNP_PACKETS;
@ -957,9 +973,9 @@ DEFUN (no_debug_isis_snp,
DEFUN (debug_isis_upd,
debug_isis_upd_cmd,
"debug isis update-packets",
"debug " PROTO_NAME " update-packets",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Update related packets\n")
{
isis->debugs |= DEBUG_UPDATE_PACKETS;
@ -970,10 +986,10 @@ DEFUN (debug_isis_upd,
DEFUN (no_debug_isis_upd,
no_debug_isis_upd_cmd,
"no debug isis update-packets",
"no debug " PROTO_NAME " update-packets",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Update related packets\n")
{
isis->debugs &= ~DEBUG_UPDATE_PACKETS;
@ -984,9 +1000,9 @@ DEFUN (no_debug_isis_upd,
DEFUN (debug_isis_spfevents,
debug_isis_spfevents_cmd,
"debug isis spf-events",
"debug " PROTO_NAME " spf-events",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Shortest Path First Events\n")
{
isis->debugs |= DEBUG_SPF_EVENTS;
@ -997,10 +1013,10 @@ DEFUN (debug_isis_spfevents,
DEFUN (no_debug_isis_spfevents,
no_debug_isis_spfevents_cmd,
"no debug isis spf-events",
"no debug " PROTO_NAME " spf-events",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Shortest Path First Events\n")
{
isis->debugs &= ~DEBUG_SPF_EVENTS;
@ -1011,9 +1027,9 @@ DEFUN (no_debug_isis_spfevents,
DEFUN (debug_isis_spfstats,
debug_isis_spfstats_cmd,
"debug isis spf-statistics ",
"debug " PROTO_NAME " spf-statistics ",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS SPF Timing and Statistic Data\n")
{
isis->debugs |= DEBUG_SPF_STATS;
@ -1024,10 +1040,10 @@ DEFUN (debug_isis_spfstats,
DEFUN (no_debug_isis_spfstats,
no_debug_isis_spfstats_cmd,
"no debug isis spf-statistics",
"no debug " PROTO_NAME " spf-statistics",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS SPF Timing and Statistic Data\n")
{
isis->debugs &= ~DEBUG_SPF_STATS;
@ -1038,9 +1054,9 @@ DEFUN (no_debug_isis_spfstats,
DEFUN (debug_isis_spftrigg,
debug_isis_spftrigg_cmd,
"debug isis spf-triggers",
"debug " PROTO_NAME " spf-triggers",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS SPF triggering events\n")
{
isis->debugs |= DEBUG_SPF_TRIGGERS;
@ -1051,10 +1067,10 @@ DEFUN (debug_isis_spftrigg,
DEFUN (no_debug_isis_spftrigg,
no_debug_isis_spftrigg_cmd,
"no debug isis spf-triggers",
"no debug " PROTO_NAME " spf-triggers",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS SPF triggering events\n")
{
isis->debugs &= ~DEBUG_SPF_TRIGGERS;
@ -1065,9 +1081,9 @@ DEFUN (no_debug_isis_spftrigg,
DEFUN (debug_isis_rtevents,
debug_isis_rtevents_cmd,
"debug isis route-events",
"debug " PROTO_NAME " route-events",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Route related events\n")
{
isis->debugs |= DEBUG_RTE_EVENTS;
@ -1078,10 +1094,10 @@ DEFUN (debug_isis_rtevents,
DEFUN (no_debug_isis_rtevents,
no_debug_isis_rtevents_cmd,
"no debug isis route-events",
"no debug " PROTO_NAME " route-events",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Route related events\n")
{
isis->debugs &= ~DEBUG_RTE_EVENTS;
@ -1092,9 +1108,9 @@ DEFUN (no_debug_isis_rtevents,
DEFUN (debug_isis_events,
debug_isis_events_cmd,
"debug isis events",
"debug " PROTO_NAME " events",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Events\n")
{
isis->debugs |= DEBUG_EVENTS;
@ -1105,10 +1121,10 @@ DEFUN (debug_isis_events,
DEFUN (no_debug_isis_events,
no_debug_isis_events_cmd,
"no debug isis events",
"no debug " PROTO_NAME " events",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Events\n")
{
isis->debugs &= ~DEBUG_EVENTS;
@ -1119,9 +1135,9 @@ DEFUN (no_debug_isis_events,
DEFUN (debug_isis_packet_dump,
debug_isis_packet_dump_cmd,
"debug isis packet-dump",
"debug " PROTO_NAME " packet-dump",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS packet dump\n")
{
isis->debugs |= DEBUG_PACKET_DUMP;
@ -1132,10 +1148,10 @@ DEFUN (debug_isis_packet_dump,
DEFUN (no_debug_isis_packet_dump,
no_debug_isis_packet_dump_cmd,
"no debug isis packet-dump",
"no debug " PROTO_NAME " packet-dump",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS packet dump\n")
{
isis->debugs &= ~DEBUG_PACKET_DUMP;
@ -1146,9 +1162,9 @@ DEFUN (no_debug_isis_packet_dump,
DEFUN (debug_isis_lsp_gen,
debug_isis_lsp_gen_cmd,
"debug isis lsp-gen",
"debug " PROTO_NAME " lsp-gen",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS generation of own LSPs\n")
{
isis->debugs |= DEBUG_LSP_GEN;
@ -1159,10 +1175,10 @@ DEFUN (debug_isis_lsp_gen,
DEFUN (no_debug_isis_lsp_gen,
no_debug_isis_lsp_gen_cmd,
"no debug isis lsp-gen",
"no debug " PROTO_NAME " lsp-gen",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS generation of own LSPs\n")
{
isis->debugs &= ~DEBUG_LSP_GEN;
@ -1173,9 +1189,9 @@ DEFUN (no_debug_isis_lsp_gen,
DEFUN (debug_isis_lsp_sched,
debug_isis_lsp_sched_cmd,
"debug isis lsp-sched",
"debug " PROTO_NAME " lsp-sched",
DEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS scheduling of LSP generation\n")
{
isis->debugs |= DEBUG_LSP_SCHED;
@ -1186,10 +1202,10 @@ DEFUN (debug_isis_lsp_sched,
DEFUN (no_debug_isis_lsp_sched,
no_debug_isis_lsp_sched_cmd,
"no debug isis lsp-sched",
"no debug " PROTO_NAME " lsp-sched",
NO_STR
UNDEBUG_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS scheduling of LSP generation\n")
{
isis->debugs &= ~DEBUG_LSP_SCHED;
@ -1200,9 +1216,9 @@ DEFUN (no_debug_isis_lsp_sched,
DEFUN (show_hostname,
show_hostname_cmd,
"show isis hostname",
"show " PROTO_NAME " hostname",
SHOW_STR
"IS-IS information\n"
PROTO_HELP
"IS-IS Dynamic hostname mapping\n")
{
dynhn_print_all(vty);
@ -1212,10 +1228,10 @@ DEFUN (show_hostname,
DEFUN (show_isis_spf_ietf,
show_isis_spf_ietf_cmd,
"show isis spf-delay-ietf",
"show " PROTO_NAME " spf-delay-ietf",
SHOW_STR
"IS-IS information\n"
"IS-IS SPF delay IETF information\n")
PROTO_HELP
"SPF delay IETF information\n")
{
if (!isis) {
vty_out(vty, "ISIS is not running\n");
@ -1261,15 +1277,15 @@ DEFUN (show_isis_spf_ietf,
DEFUN (show_isis_summary,
show_isis_summary_cmd,
"show isis summary",
SHOW_STR "IS-IS information\n" "IS-IS summary\n")
"show " PROTO_NAME " summary",
SHOW_STR PROTO_HELP "summary\n")
{
struct listnode *node, *node2;
struct isis_area *area;
int level;
if (isis == NULL) {
vty_out(vty, "ISIS is not running\n");
vty_out(vty, PROTO_NAME " is not running\n");
return CMD_SUCCESS;
}
@ -1289,6 +1305,14 @@ DEFUN (show_isis_summary,
vty_out(vty, "Area %s:\n",
area->area_tag ? area->area_tag : "null");
if (fabricd) {
uint8_t tier = fabricd_tier(area);
if (tier == ISIS_TIER_UNDEFINED)
vty_out(vty, " Tier: undefined\n");
else
vty_out(vty, " Tier: %" PRIu8 "\n", tier);
}
if (listcount(area->area_addrs) > 0) {
struct area_addr *area_addr;
for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node2,
@ -1471,10 +1495,10 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
DEFUN (show_database,
show_database_cmd,
"show isis database [detail] [WORD]",
"show " PROTO_NAME " database [detail] [WORD]",
SHOW_STR
"IS-IS information\n"
"IS-IS link state database\n"
PROTO_HELP
"Link state database\n"
"Detailed information\n"
"LSP ID\n")
{
@ -1491,9 +1515,9 @@ DEFUN (show_database,
*/
DEFUN_NOSH (router_isis,
router_isis_cmd,
"router isis WORD",
"router " PROTO_NAME " WORD",
ROUTER_STR
"ISO IS-IS\n"
PROTO_HELP
"ISO Routing area tag\n")
{
int idx_word = 2;
@ -1505,8 +1529,11 @@ DEFUN_NOSH (router_isis,
*/
DEFUN (no_router_isis,
no_router_isis_cmd,
"no router isis WORD",
"no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag\n")
"no router " PROTO_NAME " WORD",
NO_STR
ROUTER_STR
PROTO_HELP
"ISO Routing area tag\n")
{
int idx_word = 3;
return isis_area_destroy(vty, argv[idx_word]->arg);
@ -1869,7 +1896,7 @@ int isis_config_write(struct vty *vty)
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
/* ISIS - Area name */
vty_out(vty, "router isis %s\n", area->area_tag);
vty_out(vty, "router " PROTO_NAME " %s\n", area->area_tag);
write++;
/* ISIS - Net */
if (listcount(area->area_addrs) > 0) {
@ -1893,16 +1920,18 @@ int isis_config_write(struct vty *vty)
write++;
}
/* ISIS - Metric-Style - when true displays wide */
if (area->newmetric) {
if (!area->oldmetric)
vty_out(vty, " metric-style wide\n");
else
vty_out(vty,
" metric-style transition\n");
write++;
} else {
vty_out(vty, " metric-style narrow\n");
write++;
if (!fabricd) {
if (area->newmetric) {
if (!area->oldmetric)
vty_out(vty, " metric-style wide\n");
else
vty_out(vty,
" metric-style transition\n");
write++;
} else {
vty_out(vty, " metric-style narrow\n");
write++;
}
}
/* ISIS - overload-bit */
if (area->overload_bit) {
@ -1910,12 +1939,14 @@ int isis_config_write(struct vty *vty)
write++;
}
/* ISIS - Area is-type (level-1-2 is default) */
if (area->is_type == IS_LEVEL_1) {
vty_out(vty, " is-type level-1\n");
write++;
} else if (area->is_type == IS_LEVEL_2) {
vty_out(vty, " is-type level-2-only\n");
write++;
if (!fabricd) {
if (area->is_type == IS_LEVEL_1) {
vty_out(vty, " is-type level-1\n");
write++;
} else if (area->is_type == IS_LEVEL_2) {
vty_out(vty, " is-type level-2-only\n");
write++;
}
}
write += isis_redist_config_write(vty, area, AF_INET);
write += isis_redist_config_write(vty, area, AF_INET6);
@ -1998,6 +2029,10 @@ int isis_config_write(struct vty *vty)
vty_out(vty, " lsp-mtu %u\n", area->lsp_mtu);
write++;
}
if (area->purge_originator) {
vty_out(vty, " purge-originator\n");
write++;
}
/* Minimum SPF interval. */
if (area->min_spf_interval[0]
@ -2116,6 +2151,7 @@ int isis_config_write(struct vty *vty)
}
write += area_write_mt_settings(area, vty);
write += fabricd_write_settings(area, vty);
}
isis_mpls_te_config_write_router(vty);
}
@ -2123,12 +2159,12 @@ int isis_config_write(struct vty *vty)
return write;
}
struct cmd_node isis_node = {ISIS_NODE, "%s(config-router)# ", 1};
struct cmd_node router_node = {ROUTER_NODE, "%s(config-router)# ", 1};
void isis_init()
{
/* Install IS-IS top node */
install_node(&isis_node, isis_config_write);
install_node(&router_node, isis_config_write);
install_element(VIEW_NODE, &show_isis_summary_cmd);
@ -2212,16 +2248,16 @@ void isis_init()
install_element(CONFIG_NODE, &router_isis_cmd);
install_element(CONFIG_NODE, &no_router_isis_cmd);
install_default(ISIS_NODE);
install_default(ROUTER_NODE);
install_element(ISIS_NODE, &net_cmd);
install_element(ISIS_NODE, &no_net_cmd);
install_element(ROUTER_NODE, &net_cmd);
install_element(ROUTER_NODE, &no_net_cmd);
install_element(ISIS_NODE, &isis_topology_cmd);
install_element(ISIS_NODE, &no_isis_topology_cmd);
install_element(ROUTER_NODE, &isis_topology_cmd);
install_element(ROUTER_NODE, &no_isis_topology_cmd);
install_element(ISIS_NODE, &log_adj_changes_cmd);
install_element(ISIS_NODE, &no_log_adj_changes_cmd);
install_element(ROUTER_NODE, &log_adj_changes_cmd);
install_element(ROUTER_NODE, &no_log_adj_changes_cmd);
spf_backoff_cmd_init();
}

View File

@ -33,12 +33,32 @@
#include "isis_memory.h"
#include "qobj.h"
#ifdef FABRICD
static const bool fabricd = true;
#define PROTO_TYPE ZEBRA_ROUTE_OPENFABRIC
#define PROTO_NAME "openfabric"
#define PROTO_HELP "OpenFabric routing protocol\n"
#define PROTO_REDIST_STR FRR_REDIST_STR_FABRICD
#define PROTO_REDIST_HELP FRR_REDIST_HELP_STR_FABRICD
#define ROUTER_NODE OPENFABRIC_NODE
#else
static const bool fabricd = false;
#define PROTO_TYPE ZEBRA_ROUTE_ISIS
#define PROTO_NAME "isis"
#define PROTO_HELP "IS-IS routing protocol\n"
#define PROTO_REDIST_STR FRR_REDIST_STR_ISISD
#define PROTO_REDIST_HELP FRR_REDIST_HELP_STR_ISISD
#define ROUTER_NODE ISIS_NODE
#endif
extern struct zebra_privs_t isisd_privs;
/* uncomment if you are a developer in bug hunt */
/* #define EXTREME_DEBUG */
/* #define EXTREME_DICT_DEBUG */
struct fabricd;
struct isis {
unsigned long process_id;
int sysid_set;
@ -93,6 +113,8 @@ struct isis_area {
*/
int lsp_regenerate_pending[ISIS_LEVELS];
struct fabricd *fabricd;
/*
* Configurables
*/
@ -126,6 +148,7 @@ struct isis_area {
/* multi topology settings */
struct list *mt_settings;
int ipv6_circuits;
bool purge_originator;
/* Counters */
uint32_t circuit_state_changes;
struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
@ -168,7 +191,6 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
void isis_vty_init(void);
/* Master of threads. */
extern struct thread_master *master;
@ -188,6 +210,7 @@ extern struct thread_master *master;
#define DEBUG_PACKET_DUMP (1<<12)
#define DEBUG_LSP_GEN (1<<13)
#define DEBUG_LSP_SCHED (1<<14)
#define DEBUG_FABRICD_FLOODING (1<<15)
#define lsp_debug(...) \
do { \

View File

@ -8,33 +8,11 @@ sbin_PROGRAMS += isisd/isisd
dist_examples_DATA += isisd/isisd.conf.sample
endif
isisd_libisis_a_SOURCES = \
isisd/dict.c \
isisd/isis_adjacency.c \
isisd/isis_circuit.c \
isisd/isis_csm.c \
isisd/isis_dr.c \
isisd/isis_dynhn.c \
isisd/isis_errors.c \
isisd/isis_events.c \
isisd/isis_flags.c \
isisd/isis_lsp.c \
isisd/isis_lsp_hash.c \
isisd/isis_memory.c \
isisd/isis_misc.c \
isisd/isis_mt.c \
isisd/isis_pdu.c \
isisd/isis_redist.c \
isisd/isis_route.c \
isisd/isis_routemap.c \
isisd/isis_spf.c \
isisd/isis_te.c \
isisd/isis_tlvs.c \
isisd/isis_vty.c \
isisd/isis_zebra.c \
isisd/isisd.c \
isisd/iso_checksum.c \
# end
if FABRICD
noinst_LIBRARIES += isisd/libfabric.a
sbin_PROGRAMS += isisd/fabricd
dist_examples_DATA += isisd/fabricd.conf.sample
endif
noinst_HEADERS += \
isisd/dict.h \
@ -49,7 +27,6 @@ noinst_HEADERS += \
isisd/isis_events.h \
isisd/isis_flags.h \
isisd/isis_lsp.h \
isisd/isis_lsp_hash.h \
isisd/isis_memory.h \
isisd/isis_misc.h \
isisd/isis_mt.h \
@ -59,17 +36,73 @@ noinst_HEADERS += \
isisd/isis_route.h \
isisd/isis_routemap.h \
isisd/isis_spf.h \
isisd/isis_spf_private.h \
isisd/isis_te.h \
isisd/isis_tlvs.h \
isisd/isis_tx_queue.h \
isisd/isis_vty_common.h \
isisd/isis_zebra.h \
isisd/isisd.h \
isisd/iso_checksum.h \
isisd/fabricd.h \
# end
isisd_isisd_LDADD = isisd/libisis.a lib/libfrr.la @LIBCAP@
isisd_isisd_SOURCES = \
LIBISIS_SOURCES = \
isisd/dict.c \
isisd/isis_adjacency.c \
isisd/isis_circuit.c \
isisd/isis_csm.c \
isisd/isis_dr.c \
isisd/isis_dynhn.c \
isisd/isis_errors.c \
isisd/isis_events.c \
isisd/isis_flags.c \
isisd/isis_lsp.c \
isisd/isis_memory.c \
isisd/isis_misc.c \
isisd/isis_mt.c \
isisd/isis_pdu.c \
isisd/isis_redist.c \
isisd/isis_route.c \
isisd/isis_routemap.c \
isisd/isis_spf.c \
isisd/isis_te.c \
isisd/isis_tlvs.c \
isisd/isis_tx_queue.c \
isisd/isis_vty_common.c \
isisd/isis_zebra.c \
isisd/isisd.c \
isisd/iso_checksum.c \
isisd/fabricd.c \
# end
ISIS_SOURCES = \
isisd/isis_bpf.c \
isisd/isis_dlpi.c \
isisd/isis_main.c \
isisd/isis_pfpacket.c \
# end
ISIS_LDADD_COMMON = lib/libfrr.la @LIBCAP@
# Building isisd
isisd_libisis_a_SOURCES = \
$(LIBISIS_SOURCES) \
isisd/isis_vty_isisd.c \
#end
isisd_isisd_LDADD = isisd/libisis.a $(ISIS_LDADD_COMMON)
isisd_isisd_SOURCES = $(ISIS_SOURCES)
# Building fabricd
FABRICD_CPPFLAGS = -DFABRICD=1 $(AM_CPPFLAGS)
isisd_libfabric_a_SOURCES = \
$(LIBISIS_SOURCES) \
isisd/isis_vty_fabricd.c \
#end
isisd_libfabric_a_CPPFLAGS = $(FABRICD_CPPFLAGS)
isisd_fabricd_LDADD = isisd/libfabric.a $(ISIS_LDADD_COMMON)
isisd_fabricd_SOURCES = $(ISIS_SOURCES)
isisd_fabricd_CPPFLAGS = $(FABRICD_CPPFLAGS)

View File

@ -146,6 +146,7 @@ const char *node_names[] = {
*/
"bfd", /* BFD_NODE */
"bfd peer", /* BFD_PEER_NODE */
"openfabric", // OPENFABRIC_NODE
};
/* clang-format on */
@ -1435,6 +1436,7 @@ void cmd_exit(struct vty *vty)
case LDP_NODE:
case LDP_L2VPN_NODE:
case ISIS_NODE:
case OPENFABRIC_NODE:
case KEYCHAIN_NODE:
case RMAP_NODE:
case PBRMAP_NODE:
@ -1550,6 +1552,7 @@ DEFUN (config_end,
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case OPENFABRIC_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
case VTY_NODE:

View File

@ -141,6 +141,7 @@ enum node_type {
BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */
BFD_NODE, /* BFD protocol mode. */
BFD_PEER_NODE, /* BFD peer configuration mode. */
OPENFABRIC_NODE, /* OpenFabric router configuration node */
NODE_TYPE_MAX, /* maximum */
};
@ -364,7 +365,6 @@ struct cmd_node {
#define PREFIX_LIST_STR "Build a prefix list\n"
#define OSPF6_DUMP_TYPE_LIST \
"<neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr>"
#define ISIS_STR "IS-IS information\n"
#define AREA_TAG_STR "[area tag]\n"
#define COMMUNITY_AANN_STR "Community number where AA and NN are (0-65535)\n"
#define COMMUNITY_VAL_STR "Community number in AA:NN format (where AA and NN are (0-65535)) or local-AS|no-advertise|no-export|internet or additive\n"

View File

@ -1074,6 +1074,8 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
else if (strmatch(s, "openfabric"))
return ZEBRA_ROUTE_OPENFABRIC;
}
if (afi == AFI_IP6) {
if (strmatch(s, "kernel"))
@ -1102,6 +1104,8 @@ int proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
else if (strmatch(s, "openfabric"))
return ZEBRA_ROUTE_OPENFABRIC;
}
return -1;
}

View File

@ -82,6 +82,7 @@ ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, 1, "SHARP"
ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
@ -109,3 +110,4 @@ ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol"

View File

@ -811,6 +811,7 @@ static void vty_end_config(struct vty *vty)
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case OPENFABRIC_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
@ -1210,6 +1211,7 @@ static void vty_stop_input(struct vty *vty)
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case OPENFABRIC_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
case VTY_NODE:

View File

@ -414,6 +414,7 @@ extern const char *zserv_command_string(unsigned int command);
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
#define ZEBRA_FLAG_EVPN_ROUTE 0x400
#define ZEBRA_FLAG_RR_USE_DISTANCE 0x800
#define ZEBRA_FLAG_ONLINK 0x1000
/* ZEBRA_FLAG_BLACKHOLE was 0x04 */
/* ZEBRA_FLAG_REJECT was 0x80 */

View File

@ -53,6 +53,7 @@ sharpd=no
pbrd=no
staticd=no
bfdd=no
fabricd=no
#
# Command line options for the daemons
@ -73,6 +74,7 @@ sharpd_options=("-A 127.0.0.1")
pbrd_options=("-A 127.0.0.1")
staticd_options=("-A 127.0.0.1")
bfdd_options=("-A 127.0.0.1")
fabricd_options=("-A 127.0.0.1")
#
# If the vtysh_enable is yes, then the unified config is read

View File

@ -33,7 +33,7 @@ V_PATH=/var/run/frr
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd"
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd fabricd"
MAX_INSTANCES=5
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py

View File

@ -93,3 +93,11 @@
/bin/kill -USR1 `cat /var/run/frr/bfdd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
/var/log/frr/fabricd.log {
notifempty
missingok
postrotate
/bin/kill -USR1 `cat /var/run/frr/fabricd.pid 2> /dev/null` 2> /dev/null || true
endscript
}

View File

@ -86,7 +86,7 @@
%{!?frr_gid: %global frr_gid 92 }
%{!?vty_gid: %global vty_gid 85 }
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd
%if %{with_ldpd}
%define daemon_ldpd ldpd
@ -459,6 +459,7 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty"
%if %{with_bfdd}
zebra_spec_add_service bfdd 2617/tcp "BFDd vty"
%endif
zebra_spec_add_service fabricd 2618/tcp "Fabricd vty"
%if "%{initsystem}" == "systemd"
for daemon in %all_daemons ; do
@ -594,6 +595,7 @@ fi
%{_sbindir}/pbrd
%endif
%{_sbindir}/isisd
%{_sbindir}/fabricd
%if %{with_ldpd}
%{_sbindir}/ldpd
%endif

View File

@ -114,7 +114,11 @@ static int test(FILE *input, FILE *output)
const char *s_tlvs = isis_format_tlvs(tlvs);
fprintf(output, "Unpacked TLVs:\n%s", s_tlvs);
struct isis_item *orig_auth = tlvs->isis_auth.head;
tlvs->isis_auth.head = NULL;
s_tlvs = isis_format_tlvs(tlvs);
struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs);
tlvs->isis_auth.head = orig_auth;
isis_free_tlvs(tlvs);
struct stream *s2 = stream_new(TEST_STREAM_SIZE);

View File

@ -16,42 +16,46 @@ static size_t vertex_count;
static void setup_test_vertices(void)
{
union isis_N nid, nip = {
.ip.dest.family = AF_UNSPEC
struct isis_spftree t = {
};
struct prefix_pair p = {
};
uint8_t node_id[7];
vertices = XMALLOC(MTYPE_TMP, sizeof(*vertices) * 16);
nip.ip.dest.family = AF_INET;
nip.ip.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.1.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
p.dest.family = AF_INET;
p.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.1.0", &p.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&t, &p, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
nip.ip.dest.family = AF_INET;
nip.ip.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.2.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
p.dest.family = AF_INET;
p.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.2.0", &p.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&t, &p, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
memset(nid.id, 0, sizeof(nid.id));
nid.id[6] = 1;
vertices[vertex_count] = isis_vertex_new(&nid, VTYPE_PSEUDO_TE_IS);
memset(node_id, 0, sizeof(node_id));
node_id[6] = 1;
vertices[vertex_count] = isis_vertex_new(&t, node_id,
VTYPE_PSEUDO_TE_IS);
vertices[vertex_count]->d_N = 15;
vertex_count++;
memset(nid.id, 0, sizeof(nid.id));
nid.id[5] = 2;
vertices[vertex_count] = isis_vertex_new(&nid, VTYPE_NONPSEUDO_TE_IS);
memset(node_id, 0, sizeof(node_id));
node_id[5] = 2;
vertices[vertex_count] = isis_vertex_new(&t, node_id,
VTYPE_NONPSEUDO_TE_IS);
vertices[vertex_count]->d_N = 15;
vertex_count++;
nip.ip.dest.family = AF_INET;
nip.ip.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.3.0", &nip.ip.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&nip, VTYPE_IPREACH_TE);
p.dest.family = AF_INET;
p.dest.prefixlen = 24;
inet_pton(AF_INET, "192.168.3.0", &p.dest.u.prefix4);
vertices[vertex_count] = isis_vertex_new(&t, &p, VTYPE_IPREACH_TE);
vertices[vertex_count]->d_N = 20;
vertex_count++;
};

View File

@ -11,3 +11,4 @@
194 sharp
195 pbr
196 static
197 openfabric

View File

@ -587,6 +587,7 @@ case "$1" in
ip route flush proto 194
ip route flush proto 195
ip route flush proto 196
ip route flush proto 197
else
[ -n "$dmn" ] && eval "${dmn/-/_}=0"
start_watchfrr

View File

@ -64,7 +64,9 @@ if ISISD
vtysh_scan += $(top_srcdir)/isisd/isis_redist.c
vtysh_scan += $(top_srcdir)/isisd/isis_spf.c
vtysh_scan += $(top_srcdir)/isisd/isis_te.c
vtysh_scan += $(top_srcdir)/isisd/isis_vty.c
vtysh_scan += $(top_srcdir)/isisd/isis_vty_common.c
vtysh_scan += $(top_srcdir)/isisd/isis_vty_fabricd.c
vtysh_scan += $(top_srcdir)/isisd/isis_vty_isisd.c
vtysh_scan += $(top_srcdir)/isisd/isisd.c
endif

View File

@ -35,10 +35,12 @@ EOF
my $cli_stomp = 0;
foreach (@ARGV) {
$file = $_;
sub scan_file {
my ( $file, $fabricd) = @_;
open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/bgpd -I@top_srcdir@/@LIBRFP@ -I@top_srcdir@/bgpd/rfapi @CPPFLAGS@ $file |");
$cppadd = $fabricd ? "-DFABRICD=1" : "";
open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/bgpd -I@top_srcdir@/@LIBRFP@ -I@top_srcdir@/bgpd/rfapi @CPPFLAGS@ $cppadd $file |");
local $/; undef $/;
$line = <FH>;
close (FH);
@ -77,6 +79,10 @@ foreach (@ARGV) {
$cmd =~ s/^\s+//g;
$cmd =~ s/\s+$//g;
if ($fabricd) {
$cmd = "fabricd_" . $cmd;
}
# $protocol is VTYSH_PROTO format for redirection of user input
if ($file =~ /lib\/keychain\.c$/) {
$protocol = "VTYSH_RIPD";
@ -107,9 +113,9 @@ foreach (@ARGV) {
}
elsif ($file =~ /lib\/plist\.c$/) {
if ($defun_array[1] =~ m/ipv6/) {
$protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_BABELD|VTYSH_ISISD";
$protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
} else {
$protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD";
$protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
}
}
elsif ($file =~ /lib\/distribute\.c$/) {
@ -132,6 +138,9 @@ foreach (@ARGV) {
elsif ($file =~ /librfp\/.*\.c$/ || $file =~ /rfapi\/.*\.c$/) {
$protocol = "VTYSH_BGPD";
}
elsif ($fabricd) {
$protocol = "VTYSH_FABRICD";
}
else {
($protocol) = ($file =~ /^.*\/([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/);
$protocol = "VTYSH_" . uc $protocol;
@ -170,6 +179,10 @@ foreach (@ARGV) {
$ecmd =~ s/^\s+//g;
$ecmd =~ s/\s+$//g;
if ($fabricd) {
$ecmd = "fabricd_" . $ecmd;
}
# Register $ecmd
if (defined ($cmd2str{$ecmd})) {
my ($key);
@ -187,6 +200,24 @@ foreach (@ARGV) {
}
}
foreach (@ARGV) {
if (/\/isisd\//) {
# We scan all the IS-IS files twice, once for isisd,
# once for fabricd. Exceptions are made for the files
# that are not shared between the two.
if (/isis_vty_isisd.c/) {
scan_file($_, 0);
} elsif (/isis_vty_fabricd.c/) {
scan_file($_, 1);
} else {
scan_file($_, 0);
scan_file($_, 1);
}
} else {
scan_file($_, 0);
}
}
# When we have cli commands that map to the same function name, we
# can introduce subtle bugs due to code not being called when
# we think it is.

View File

@ -132,6 +132,7 @@ struct vtysh_client vtysh_client[] = {
{.fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL},
{.fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .next = NULL},
{.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
{.fd = -1, .name = "fabricd", .flag = VTYSH_FABRICD, .next = NULL},
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
{.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
@ -1141,6 +1142,10 @@ static struct cmd_node isis_node = {
ISIS_NODE, "%s(config-router)# ",
};
static struct cmd_node openfabric_node = {
OPENFABRIC_NODE, "%s(config-router)# ",
};
static struct cmd_node interface_node = {
INTERFACE_NODE, "%s(config-if)# ",
};
@ -1653,6 +1658,15 @@ DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, "router isis WORD",
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfabric WORD",
ROUTER_STR
"OpenFabric routing protocol\n"
"ISO Routing area tag\n")
{
vty->node = OPENFABRIC_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
"route-map WORD <deny|permit> (1-65535)",
"Create route-map or enter route-map command mode\n"
@ -1767,6 +1781,7 @@ static int vtysh_exit(struct vty *vty)
case LDP_NODE:
case LDP_L2VPN_NODE:
case ISIS_NODE:
case OPENFABRIC_NODE:
case RMAP_NODE:
case PBRMAP_NODE:
case VTY_NODE:
@ -2042,6 +2057,18 @@ ALIAS(vtysh_exit_bfdd, vtysh_quit_bfdd_cmd, "quit",
"Exit current mode and down to previous mode\n")
#endif
DEFUNSH(VTYSH_FABRICD, vtysh_exit_fabricd, vtysh_exit_fabricd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit(vty);
}
DEFUNSH(VTYSH_FABRICD, vtysh_quit_fabricd, vtysh_quit_fabricd_cmd, "quit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit_fabricd(self, vty, argc, argv);
}
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@ -2245,7 +2272,7 @@ DEFUN (vtysh_show_work_queues,
DEFUN (vtysh_show_work_queues_daemon,
vtysh_show_work_queues_daemon_cmd,
"show work-queues <zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd>",
"show work-queues <zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd>",
SHOW_STR
"Work Queue information\n"
"For the zebra daemon\n"
@ -2255,7 +2282,8 @@ DEFUN (vtysh_show_work_queues_daemon,
"For the ospfv6 daemon\n"
"For the bgp daemon\n"
"For the isis daemon\n"
"For the pbr daemon\n")
"For the pbr daemon\n"
"For the fabricd daemon\n")
{
int idx_protocol = 2;
unsigned int i;
@ -2593,7 +2621,7 @@ DEFUNSH(VTYSH_ALL, no_vtysh_config_enable_password,
DEFUN (vtysh_write_terminal,
vtysh_write_terminal_cmd,
"write terminal [<zebra|ripd|ripngd|ospfd|ospf6d|ldpd|bgpd|isisd|pimd>]",
"write terminal [<zebra|ripd|ripngd|ospfd|ospf6d|ldpd|bgpd|isisd|fabricd|pimd>]",
"Write running configuration to memory, network, or terminal\n"
"Write to terminal\n"
"For the zebra daemon\n"
@ -2604,6 +2632,7 @@ DEFUN (vtysh_write_terminal,
"For the ldpd daemon\n"
"For the bgp daemon\n"
"For the isis daemon\n"
"For the fabricd daemon\n"
"For the pim daemon\n")
{
unsigned int i;
@ -2630,7 +2659,7 @@ DEFUN (vtysh_write_terminal,
DEFUN (vtysh_show_running_config,
vtysh_show_running_config_cmd,
"show running-config [<zebra|ripd|ripngd|ospfd|ospf6d|ldpd|bgpd|isisd|pimd>]",
"show running-config [<zebra|ripd|ripngd|ospfd|ospf6d|ldpd|bgpd|isisd|fabricd|pimd>]",
SHOW_STR
"Current operating configuration\n"
"For the zebra daemon\n"
@ -2641,6 +2670,7 @@ DEFUN (vtysh_show_running_config,
"For the ldp daemon\n"
"For the bgp daemon\n"
"For the isis daemon\n"
"For the fabricd daemon\n"
"For the pim daemon\n")
{
return vtysh_write_terminal(self, vty, argc, argv);
@ -3493,6 +3523,7 @@ void vtysh_init_vty(void)
install_node(&keychain_node, NULL);
install_node(&keychain_key_node, NULL);
install_node(&isis_node, NULL);
install_node(&openfabric_node, NULL);
install_node(&vty_node, NULL);
#if defined(HAVE_RPKI)
install_node(&rpki_node, NULL);
@ -3587,6 +3618,8 @@ void vtysh_init_vty(void)
#endif
install_element(ISIS_NODE, &vtysh_exit_isisd_cmd);
install_element(ISIS_NODE, &vtysh_quit_isisd_cmd);
install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd);
install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd);
install_element(KEYCHAIN_NODE, &vtysh_exit_ripd_cmd);
install_element(KEYCHAIN_NODE, &vtysh_quit_ripd_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_ripd_cmd);
@ -3647,6 +3680,7 @@ void vtysh_init_vty(void)
install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
install_element(ISIS_NODE, &vtysh_end_all_cmd);
install_element(OPENFABRIC_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
install_element(RMAP_NODE, &vtysh_end_all_cmd);
@ -3696,6 +3730,7 @@ void vtysh_init_vty(void)
install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd);
#endif
install_element(CONFIG_NODE, &router_isis_cmd);
install_element(CONFIG_NODE, &router_openfabric_cmd);
install_element(CONFIG_NODE, &router_bgp_cmd);
install_element(BGP_NODE, &address_family_vpnv4_cmd);
install_element(BGP_NODE, &address_family_vpnv6_cmd);

View File

@ -41,6 +41,7 @@ DECLARE_MGROUP(MVTYSH)
#define VTYSH_PBRD 0x04000
#define VTYSH_STATICD 0x08000
#define VTYSH_BFDD 0x10000
#define VTYSH_FABRICD 0x20000
#define VTYSH_WAS_ACTIVE (-2)
@ -49,9 +50,9 @@ DECLARE_MGROUP(MVTYSH)
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD|VTYSH_FABRICD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD
#define VTYSH_NS VTYSH_ZEBRA
#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD

View File

@ -245,6 +245,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
else if (strncmp(line, "router isis", strlen("router isis"))
== 0)
config = config_get(ISIS_NODE, line);
else if (strncmp(line, "router openfabric", strlen("router openfabric"))
== 0)
config = config_get(OPENFABRIC_NODE, line);
else if (strncmp(line, "route-map", strlen("route-map")) == 0)
config = config_get(RMAP_NODE, line);
else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)

View File

@ -99,7 +99,7 @@ static inline int is_selfroute(int proto)
|| (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
|| (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
|| (proto == RTPROT_PBR)) {
|| (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)) {
return 1;
}
@ -146,6 +146,9 @@ static inline int zebra2proto(int proto)
case ZEBRA_ROUTE_PBR:
proto = RTPROT_PBR;
break;
case ZEBRA_ROUTE_OPENFABRIC:
proto = RTPROT_OPENFABRIC;
break;
default:
/*
* When a user adds a new protocol this will show up
@ -203,6 +206,9 @@ static inline int proto2zebra(int proto, int family)
case RTPROT_PBR:
proto = ZEBRA_ROUTE_PBR;
break;
case RTPROT_OPENFABRIC:
proto = ZEBRA_ROUTE_OPENFABRIC;
break;
default:
/*
* When a user adds a new protocol this will show up

View File

@ -54,6 +54,7 @@
#define RTPROT_SHARP 194
#define RTPROT_PBR 195
#define RTPROT_ZSTATIC 196
#define RTPROT_OPENFABRIC 197
void rt_netlink_init(void);

View File

@ -266,7 +266,8 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
There was a crash because ifp here was coming to be NULL */
if (ifp)
if (connected_is_unnumbered(ifp)
|| CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|| CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)
|| CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
}
@ -303,8 +304,10 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)
|| CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
}
route_entry_nexthop_add(re, nexthop);
@ -442,7 +445,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (ifp && connected_is_unnumbered(ifp)) {
if ((ifp && connected_is_unnumbered(ifp))
|| CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) {
if (if_is_operative(ifp))
return 1;
else {