frr/isisd/isis_circuit.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1687 lines
46 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
2003-12-23 09:09:43 +01:00
/*
* IS-IS Rout(e)ing protocol - isis_circuit.h
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
*/
#include <zebra.h>
2004-05-19 13:38:40 +02:00
#ifdef GNU_LINUX
2003-12-23 09:09:43 +01:00
#include <net/ethernet.h>
2004-05-19 13:38:40 +02:00
#else
#include <netinet/if_ether.h>
#endif
2003-12-23 09:09:43 +01:00
#include "log.h"
#include "memory.h"
#include "vrf.h"
2003-12-23 09:09:43 +01:00
#include "if.h"
#include "linklist.h"
#include "command.h"
#include "frrevent.h"
#include "vty.h"
2003-12-23 09:09:43 +01:00
#include "hash.h"
#include "prefix.h"
#include "stream.h"
#include "qobj.h"
#include "lib/northbound_cli.h"
2003-12-23 09:09:43 +01:00
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
2012-03-24 16:35:20 +01:00
#include "isisd/isis_flags.h"
2003-12-23 09:09:43 +01:00
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_pdu.h"
#include "isisd/isis_network.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dr.h"
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_srv6.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
#include "isisd/isis_ldp_sync.h"
2003-12-23 09:09:43 +01:00
DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit");
DEFINE_QOBJ_TYPE(isis_circuit);
DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
/*
* Prototypes.
*/
int isis_if_new_hook(struct interface *);
int isis_if_delete_hook(struct interface *);
DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit));
DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
static void isis_circuit_enable(struct isis_circuit *circuit)
{
struct isis_area *area = circuit->area;
struct interface *ifp = circuit->interface;
if (!area) {
area = isis_area_lookup(circuit->tag, ifp->vrf->vrf_id);
if (area)
isis_area_add_circuit(area, circuit);
}
if (if_is_operative(ifp))
isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
}
static void isis_circuit_disable(struct isis_circuit *circuit)
{
struct isis_area *area = circuit->area;
struct interface *ifp = circuit->interface;
if (if_is_operative(ifp))
isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
if (area)
isis_area_del_circuit(area, circuit);
}
struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag)
2003-12-23 09:09:43 +01:00
{
struct isis_circuit *circuit;
int i;
circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit));
circuit->tag = XSTRDUP(MTYPE_ISIS_CIRCUIT, tag);
2012-03-24 16:35:20 +01:00
/*
* Default values
*/
#ifndef FABRICD
circuit->is_type_config = yang_get_default_enum(
"/frr-interface:lib/interface/frr-isisd:isis/circuit-type");
circuit->flags = 0;
circuit->pad_hellos = yang_get_default_enum(
"/frr-interface:lib/interface/frr-isisd:isis/hello/padding");
circuit->hello_interval[0] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1");
circuit->hello_interval[1] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2");
circuit->hello_multiplier[0] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1");
circuit->hello_multiplier[1] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2");
circuit->csnp_interval[0] = yang_get_default_uint16(
"/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1");
circuit->csnp_interval[1] = yang_get_default_uint16(
"/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2");
circuit->psnp_interval[0] = yang_get_default_uint16(
"/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1");
circuit->psnp_interval[1] = yang_get_default_uint16(
"/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2");
circuit->priority[0] = yang_get_default_uint8(
"/frr-interface:lib/interface/frr-isisd:isis/priority/level-1");
circuit->priority[1] = yang_get_default_uint8(
"/frr-interface:lib/interface/frr-isisd:isis/priority/level-2");
circuit->metric[0] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
circuit->metric[1] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
circuit->te_metric[0] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
circuit->te_metric[1] = yang_get_default_uint32(
"/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
for (i = 0; i < 2; i++) {
circuit->level_arg[i].level = i + 1;
circuit->level_arg[i].circuit = circuit;
}
#else
circuit->is_type_config = IS_LEVEL_1_AND_2;
2012-03-24 16:35:20 +01:00
circuit->flags = 0;
circuit->pad_hellos = ISIS_HELLO_PADDING_ALWAYS;
2012-03-24 16:35:20 +01:00
for (i = 0; i < 2; i++) {
circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
circuit->priority[i] = DEFAULT_PRIORITY;
circuit->metric[i] = DEFAULT_CIRCUIT_METRIC;
2012-03-24 16:35:20 +01:00
circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
circuit->level_arg[i].level = i + 1;
circuit->level_arg[i].circuit = circuit;
2012-03-24 16:35:20 +01:00
}
#endif /* ifndef FABRICD */
circuit->is_type = circuit->is_type_config;
circuit_mt_init(circuit);
isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1);
isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2);
circuit->ldp_sync_info = ldp_sync_info_create();
circuit->ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
QOBJ_REG(circuit, isis_circuit);
isis_circuit_if_bind(circuit, ifp);
circuit->ip_addrs = list_new();
circuit->ipv6_link = list_new();
circuit->ipv6_non_link = list_new();
if (ifp->ifindex != IFINDEX_INTERNAL)
isis_circuit_enable(circuit);
2003-12-23 09:09:43 +01:00
return circuit;
}
2012-03-24 16:35:20 +01:00
void isis_circuit_del(struct isis_circuit *circuit)
{
if (!circuit)
return;
if (circuit->interface->ifindex != IFINDEX_INTERNAL)
isis_circuit_disable(circuit);
2012-03-24 16:35:20 +01:00
isis_circuit_if_unbind(circuit, circuit->interface);
QOBJ_UNREG(circuit);
ldp_sync_info_free(&circuit->ldp_sync_info);
circuit_mt_finish(circuit);
isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL1);
isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL2);
list_delete(&circuit->ip_addrs);
list_delete(&circuit->ipv6_link);
list_delete(&circuit->ipv6_non_link);
if (circuit->ext) {
isis_del_ext_subtlvs(circuit->ext);
circuit->ext = NULL;
}
XFREE(MTYPE_TMP, circuit->bfd_config.profile);
XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag);
2012-03-24 16:35:20 +01:00
/* and lastly the circuit itself */
XFREE(MTYPE_ISIS_CIRCUIT, circuit);
return;
}
2003-12-23 09:09:43 +01:00
void isis_circuit_configure(struct isis_circuit *circuit,
struct isis_area *area)
{
2012-03-24 16:35:20 +01:00
assert(area);
circuit->isis = area->isis;
2003-12-23 09:09:43 +01:00
circuit->area = area;
2003-12-23 09:09:43 +01:00
/*
* Whenever the is-type of an area is changed, the is-type of each
* circuit
* in that area is updated to a non-empty subset of the area is-type.
* Inversely, when configuring a new circuit, this property should be
* ensured as well.
2003-12-23 09:09:43 +01:00
*/
if (area->is_type != IS_LEVEL_1_AND_2)
circuit->is_type = area->is_type;
2003-12-23 09:09:43 +01:00
/*
* Add the circuit into area
*/
listnode_add(area->circuit_list, circuit);
2003-12-23 09:09:43 +01:00
circuit->idx = flags_get_index(&area->flags);
hook_call(isis_circuit_new_hook, circuit);
2003-12-23 09:09:43 +01:00
return;
}
2012-03-24 16:35:20 +01:00
void isis_circuit_deconfigure(struct isis_circuit *circuit,
struct isis_area *area)
2003-12-23 09:09:43 +01:00
{
hook_call(isis_circuit_del_hook, circuit);
2003-12-23 09:09:43 +01:00
/* Free the index of SRM and SSN flags */
flags_free_index(&area->flags, circuit->idx);
2012-03-24 16:35:20 +01:00
circuit->idx = 0;
/* Reset IS type to configured */
circuit->is_type = circuit->is_type_config;
2012-03-24 16:35:20 +01:00
/* Remove circuit from area */
assert(circuit->area == area);
listnode_delete(area->circuit_list, circuit);
circuit->area = NULL;
circuit->isis = NULL;
2003-12-23 09:09:43 +01:00
return;
}
struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
{
return (struct isis_circuit *)ifp->info;
2003-12-23 09:09:43 +01:00
}
DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
(circuit));
void isis_circuit_add_addr(struct isis_circuit *circuit,
struct connected *connected)
2003-12-23 09:09:43 +01:00
{
2012-03-24 16:35:20 +01:00
struct listnode *node;
2003-12-23 09:09:43 +01:00
struct prefix_ipv4 *ipv4;
struct prefix_ipv6 *ipv6;
if (connected->address->family == AF_INET) {
uint32_t addr = connected->address->u.prefix4.s_addr;
2012-03-24 16:35:20 +01:00
addr = ntohl(addr);
if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr))
2012-03-24 16:35:20 +01:00
return;
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4))
if (prefix_same((struct prefix *)ipv4,
connected->address))
return;
ipv4 = prefix_ipv4_new();
ipv4->prefixlen = connected->address->prefixlen;
ipv4->prefix = connected->address->u.prefix4;
listnode_add(circuit->ip_addrs, ipv4);
/* Update Local IP address parameter if MPLS TE is enable */
if (circuit->ext && circuit->area
&& IS_MPLS_TE(circuit->area->mta)) {
circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr;
SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR);
}
if (circuit->area)
2012-03-24 16:35:20 +01:00
lsp_regenerate_schedule(circuit->area, circuit->is_type,
0);
2003-12-23 09:09:43 +01:00
#ifdef EXTREME_DEBUG
if (IS_DEBUG_EVENTS)
zlog_debug("Added IP address %pFX to circuit %s",
connected->address,
circuit->interface->name);
#endif /* EXTREME_DEBUG */
}
if (connected->address->family == AF_INET6) {
2012-03-24 16:35:20 +01:00
if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
return;
2012-03-24 16:35:20 +01:00
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6))
if (prefix_same((struct prefix *)ipv6,
connected->address))
return;
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6))
if (prefix_same((struct prefix *)ipv6,
connected->address))
return;
ipv6 = prefix_ipv6_new();
ipv6->prefixlen = connected->address->prefixlen;
ipv6->prefix = connected->address->u.prefix6;
if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix))
listnode_add(circuit->ipv6_link, ipv6);
else {
listnode_add(circuit->ipv6_non_link, ipv6);
/* Update Local IPv6 address param. if MPLS TE is on */
if (circuit->ext && circuit->area
&& IS_MPLS_TE(circuit->area->mta)) {
IPV6_ADDR_COPY(&circuit->ext->local_addr6,
&ipv6->prefix);
SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR6);
}
}
if (circuit->area)
2012-03-24 16:35:20 +01:00
lsp_regenerate_schedule(circuit->area, circuit->is_type,
0);
2003-12-23 09:09:43 +01:00
#ifdef EXTREME_DEBUG
if (IS_DEBUG_EVENTS)
zlog_debug("Added IPv6 address %pFX to circuit %s",
connected->address,
circuit->interface->name);
#endif /* EXTREME_DEBUG */
}
hook_call(isis_circuit_add_addr_hook, circuit);
2003-12-23 09:09:43 +01:00
return;
}
void isis_circuit_del_addr(struct isis_circuit *circuit,
struct connected *connected)
2003-12-23 09:09:43 +01:00
{
struct prefix_ipv4 *ipv4, *ip = NULL;
struct listnode *node;
struct prefix_ipv6 *ipv6, *ip6 = NULL;
int found = 0;
if (connected->address->family == AF_INET) {
ipv4 = prefix_ipv4_new();
ipv4->prefixlen = connected->address->prefixlen;
ipv4->prefix = connected->address->u.prefix4;
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip))
2012-03-24 16:35:20 +01:00
if (prefix_same((struct prefix *)ip,
(struct prefix *)ipv4))
break;
if (ip) {
listnode_delete(circuit->ip_addrs, ip);
prefix_ipv4_free(&ip);
2012-03-24 16:35:20 +01:00
if (circuit->area)
lsp_regenerate_schedule(circuit->area,
circuit->is_type, 0);
} else {
zlog_warn(
"Nonexistent ip address %pFX removal attempt from circuit %s",
connected->address, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
2012-03-24 16:35:20 +01:00
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
ip)) {
zlog_warn(" %pFX", ip);
}
zlog_warn("End of addresses");
}
prefix_ipv4_free(&ipv4);
}
if (connected->address->family == AF_INET6) {
ipv6 = prefix_ipv6_new();
ipv6->prefixlen = connected->address->prefixlen;
ipv6->prefix = connected->address->u.prefix6;
if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) {
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
ip6)) {
if (prefix_same((struct prefix *)ip6,
(struct prefix *)ipv6))
break;
}
if (ip6) {
listnode_delete(circuit->ipv6_link, ip6);
prefix_ipv6_free(&ip6);
found = 1;
}
} else {
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
ip6)) {
if (prefix_same((struct prefix *)ip6,
(struct prefix *)ipv6))
break;
}
if (ip6) {
listnode_delete(circuit->ipv6_non_link, ip6);
prefix_ipv6_free(&ip6);
found = 1;
}
}
if (!found) {
2017-02-13 19:27:54 +01:00
zlog_warn(
"Nonexistent ip address %pFX removal attempt from circuit %s",
connected->address, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
ip6))
zlog_warn(" %pFX", (struct prefix *)ip6);
zlog_warn(" -----");
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
ip6))
zlog_warn(" %pFX", (struct prefix *)ip6);
zlog_warn("End of addresses");
2012-03-24 16:35:20 +01:00
} else if (circuit->area)
lsp_regenerate_schedule(circuit->area, circuit->is_type,
0);
prefix_ipv6_free(&ipv6);
}
return;
}
static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp)
{
/* Circuit ids MUST be unique for any broadcast circuits. Otherwise,
* Pseudo-Node LSPs cannot be generated correctly.
*
* Currently, allocate one circuit ID for any circuit, limiting the total
* numer of circuits IS-IS can run on to 255.
*
* We should revisit this when implementing 3-way adjacencies for p2p, since
* we then have extended interface IDs available.
*/
uint8_t id = ifp->ifindex;
2012-03-24 16:35:20 +01:00
unsigned int i;
for (i = 0; i < 256; i++) {
if (id && !_ISIS_CHECK_FLAG(isis->circuit_ids_used, id))
break;
id++;
}
if (i == 256) {
zlog_warn("Could not allocate a circuit id for '%s'",
ifp->name);
return 0;
}
_ISIS_SET_FLAG(isis->circuit_ids_used, id);
2012-03-24 16:35:20 +01:00
return id;
}
2003-12-23 09:09:43 +01:00
void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
{
struct connected *conn;
if (if_is_broadcast(ifp)) {
if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P)
2012-03-24 16:35:20 +01:00
circuit->circ_type = CIRCUIT_T_P2P;
else
2012-03-24 16:35:20 +01:00
circuit->circ_type = CIRCUIT_T_BROADCAST;
} else if (if_is_pointopoint(ifp)) {
circuit->circ_type = CIRCUIT_T_P2P;
} else if (if_is_loopback(ifp)) {
2012-03-24 16:35:20 +01:00
circuit->circ_type = CIRCUIT_T_LOOPBACK;
circuit->is_passive = 1;
} else {
/* It's normal in case of loopback etc. */
if (IS_DEBUG_EVENTS)
zlog_debug("%s: unsupported media", __func__);
2012-03-24 16:35:20 +01:00
circuit->circ_type = CIRCUIT_T_UNKNOWN;
}
frr_each (if_connected, ifp->connected, conn)
isis_circuit_add_addr(circuit, conn);
2003-12-23 09:09:43 +01:00
}
2012-03-24 16:35:20 +01:00
void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
2003-12-23 09:09:43 +01:00
{
2012-03-24 16:35:20 +01:00
struct connected *conn;
2012-03-24 16:35:20 +01:00
assert(circuit->interface == ifp);
2012-03-24 16:35:20 +01:00
/* destroy addresses */
frr_each_safe (if_connected, ifp->connected, conn)
2012-03-24 16:35:20 +01:00
isis_circuit_del_addr(circuit, conn);
2012-03-24 16:35:20 +01:00
circuit->circ_type = CIRCUIT_T_UNKNOWN;
2003-12-23 09:09:43 +01:00
}
2012-03-24 16:35:20 +01:00
void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp)
{
assert(circuit != NULL);
assert(ifp != NULL);
if (circuit->interface)
assert(circuit->interface == ifp);
else
circuit->interface = ifp;
if (ifp->info)
assert(ifp->info == circuit);
else
ifp->info = circuit;
}
void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp)
2003-12-23 09:09:43 +01:00
{
2012-03-24 16:35:20 +01:00
assert(circuit != NULL);
assert(ifp != NULL);
assert(circuit->interface == ifp);
assert(ifp->info == circuit);
2003-12-23 09:09:43 +01:00
circuit->interface = NULL;
2012-03-24 16:35:20 +01:00
ifp->info = NULL;
}
2012-03-24 16:35:20 +01:00
static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit,
int is_set)
{
struct isis_area *area;
struct isis_lsp *lsp;
int level;
2012-03-24 16:35:20 +01:00
assert(circuit);
area = circuit->area;
assert(area);
for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
if (!(level & circuit->is_type))
continue;
if (!lspdb_count(&area->lspdb[level - 1]))
continue;
frr_each (lspdb, &area->lspdb[level - 1], lsp) {
if (is_set) {
isis_tx_queue_add(circuit->tx_queue, lsp,
TX_LSP_NORMAL);
} else {
isis_tx_queue_del(circuit->tx_queue, lsp);
2012-03-24 16:35:20 +01:00
}
}
}
2003-12-23 09:09:43 +01:00
}
size_t isis_circuit_pdu_size(struct isis_circuit *circuit)
{
return ISO_MTU(circuit);
}
static bool isis_circuit_lfa_enabled(struct isis_circuit *circuit, int level)
{
return (circuit->lfa_protection[level - 1] ||
circuit->rlfa_protection[level - 1] ||
circuit->tilfa_protection[level - 1]);
}
void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
union g_addr *nexthop_ip, ifindex_t ifindex)
{
char is_type;
if (!circuit->area)
return;
is_type = circuit->area->is_type;
if ((is_type == IS_LEVEL_1 || is_type == IS_LEVEL_1_AND_2) &&
isis_circuit_lfa_enabled(circuit, IS_LEVEL_1))
isis_area_switchover_routes(circuit->area, family, nexthop_ip,
ifindex, IS_LEVEL_1);
if ((is_type == IS_LEVEL_2 || is_type == IS_LEVEL_1_AND_2) &&
isis_circuit_lfa_enabled(circuit, IS_LEVEL_2))
isis_area_switchover_routes(circuit->area, family, nexthop_ip,
ifindex, IS_LEVEL_2);
}
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
{
size_t stream_size = isis_circuit_pdu_size(circuit);
if (!*stream) {
*stream = stream_new(stream_size);
} else {
if (STREAM_SIZE(*stream) != stream_size)
stream_resize_inplace(stream, stream_size);
stream_reset(*stream);
}
}
void isis_circuit_prepare(struct isis_circuit *circuit)
{
#if ISIS_METHOD != ISIS_METHOD_DLPI
event_add_read(master, isis_receive, circuit, circuit->fd,
&circuit->t_read);
#else
event_add_timer_msec(master, isis_receive, circuit,
listcount(circuit->area->circuit_list) * 100,
&circuit->t_read);
#endif
}
2003-12-23 09:09:43 +01:00
int isis_circuit_up(struct isis_circuit *circuit)
{
2012-03-24 16:35:20 +01:00
int retv;
2012-03-24 16:35:20 +01:00
/* Set the flags for all the lsps of the circuit. */
isis_circuit_update_all_srmflags(circuit, 1);
2012-03-24 16:35:20 +01:00
if (circuit->state == C_STATE_UP)
return ISIS_OK;
if (circuit->is_passive) {
circuit->last_uptime = time(NULL);
/* make sure the union fields are initialized, else we
* could end with garbage values from a previous circuit
* type, which would then cause a segfault when building
* LSPs or computing the SPF tree
*/
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
circuit->u.bc.adjdb[0] = list_new();
circuit->u.bc.adjdb[1] = list_new();
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
circuit->u.p2p.neighbor = NULL;
}
2012-03-24 16:35:20 +01:00
return ISIS_OK;
}
if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) {
flog_err(
EC_ISIS_CONFIG,
"Interface MTU %zu on %s is too low to support area lsp mtu %u!",
isis_circuit_pdu_size(circuit),
circuit->interface->name, circuit->area->lsp_mtu);
isisd: Fix crash in ISIS when mtu mismatch occurs When lsp-mtu is configured larger than interface mtu and the interface is brought up, the ISIS code would crash. When other vendors have this misconfiguration they just continue ISIS running and allow the LSP packets to be created but not sent. When the misconfiguration is corrected the LSP packets start being sent. This change creates that same behavior in FRR. The startup issue I am hitting is when the isis lsp-mtu is larger that the interfaces mtu. We run into this case when we are in the process of changing the mtu on a tunnel. I issue a shutdown/no shutdown on the interface, because the tunnel MTU is smaller than the lsp-mtu, it is considered an error and calls circuit_if_del. This deletes part of the circuit information, which includes the circuit->ip_addr list. Later on we get an address update from zebra and try to add the interface address to this list and crash. 2022/04/07 20:19:52.032 ISIS: [GTRPJ-X68CG] CSM_EVENT for tun_gw2: IF_UP_FROM_Z calls isis_circuit_if_add this initialize the circuit->ip_addrs isis_circuit_up has the mtu check circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit) and fails returns ISIS_ERROR on failure call isis_circuit_if_del this deletes the circiut->ip_addrs list <---- 2022/04/07 20:19:52.032 ZEBRA: [NXYHN-ZKW2V] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex 3, addr 192.168.0.1/24 message to isisd to add address isis_zebra_if_address_add isis_circuit_add_addr circuit->ip_addr we try to add the ip address to the list, but it was deleted above and isisd crashes Signed-off-by: Lynne Morrison <lynne.morrison@ibm.com>
2022-04-13 22:07:44 +02:00
/* Allow ISIS to continue configuration. With this
* configuration failure ISIS will attempt to send lsp
* packets but will fail until the mtu is configured properly
*/
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
circuit->circuit_id =
isis_circuit_id_gen(circuit->isis, circuit->interface);
if (!circuit->circuit_id) {
flog_err(
EC_ISIS_CONFIG,
"There are already 255 broadcast circuits active!");
return ISIS_ERROR;
}
2012-03-24 16:35:20 +01:00
/*
* Get the Hardware Address
*/
if (circuit->interface->hw_addr_len != ETH_ALEN) {
zlog_warn("unsupported link layer");
} else {
memcpy(circuit->u.bc.snpa, circuit->interface->hw_addr,
ETH_ALEN);
}
#ifdef EXTREME_DEGUG
if (IS_DEBUG_EVENTS)
zlog_debug("%s: if_id %d, isomtu %d snpa %pSY",
__func__, circuit->interface->ifindex,
ISO_MTU(circuit), circuit->u.bc.snpa);
2012-03-24 16:35:20 +01:00
#endif /* EXTREME_DEBUG */
circuit->u.bc.adjdb[0] = list_new();
circuit->u.bc.adjdb[1] = list_new();
/*
* ISO 10589 - 8.4.1 Enabling of broadcast circuits
*/
/* initilizing the hello sending threads
* for a broadcast IF
*/
/* 8.4.1 a) commence sending of IIH PDUs */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
if (!(circuit->is_type & level))
continue;
send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY);
circuit->u.bc.lan_neighs[level - 1] = list_new();
event_add_timer(master, isis_run_dr,
&circuit->level_arg[level - 1],
2 * circuit->hello_interval[level - 1],
&circuit->u.bc.t_run_dr[level - 1]);
2012-03-24 16:35:20 +01:00
}
/* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
/* 8.4.1 c) FIXME: listen for ESH PDUs */
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
/* initializing the hello send threads
* for a ptp IF
*/
2012-03-24 16:35:20 +01:00
circuit->u.p2p.neighbor = NULL;
send_hello_sched(circuit, 0, TRIGGERED_IIH_DELAY);
}
2003-12-23 09:09:43 +01:00
/* initializing PSNP timers */
2012-03-24 16:35:20 +01:00
if (circuit->is_type & IS_LEVEL_1)
event_add_timer(
master, send_l1_psnp, circuit,
isis_jitter(circuit->psnp_interval[0], PSNP_JITTER),
&circuit->t_send_psnp[0]);
2012-03-24 16:35:20 +01:00
if (circuit->is_type & IS_LEVEL_2)
event_add_timer(
master, send_l2_psnp, circuit,
isis_jitter(circuit->psnp_interval[1], PSNP_JITTER),
&circuit->t_send_psnp[1]);
2012-03-24 16:35:20 +01:00
/* unified init for circuits; ignore warnings below this level */
retv = isis_sock_init(circuit);
if (retv != ISIS_OK) {
isis_circuit_down(circuit);
return retv;
}
2012-03-24 16:35:20 +01:00
/* initialize the circuit streams after opening connection */
isis_circuit_stream(circuit, &circuit->rcv_stream);
isis_circuit_stream(circuit, &circuit->snd_stream);
isis_circuit_prepare(circuit);
circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp);
circuit->last_uptime = time(NULL);
if (circuit->area->mta && circuit->area->mta->status)
isis_link_params_update(circuit, circuit->interface);
isis_if_ldp_sync_enable(circuit);
#ifndef FABRICD
/* send northbound notification */
isis_notif_if_state_change(circuit, false);
#endif /* ifndef FABRICD */
2012-03-24 16:35:20 +01:00
return ISIS_OK;
2003-12-23 09:09:43 +01:00
}
void isis_circuit_down(struct isis_circuit *circuit)
{
#ifndef FABRICD
/* send northbound notification */
isis_notif_if_state_change(circuit, true);
#endif /* ifndef FABRICD */
isis_if_ldp_sync_disable(circuit);
/* log adjacency changes if configured to do so */
if (circuit->area->log_adj_changes) {
struct isis_adjacency *adj = NULL;
if (circuit->circ_type == CIRCUIT_T_P2P) {
adj = circuit->u.p2p.neighbor;
if (adj)
isis_log_adj_change(
adj, adj->adj_state, ISIS_ADJ_DOWN,
"circuit is being brought down");
} else if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
struct list *adj_list;
struct listnode *node;
if (circuit->u.bc.adjdb[0]) {
adj_list = list_new();
isis_adj_build_up_list(circuit->u.bc.adjdb[0],
adj_list);
for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj))
isis_log_adj_change(
adj, adj->adj_state,
ISIS_ADJ_DOWN,
"circuit is being brought down");
list_delete(&adj_list);
}
if (circuit->u.bc.adjdb[1]) {
adj_list = list_new();
isis_adj_build_up_list(circuit->u.bc.adjdb[1],
adj_list);
for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj))
isis_log_adj_change(
adj, adj->adj_state,
ISIS_ADJ_DOWN,
"circuit is being brought down");
list_delete(&adj_list);
}
}
}
2012-03-24 16:35:20 +01:00
/* Clear the flags for all the lsps of the circuit. */
isis_circuit_update_all_srmflags(circuit, 0);
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
2012-03-24 16:35:20 +01:00
/* destroy neighbour lists */
if (circuit->u.bc.lan_neighs[0]) {
list_delete(&circuit->u.bc.lan_neighs[0]);
2012-03-24 16:35:20 +01:00
circuit->u.bc.lan_neighs[0] = NULL;
}
if (circuit->u.bc.lan_neighs[1]) {
list_delete(&circuit->u.bc.lan_neighs[1]);
2012-03-24 16:35:20 +01:00
circuit->u.bc.lan_neighs[1] = NULL;
}
/* destroy adjacency databases */
if (circuit->u.bc.adjdb[0]) {
circuit->u.bc.adjdb[0]->del = isis_delete_adj;
list_delete(&circuit->u.bc.adjdb[0]);
2012-03-24 16:35:20 +01:00
circuit->u.bc.adjdb[0] = NULL;
}
if (circuit->u.bc.adjdb[1]) {
circuit->u.bc.adjdb[1]->del = isis_delete_adj;
list_delete(&circuit->u.bc.adjdb[1]);
2012-03-24 16:35:20 +01:00
circuit->u.bc.adjdb[1] = NULL;
}
if (circuit->u.bc.is_dr[0]) {
isis_dr_resign(circuit, 1);
circuit->u.bc.is_dr[0] = 0;
}
isisd: When the ISIS types of the routers do not match on a P2P link, the neighbor status remains UP Test Scenario: RouterA and RouterB are in the same routing domain and have configured a P2P link. RouterA is configured with "is-type level-1" while RouterB is configured with "is-type level-1-2". They establish a level-1 UP neighborship. In this scenario, we expect that when RouterB's configuration is switched to "is-type level-2-only", the neighborship status on both RouterA and RouterB would be non-UP. However, RouterB still shows the neighbor as UP. Upon receiving a P2P Hello packet, the function "process_p2p_hello" is invoked. According to the ISO/IEC 10589 protocol specification, section 8.2.5.2 a) and tables 5 and 7, if the "iih->circ_type" of the neighbor's hello packet does not match one's own "circuit->is_type," we may choose to take no action. When establishing a neighborship for the first time, the neighbor's status can remain in the "Initializing" state. However, if the neighborship has already been established and one's own "circuit->is_type" changes, the neighbor's UP status cannot be reset. Therefore, when processing P2P Hello packets, we should be cognizant of changes in our own link adjacency type. Topotest has identified a core issue during testing. (gdb) bt "#0 0xb7efe579 in __kernel_vsyscall () \#1 0xb79f62f7 in ?? () \#2 0xbf981dd0 in ?? () \#3 <signal handler called> \#4 0xb79f7722 in ?? () \#5 0xb7ed8634 in _DYNAMIC () from /home/z15467/isis_core/usr/lib/i386-linux-gnu/frr/libfrr.so.0.0.0 \#6 0x0001003c in ?? () \#7 0x00010000 in ?? () \#8 0xb7df3322 in _frr_mtx_lock (mutex=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/frr_pthread.h:255 \#9 event_timer_remain_msec (thread=0x10000) at ../lib/event.c:734 \#10 event_timer_remain_msec (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/event.c:727 \#11 0x004fb4aa in _send_hello_sched (circuit=<optimized out>, threadp=0x2189de0, level=1, delay=<optimized out>) at ../isisd/isis_pdu.c:2116 \#12 0x004e8dbc in isis_circuit_up (circuit=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_circuit.c:734 \#13 0x004ea8f7 in isis_csm_state_change (event=<optimized out>, circuit=<optimized out>, arg=<optimized out>) at ../isisd/isis_csm.c:98 \#14 0x004ea23f in isis_circuit_circ_type_set (circuit=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, circ_type=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_circuit.c:1578 \#15 0x0053aefa in lib_interface_isis_network_type_modify (args=<optimized out>) at ../isisd/isis_nb_config.c:4190 \#16 0xb7dbcc8d in nb_callback_modify (errmsg_len=8192, errmsg=0xbf982afc "", resource=0x2186220, dnode=<optimized out>, event=NB_EV_APPLY, nb_node=0x1fafe70, context=<optimized out>) at ../lib/northbound.c:1550 \#17 nb_callback_configuration (context=<optimized out>, event=NB_EV_APPLY, change=<optimized out>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1900 \#18 0xb7dbd646 in nb_transaction_process (errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, event=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:2028 \#19 nb_candidate_commit_apply (transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, save_transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction_id=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1368 \#20 0xb7dbdd68 in nb_candidate_commit (context=..., candidate=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, save_transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, comment=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction_id=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1401 \#21 0xb7dc0cff in nb_cli_classic_commit (vty=vty@entry=0x21d6940) at ../lib/northbound_cli.c:57 \#22 0xb7dc0f46 in nb_cli_apply_changes_internal (vty=vty@entry=0x21d6940, xpath_base=xpath_base@entry=0xbf986b7c "/frr-interface:lib/interface[name='r5-eth0']", clear_pending=clear_pending@entry=false) at ../lib/northbound_cli.c:184 \#23 0xb7dc130b in nb_cli_apply_changes (vty=<optimized out>, xpath_base_fmt=<optimized out>) at ../lib/northbound_cli.c:240 \#24 0x00542c1d in isis_network_magic (self=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argc=<optimized out>, argv=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, no=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_cli.c:3101 \#25 isis_network (self=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argc=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argv=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ./isisd/isis_cli_clippy.c:5499 \#26 0xb7d6d8f1 in cmd_execute_command_real (vline=vline@entry=0x219afa0, vty=vty@entry=0x21d6940, cmd=cmd@entry=0x0, up_level=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1003 \#27 0xb7d6d9e0 in cmd_execute_command (vline=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, cmd=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vtysh=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1061 \#28 0xb7d6dc60 in cmd_execute (vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, cmd=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, matched=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vtysh=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1228 \#29 0xb7dfb58a in vty_command (vty=vty@entry=0x21d6940, buf=0x21e0ff0 ' ' <repeats 12 times>, "isis network point-to-point") at ../lib/vty.c:625 \#30 0xb7dfc560 in vty_execute (vty=vty@entry=0x21d6940) at ../lib/vty.c:1388 \#31 0xb7dfdc8d in vtysh_read (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/vty.c:2400 \#32 0xb7df4d47 in event_call (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/event.c:2019 \#33 0xb7d9a831 in frr_run (master=<optimized out>) at ../lib/libfrr.c:1232 \#34 0x004e4758 in main (argc=7, argv=0xbf989a24, envp=0xbf989a44) at ../isisd/isis_main.c:354 (gdb) f 9 \#9 event_timer_remain_msec (thread=0x10000) at ../lib/event.c:734 734 ../lib/event.c: No such file or directory. (gdb) p pthread No symbol "pthread" in current context. (gdb) p thread $1 = (struct event *) 0x10000 When LAN links and P2P links share the` circuit->u` of a neighbor, if one link is no longer in use and the union is not cleared, the other link is unable to pass the non-empty check, resulting in accessing an invalid pointer. Unfortunately, for non-DIS devices in LAN links, `circuit->u.bc.run_dr_elect[x]` is essentially always 1, but in `isis_circuit_down()`,` circuit->u.bc.run_dr_elect[x] `will not be cleared because `circuit->u.bc.is_dr[x]` is always 0. Consequently, when switching to a P2P link, `isis_circuit_circ_type_set()` does not reset the link in a non-C_STATE_UP state, leading to subsequent accesses of `circuit->u.p2p.t_send_p2p_hello` resulting in a non-empty yet invalid address. I believe that in `isis_circuit_down()`, the LAN link should unconditionally clear `circuit->u.bc.run_dr_elect[x]`. Signed-off-by: zhou-run <zhou.run@h3c.com>
2024-10-24 05:09:37 +02:00
circuit->u.bc.run_dr_elect[0] = 0;
2012-03-24 16:35:20 +01:00
memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
if (circuit->u.bc.is_dr[1]) {
isis_dr_resign(circuit, 2);
circuit->u.bc.is_dr[1] = 0;
}
isisd: When the ISIS types of the routers do not match on a P2P link, the neighbor status remains UP Test Scenario: RouterA and RouterB are in the same routing domain and have configured a P2P link. RouterA is configured with "is-type level-1" while RouterB is configured with "is-type level-1-2". They establish a level-1 UP neighborship. In this scenario, we expect that when RouterB's configuration is switched to "is-type level-2-only", the neighborship status on both RouterA and RouterB would be non-UP. However, RouterB still shows the neighbor as UP. Upon receiving a P2P Hello packet, the function "process_p2p_hello" is invoked. According to the ISO/IEC 10589 protocol specification, section 8.2.5.2 a) and tables 5 and 7, if the "iih->circ_type" of the neighbor's hello packet does not match one's own "circuit->is_type," we may choose to take no action. When establishing a neighborship for the first time, the neighbor's status can remain in the "Initializing" state. However, if the neighborship has already been established and one's own "circuit->is_type" changes, the neighbor's UP status cannot be reset. Therefore, when processing P2P Hello packets, we should be cognizant of changes in our own link adjacency type. Topotest has identified a core issue during testing. (gdb) bt "#0 0xb7efe579 in __kernel_vsyscall () \#1 0xb79f62f7 in ?? () \#2 0xbf981dd0 in ?? () \#3 <signal handler called> \#4 0xb79f7722 in ?? () \#5 0xb7ed8634 in _DYNAMIC () from /home/z15467/isis_core/usr/lib/i386-linux-gnu/frr/libfrr.so.0.0.0 \#6 0x0001003c in ?? () \#7 0x00010000 in ?? () \#8 0xb7df3322 in _frr_mtx_lock (mutex=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/frr_pthread.h:255 \#9 event_timer_remain_msec (thread=0x10000) at ../lib/event.c:734 \#10 event_timer_remain_msec (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/event.c:727 \#11 0x004fb4aa in _send_hello_sched (circuit=<optimized out>, threadp=0x2189de0, level=1, delay=<optimized out>) at ../isisd/isis_pdu.c:2116 \#12 0x004e8dbc in isis_circuit_up (circuit=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_circuit.c:734 \#13 0x004ea8f7 in isis_csm_state_change (event=<optimized out>, circuit=<optimized out>, arg=<optimized out>) at ../isisd/isis_csm.c:98 \#14 0x004ea23f in isis_circuit_circ_type_set (circuit=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, circ_type=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_circuit.c:1578 \#15 0x0053aefa in lib_interface_isis_network_type_modify (args=<optimized out>) at ../isisd/isis_nb_config.c:4190 \#16 0xb7dbcc8d in nb_callback_modify (errmsg_len=8192, errmsg=0xbf982afc "", resource=0x2186220, dnode=<optimized out>, event=NB_EV_APPLY, nb_node=0x1fafe70, context=<optimized out>) at ../lib/northbound.c:1550 \#17 nb_callback_configuration (context=<optimized out>, event=NB_EV_APPLY, change=<optimized out>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1900 \#18 0xb7dbd646 in nb_transaction_process (errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, event=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:2028 \#19 nb_candidate_commit_apply (transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, save_transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction_id=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1368 \#20 0xb7dbdd68 in nb_candidate_commit (context=..., candidate=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, save_transaction=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, comment=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, transaction_id=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, errmsg_len=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/northbound.c:1401 \#21 0xb7dc0cff in nb_cli_classic_commit (vty=vty@entry=0x21d6940) at ../lib/northbound_cli.c:57 \#22 0xb7dc0f46 in nb_cli_apply_changes_internal (vty=vty@entry=0x21d6940, xpath_base=xpath_base@entry=0xbf986b7c "/frr-interface:lib/interface[name='r5-eth0']", clear_pending=clear_pending@entry=false) at ../lib/northbound_cli.c:184 \#23 0xb7dc130b in nb_cli_apply_changes (vty=<optimized out>, xpath_base_fmt=<optimized out>) at ../lib/northbound_cli.c:240 \#24 0x00542c1d in isis_network_magic (self=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argc=<optimized out>, argv=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, no=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../isisd/isis_cli.c:3101 \#25 isis_network (self=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argc=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, argv=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ./isisd/isis_cli_clippy.c:5499 \#26 0xb7d6d8f1 in cmd_execute_command_real (vline=vline@entry=0x219afa0, vty=vty@entry=0x21d6940, cmd=cmd@entry=0x0, up_level=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1003 \#27 0xb7d6d9e0 in cmd_execute_command (vline=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, cmd=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vtysh=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1061 \#28 0xb7d6dc60 in cmd_execute (vty=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, cmd=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, matched=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>, vtysh=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/command.c:1228 \#29 0xb7dfb58a in vty_command (vty=vty@entry=0x21d6940, buf=0x21e0ff0 ' ' <repeats 12 times>, "isis network point-to-point") at ../lib/vty.c:625 \#30 0xb7dfc560 in vty_execute (vty=vty@entry=0x21d6940) at ../lib/vty.c:1388 \#31 0xb7dfdc8d in vtysh_read (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/vty.c:2400 \#32 0xb7df4d47 in event_call (thread=<error reading variable: dwarf2_find_location_expression: Corrupted DWARF expression.>) at ../lib/event.c:2019 \#33 0xb7d9a831 in frr_run (master=<optimized out>) at ../lib/libfrr.c:1232 \#34 0x004e4758 in main (argc=7, argv=0xbf989a24, envp=0xbf989a44) at ../isisd/isis_main.c:354 (gdb) f 9 \#9 event_timer_remain_msec (thread=0x10000) at ../lib/event.c:734 734 ../lib/event.c: No such file or directory. (gdb) p pthread No symbol "pthread" in current context. (gdb) p thread $1 = (struct event *) 0x10000 When LAN links and P2P links share the` circuit->u` of a neighbor, if one link is no longer in use and the union is not cleared, the other link is unable to pass the non-empty check, resulting in accessing an invalid pointer. Unfortunately, for non-DIS devices in LAN links, `circuit->u.bc.run_dr_elect[x]` is essentially always 1, but in `isis_circuit_down()`,` circuit->u.bc.run_dr_elect[x] `will not be cleared because `circuit->u.bc.is_dr[x]` is always 0. Consequently, when switching to a P2P link, `isis_circuit_circ_type_set()` does not reset the link in a non-C_STATE_UP state, leading to subsequent accesses of `circuit->u.p2p.t_send_p2p_hello` resulting in a non-empty yet invalid address. I believe that in `isis_circuit_down()`, the LAN link should unconditionally clear `circuit->u.bc.run_dr_elect[x]`. Signed-off-by: zhou-run <zhou.run@h3c.com>
2024-10-24 05:09:37 +02:00
circuit->u.bc.run_dr_elect[1] = 0;
2012-03-24 16:35:20 +01:00
memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
memset(circuit->u.bc.snpa, 0, ETH_ALEN);
EVENT_OFF(circuit->u.bc.t_send_lan_hello[0]);
EVENT_OFF(circuit->u.bc.t_send_lan_hello[1]);
EVENT_OFF(circuit->u.bc.t_run_dr[0]);
EVENT_OFF(circuit->u.bc.t_run_dr[1]);
EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[0]);
EVENT_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]);
circuit->lsp_regenerate_pending[0] = 0;
circuit->lsp_regenerate_pending[1] = 0;
_ISIS_CLEAR_FLAG(circuit->isis->circuit_ids_used,
circuit->circuit_id);
circuit->circuit_id = 0;
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
2012-03-24 16:35:20 +01:00
isis_delete_adj(circuit->u.p2p.neighbor);
circuit->u.p2p.neighbor = NULL;
EVENT_OFF(circuit->u.p2p.t_send_p2p_hello);
}
/*
* All adjacencies have to be gone, delete snmp list
* and reset snmpd idx generator
*/
if (circuit->snmp_adj_list != NULL)
list_delete(&circuit->snmp_adj_list);
circuit->snmp_adj_idx_gen = 0;
2012-03-24 16:35:20 +01:00
/* Cancel all active threads */
EVENT_OFF(circuit->t_send_csnp[0]);
EVENT_OFF(circuit->t_send_csnp[1]);
EVENT_OFF(circuit->t_send_psnp[0]);
EVENT_OFF(circuit->t_send_psnp[1]);
EVENT_OFF(circuit->t_read);
if (circuit->tx_queue) {
isis_tx_queue_free(circuit->tx_queue);
circuit->tx_queue = NULL;
}
2012-03-24 16:35:20 +01:00
/* send one gratuitous hello to spead up convergence */
if (circuit->state == C_STATE_UP) {
if (circuit->is_type & IS_LEVEL_1)
send_hello(circuit, IS_LEVEL_1);
if (circuit->is_type & IS_LEVEL_2)
send_hello(circuit, IS_LEVEL_2);
}
2012-03-24 16:35:20 +01:00
circuit->upadjcount[0] = 0;
circuit->upadjcount[1] = 0;
2003-12-23 09:09:43 +01:00
/* close the socket */
2012-03-24 16:35:20 +01:00
if (circuit->fd) {
close(circuit->fd);
circuit->fd = 0;
}
2012-03-24 16:35:20 +01:00
if (circuit->rcv_stream != NULL) {
stream_free(circuit->rcv_stream);
circuit->rcv_stream = NULL;
}
2012-03-24 16:35:20 +01:00
if (circuit->snd_stream != NULL) {
stream_free(circuit->snd_stream);
circuit->snd_stream = NULL;
}
event_cancel_event(master, circuit);
2003-12-23 09:09:43 +01:00
return;
}
void circuit_update_nlpids(struct isis_circuit *circuit)
{
circuit->nlpids.count = 0;
if (circuit->ip_router) {
circuit->nlpids.nlpids[0] = NLPID_IP;
circuit->nlpids.count++;
}
if (circuit->ipv6_router) {
circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
circuit->nlpids.count++;
}
2003-12-23 09:09:43 +01:00
return;
}
void isis_circuit_print_json(struct isis_circuit *circuit,
struct json_object *json, char detail)
{
int level;
json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
*ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json,
*level_json;
char buf_prx[INET6_BUFSIZ];
char buf[255];
snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id);
if (detail == ISIS_UI_LEVEL_BRIEF) {
iface_json = json_object_new_object();
json_object_object_add(json, "interface", iface_json);
json_object_string_add(iface_json, "name",
circuit->interface->name);
json_object_string_add(iface_json, "circuit-id", buf);
json_object_string_add(iface_json, "state",
circuit_state2string(circuit->state));
json_object_string_add(iface_json, "type",
circuit_type2string(circuit->circ_type));
json_object_string_add(iface_json, "level",
circuit_t2string(circuit->is_type));
}
if (detail == ISIS_UI_LEVEL_DETAIL) {
struct listnode *node;
struct prefix *ip_addr;
iface_json = json_object_new_object();
json_object_object_add(json, "interface", iface_json);
json_object_string_add(iface_json, "name",
circuit->interface->name);
json_object_string_add(iface_json, "state",
circuit_state2string(circuit->state));
if (circuit->is_passive)
json_object_string_add(iface_json, "is-passive",
"passive");
else
json_object_string_add(iface_json, "is-passive",
"active");
json_object_string_add(iface_json, "circuit-id", buf);
json_object_string_add(iface_json, "type",
circuit_type2string(circuit->circ_type));
json_object_string_add(iface_json, "level",
circuit_t2string(circuit->is_type));
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
json_object_string_addf(iface_json, "snpa", "%pSY",
circuit->u.bc.snpa);
levels_json = json_object_new_array();
json_object_object_add(iface_json, "levels", levels_json);
for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
if ((circuit->is_type & level) == 0)
continue;
level_json = json_object_new_object();
json_object_string_add(level_json, "level",
circuit_t2string(level));
if (circuit->area->newmetric)
json_object_int_add(level_json, "metric",
circuit->te_metric[0]);
else
json_object_int_add(level_json, "metric",
circuit->metric[0]);
if (!circuit->is_passive) {
json_object_int_add(level_json,
"active-neighbors",
circuit->upadjcount[0]);
json_object_int_add(level_json,
"hello-interval",
circuit->hello_interval[0]);
hold_json = json_object_new_object();
json_object_object_add(level_json, "holddown",
hold_json);
json_object_int_add(
hold_json, "count",
circuit->hello_multiplier[0]);
json_object_string_add(
hold_json, "pad",
isis_hello_padding2string(
circuit->pad_hellos));
json_object_int_add(level_json, "cnsp-interval",
circuit->csnp_interval[0]);
json_object_int_add(level_json, "psnp-interval",
circuit->psnp_interval[0]);
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
lan_prio_json =
json_object_new_object();
json_object_object_add(level_json,
"lan",
lan_prio_json);
json_object_int_add(
lan_prio_json, "priority",
circuit->priority[0]);
json_object_string_add(
lan_prio_json, "is-dis",
(circuit->u.bc.is_dr[0]
? "yes"
: "no"));
}
}
json_object_array_add(levels_json, level_json);
}
if (listcount(circuit->ip_addrs) > 0) {
ipv4_addr_json = json_object_new_object();
json_object_object_add(iface_json, "ip-prefix",
ipv4_addr_json);
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
ip_addr)) {
snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
ip_addr);
json_object_string_add(ipv4_addr_json, "ip",
buf_prx);
}
}
if (listcount(circuit->ipv6_link) > 0) {
ipv6_link_json = json_object_new_object();
json_object_object_add(iface_json, "ipv6-link-locals",
ipv6_link_json);
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
ip_addr)) {
snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
ip_addr);
json_object_string_add(ipv6_link_json, "ipv6",
buf_prx);
}
}
if (listcount(circuit->ipv6_non_link) > 0) {
ipv6_non_link_json = json_object_new_object();
json_object_object_add(iface_json, "ipv6-prefixes",
ipv6_non_link_json);
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
ip_addr)) {
snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
ip_addr);
json_object_string_add(ipv6_non_link_json,
"ipv6", buf_prx);
}
}
}
return;
}
2012-03-24 16:35:20 +01:00
void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
char detail)
{
if (detail == ISIS_UI_LEVEL_BRIEF) {
vty_out(vty, " %-12s", circuit->interface->name);
vty_out(vty, "0x%-7x", circuit->circuit_id);
vty_out(vty, "%-9s", circuit_state2string(circuit->state));
vty_out(vty, "%-9s", circuit_type2string(circuit->circ_type));
vty_out(vty, "%-9s", circuit_t2string(circuit->is_type));
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
}
2012-03-24 16:35:20 +01:00
if (detail == ISIS_UI_LEVEL_DETAIL) {
struct listnode *node;
struct prefix *ip_addr;
2012-03-24 16:35:20 +01:00
vty_out(vty, " Interface: %s", circuit->interface->name);
vty_out(vty, ", State: %s",
circuit_state2string(circuit->state));
if (circuit->is_passive)
vty_out(vty, ", Passive");
else
vty_out(vty, ", Active");
vty_out(vty, ", Circuit Id: 0x%x", circuit->circuit_id);
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
vty_out(vty, " Type: %s",
circuit_type2string(circuit->circ_type));
vty_out(vty, ", Level: %s", circuit_t2string(circuit->is_type));
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
vty_out(vty, ", SNPA: %-10pSY", circuit->u.bc.snpa);
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
if (circuit->is_type & IS_LEVEL_1) {
vty_out(vty, " Level-1 Information:\n");
2012-03-24 16:35:20 +01:00
if (circuit->area->newmetric)
vty_out(vty, " Metric: %d",
circuit->te_metric[0]);
else
vty_out(vty, " Metric: %d",
circuit->metric[0]);
2012-03-24 16:35:20 +01:00
if (!circuit->is_passive) {
vty_out(vty, ", Active neighbors: %u\n",
circuit->upadjcount[0]);
vty_out(vty,
" Hello interval: %u, Holddown count: %u, Padding: %s\n",
2012-03-24 16:35:20 +01:00
circuit->hello_interval[0],
circuit->hello_multiplier[0],
isis_hello_padding2string(
circuit->pad_hellos));
vty_out(vty,
" CNSP interval: %u, PSNP interval: %u\n",
2012-03-24 16:35:20 +01:00
circuit->csnp_interval[0],
circuit->psnp_interval[0]);
2012-03-24 16:35:20 +01:00
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
vty_out(vty,
" LAN Priority: %u, %s\n",
2012-03-24 16:35:20 +01:00
circuit->priority[0],
(circuit->u.bc.is_dr[0]
? "is DIS"
: "is not DIS"));
2012-03-24 16:35:20 +01:00
} else {
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
}
}
2012-03-24 16:35:20 +01:00
if (circuit->is_type & IS_LEVEL_2) {
vty_out(vty, " Level-2 Information:\n");
2012-03-24 16:35:20 +01:00
if (circuit->area->newmetric)
vty_out(vty, " Metric: %d",
circuit->te_metric[1]);
else
vty_out(vty, " Metric: %d",
circuit->metric[1]);
2012-03-24 16:35:20 +01:00
if (!circuit->is_passive) {
vty_out(vty, ", Active neighbors: %u\n",
circuit->upadjcount[1]);
vty_out(vty,
" Hello interval: %u, Holddown count: %u, Padding: %s\n",
2012-03-24 16:35:20 +01:00
circuit->hello_interval[1],
circuit->hello_multiplier[1],
isis_hello_padding2string(
circuit->pad_hellos));
vty_out(vty,
" CNSP interval: %u, PSNP interval: %u\n",
2012-03-24 16:35:20 +01:00
circuit->csnp_interval[1],
circuit->psnp_interval[1]);
2012-03-24 16:35:20 +01:00
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
vty_out(vty,
" LAN Priority: %u, %s\n",
2012-03-24 16:35:20 +01:00
circuit->priority[1],
(circuit->u.bc.is_dr[1]
? "is DIS"
: "is not DIS"));
2012-03-24 16:35:20 +01:00
} else {
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
}
}
if (listcount(circuit->ip_addrs) > 0) {
vty_out(vty, " IP Prefix(es):\n");
2012-03-24 16:35:20 +01:00
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
ip_addr))
vty_out(vty, " %pFX\n", ip_addr);
}
if (listcount(circuit->ipv6_link) > 0) {
vty_out(vty, " IPv6 Link-Locals:\n");
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
ip_addr))
vty_out(vty, " %pFX\n", ip_addr);
}
if (listcount(circuit->ipv6_non_link) > 0) {
vty_out(vty, " IPv6 Prefixes:\n");
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
ip_addr))
vty_out(vty, " %pFX\n", ip_addr);
}
vty_out(vty, "\n");
2012-03-24 16:35:20 +01:00
}
return;
}
#ifdef FABRICD
DEFINE_HOOK(isis_circuit_config_write,
(struct isis_circuit *circuit, struct vty *vty),
(circuit, vty));
static int isis_interface_config_write(struct vty *vty)
2003-12-23 09:09:43 +01:00
{
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2003-12-23 09:09:43 +01:00
int write = 0;
struct interface *ifp;
2012-03-24 16:35:20 +01:00
struct isis_circuit *circuit;
2003-12-23 09:09:43 +01:00
int i;
FOR_ALL_INTERFACES (vrf, ifp) {
2012-03-24 16:35:20 +01:00
/* IF name */
if_vty_config_start(vty, ifp);
2012-03-24 16:35:20 +01:00
write++;
/* IF desc */
if (ifp->desc) {
vty_out(vty, " description %s\n", ifp->desc);
2012-03-24 16:35:20 +01:00
write++;
}
/* ISIS Circuit */
do {
circuit = circuit_scan_by_ifp(ifp);
2012-03-24 16:35:20 +01:00
if (circuit == NULL)
break;
2012-03-24 16:35:20 +01:00
if (circuit->ip_router) {
vty_out(vty, " ip router " PROTO_NAME " %s\n",
circuit->tag);
2012-03-24 16:35:20 +01:00
write++;
}
if (circuit->is_passive) {
vty_out(vty, " " PROTO_NAME " passive\n");
2012-03-24 16:35:20 +01:00
write++;
}
if (circuit->circ_type_config == CIRCUIT_T_P2P) {
vty_out(vty, " " PROTO_NAME " network point-to-point\n");
2012-03-24 16:35:20 +01:00
write++;
}
if (circuit->ipv6_router) {
vty_out(vty, " ipv6 router " PROTO_NAME " %s\n",
circuit->tag);
2012-03-24 16:35:20 +01:00
write++;
}
2012-03-24 16:35:20 +01:00
/* ISIS - circuit type */
if (!fabricd) {
if (circuit->is_type == IS_LEVEL_1) {
vty_out(vty, " " PROTO_NAME " circuit-type level-1\n");
2012-03-24 16:35:20 +01:00
write++;
} else {
if (circuit->is_type == IS_LEVEL_2) {
vty_out(vty,
" " PROTO_NAME " circuit-type level-2-only\n");
write++;
}
}
2012-03-24 16:35:20 +01:00
}
2012-03-24 16:35:20 +01:00
/* ISIS - CSNP interval */
if (circuit->csnp_interval[0]
== circuit->csnp_interval[1]) {
if (circuit->csnp_interval[0]
!= DEFAULT_CSNP_INTERVAL) {
vty_out(vty, " " PROTO_NAME " csnp-interval %d\n",
circuit->csnp_interval[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->csnp_interval[i]
!= DEFAULT_CSNP_INTERVAL) {
vty_out(vty,
" " PROTO_NAME " csnp-interval %d level-%d\n",
circuit->csnp_interval
[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
2012-03-24 16:35:20 +01:00
}
2012-03-24 16:35:20 +01:00
/* ISIS - PSNP interval */
if (circuit->psnp_interval[0]
== circuit->psnp_interval[1]) {
if (circuit->psnp_interval[0]
!= DEFAULT_PSNP_INTERVAL) {
vty_out(vty, " " PROTO_NAME " psnp-interval %d\n",
circuit->psnp_interval[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->psnp_interval[i]
!= DEFAULT_PSNP_INTERVAL) {
vty_out(vty,
" " PROTO_NAME " psnp-interval %d level-%d\n",
circuit->psnp_interval
[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
2012-03-24 16:35:20 +01:00
}
/* ISIS - Hello padding - Defaults to always so only
* display if not always */
switch (circuit->pad_hellos) {
case ISIS_HELLO_PADDING_DISABLED:
vty_out(vty, " no " PROTO_NAME " hello padding\n");
2012-03-24 16:35:20 +01:00
write++;
break;
case ISIS_HELLO_PADDING_DURING_ADJACENCY_FORMATION:
vty_out(vty, PROTO_NAME
" hello padding during-adjacency-formation\n");
write++;
break;
case ISIS_HELLO_PADDING_ALWAYS:
break;
2012-03-24 16:35:20 +01:00
}
if (circuit->disable_threeway_adj) {
vty_out(vty, " no isis three-way-handshake\n");
write++;
}
2012-03-24 16:35:20 +01:00
/* ISIS - Hello interval */
if (circuit->hello_interval[0]
== circuit->hello_interval[1]) {
if (circuit->hello_interval[0]
!= DEFAULT_HELLO_INTERVAL) {
vty_out(vty,
" " PROTO_NAME " hello-interval %d\n",
circuit->hello_interval[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->hello_interval[i]
!= DEFAULT_HELLO_INTERVAL) {
vty_out(vty,
" " PROTO_NAME " hello-interval %d level-%d\n",
circuit->hello_interval
[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
}
2012-03-24 16:35:20 +01:00
/* ISIS - Hello Multiplier */
if (circuit->hello_multiplier[0]
== circuit->hello_multiplier[1]) {
if (circuit->hello_multiplier[0]
!= DEFAULT_HELLO_MULTIPLIER) {
vty_out(vty,
" " PROTO_NAME " hello-multiplier %d\n",
circuit->hello_multiplier[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->hello_multiplier[i]
!= DEFAULT_HELLO_MULTIPLIER) {
vty_out(vty,
" " PROTO_NAME " hello-multiplier %d level-%d\n",
circuit->hello_multiplier
[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
}
2012-03-24 16:35:20 +01:00
/* ISIS - Priority */
if (circuit->priority[0] == circuit->priority[1]) {
if (circuit->priority[0] != DEFAULT_PRIORITY) {
vty_out(vty, " " PROTO_NAME " priority %d\n",
circuit->priority[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->priority[i]
!= DEFAULT_PRIORITY) {
vty_out(vty,
" " PROTO_NAME " priority %d level-%d\n",
circuit->priority[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
}
2012-03-24 16:35:20 +01:00
/* ISIS - Metric */
if (circuit->te_metric[0] == circuit->te_metric[1]) {
if (circuit->te_metric[0]
!= DEFAULT_CIRCUIT_METRIC) {
vty_out(vty, " " PROTO_NAME " metric %d\n",
circuit->te_metric[0]);
2012-03-24 16:35:20 +01:00
write++;
}
} else {
for (i = 0; i < 2; i++) {
if (circuit->te_metric[i]
!= DEFAULT_CIRCUIT_METRIC) {
vty_out(vty,
" " PROTO_NAME " metric %d level-%d\n",
circuit->te_metric[i],
i + 1);
2012-03-24 16:35:20 +01:00
write++;
}
}
}
2012-03-24 16:35:20 +01:00
if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) {
vty_out(vty, " " PROTO_NAME " password md5 %s\n",
circuit->passwd.passwd);
2012-03-24 16:35:20 +01:00
write++;
} else if (circuit->passwd.type
== ISIS_PASSWD_TYPE_CLEARTXT) {
vty_out(vty, " " PROTO_NAME " password clear %s\n",
circuit->passwd.passwd);
2012-03-24 16:35:20 +01:00
write++;
}
if (circuit->bfd_config.enabled) {
vty_out(vty, " " PROTO_NAME " bfd\n");
write++;
}
2018-10-12 16:45:32 +02:00
write += hook_call(isis_circuit_config_write,
circuit, vty);
} while (0);
if_vty_config_end(vty);
2003-12-23 09:09:43 +01:00
}
2003-12-23 09:09:43 +01:00
return write;
}
#endif /* ifdef FABRICD */
2003-12-23 09:09:43 +01:00
void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
bool ipv6_router)
2003-12-23 09:09:43 +01:00
{
struct isis_area *area = circuit->area;
int old_ipr = circuit->ip_router;
int old_ipv6r = circuit->ipv6_router;
/* is there something to do? */
if (old_ipr == ip_router && old_ipv6r == ipv6_router)
return;
circuit->ip_router = ip_router;
circuit->ipv6_router = ipv6_router;
circuit_update_nlpids(circuit);
if (area) {
area->ip_circuits += ip_router - old_ipr;
area->ipv6_circuits += ipv6_router - old_ipv6r;
if (ip_router || ipv6_router)
lsp_regenerate_schedule(area, circuit->is_type, 0);
}
2012-03-24 16:35:20 +01:00
}
2003-12-23 09:09:43 +01:00
ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive)
2012-03-24 16:35:20 +01:00
{
if (circuit->is_passive == passive)
return ferr_ok();
if (if_is_loopback(circuit->interface) && !passive)
return ferr_cfg_invalid("loopback is always passive");
2012-03-24 16:35:20 +01:00
if (circuit->state != C_STATE_UP) {
circuit->is_passive = passive;
} else {
2012-03-24 16:35:20 +01:00
struct isis_area *area = circuit->area;
isis_csm_state_change(ISIS_DISABLE, circuit, area);
circuit->is_passive = passive;
2012-03-24 16:35:20 +01:00
isis_csm_state_change(ISIS_ENABLE, circuit, area);
}
return ferr_ok();
2003-12-23 09:09:43 +01:00
}
ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
int metric)
2012-03-24 16:35:20 +01:00
{
assert(level == IS_LEVEL_1 || level == IS_LEVEL_2);
if (metric > MAX_WIDE_LINK_METRIC)
return ferr_cfg_invalid("metric %d too large for wide metric",
metric);
if (circuit->area && circuit->area->oldmetric
&& metric > MAX_NARROW_LINK_METRIC)
return ferr_cfg_invalid("metric %d too large for narrow metric",
metric);
/* Don't modify metric if advertise high metrics is configured */
if (circuit->area && circuit->area->advertise_high_metrics)
return ferr_ok();
/* inform ldp-sync of metric change
* if ldp-sync is running need to save metric
* and restore new values after ldp-sync completion.
*/
if (isis_ldp_sync_if_metric_config(circuit, level, metric)) {
circuit->te_metric[level - 1] = metric;
circuit->metric[level - 1] = metric;
if (circuit->area)
lsp_regenerate_schedule(circuit->area, level, 0);
}
return ferr_ok();
2003-12-23 09:09:43 +01:00
}
ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit)
2003-12-23 09:09:43 +01:00
{
memset(&circuit->passwd, 0, sizeof(circuit->passwd));
return ferr_ok();
2012-03-24 16:35:20 +01:00
}
ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit,
uint8_t passwd_type, const char *passwd)
2012-03-24 16:35:20 +01:00
{
int len;
if (!passwd)
return ferr_code_bug("no circuit password given");
len = strlen(passwd);
if (len > 254)
return ferr_code_bug(
"circuit password too long (max 254 chars)");
circuit->passwd.len = len;
strlcpy((char *)circuit->passwd.passwd, passwd,
sizeof(circuit->passwd.passwd));
circuit->passwd.type = passwd_type;
return ferr_ok();
2003-12-23 09:09:43 +01:00
}
ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit,
const char *passwd)
2003-12-23 09:09:43 +01:00
{
return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_CLEARTXT,
passwd);
}
ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit,
const char *passwd)
{
return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_HMAC_MD5,
passwd);
2003-12-23 09:09:43 +01:00
}
void isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
2012-03-24 16:35:20 +01:00
{
if (circuit->circ_type == circ_type)
return;
2012-03-24 16:35:20 +01:00
if (circuit->state != C_STATE_UP) {
circuit->circ_type = circ_type;
circuit->circ_type_config = circ_type;
2012-03-24 16:35:20 +01:00
} else {
struct isis_area *area = circuit->area;
isis_csm_state_change(ISIS_DISABLE, circuit, area);
circuit->circ_type = circ_type;
circuit->circ_type_config = circ_type;
isis_csm_state_change(ISIS_ENABLE, circuit, area);
2012-03-24 16:35:20 +01:00
}
}
int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid,
bool enabled)
{
struct isis_circuit_mt_setting *setting;
setting = circuit_get_mt_setting(circuit, mtid);
if (setting->enabled != enabled) {
setting->enabled = enabled;
if (circuit->area)
lsp_regenerate_schedule(circuit->area,
IS_LEVEL_1 | IS_LEVEL_2, 0);
}
return CMD_SUCCESS;
}
2003-12-23 09:09:43 +01:00
int isis_if_new_hook(struct interface *ifp)
{
return 0;
}
int isis_if_delete_hook(struct interface *ifp)
{
if (ifp->info)
isis_circuit_del(ifp->info);
2003-12-23 09:09:43 +01:00
return 0;
}
static int isis_ifp_create(struct interface *ifp)
{
struct isis_circuit *circuit = ifp->info;
if (circuit)
isis_circuit_enable(circuit);
hook_call(isis_if_new_hook, ifp);
return 0;
}
static int isis_ifp_up(struct interface *ifp)
{
struct isis_circuit *circuit = ifp->info;
if (circuit) {
UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z);
isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
}
/* Notify SRv6 that the interface went up */
isis_srv6_ifp_up_notify(ifp);
return 0;
}
static int isis_ifp_down(struct interface *ifp)
{
afi_t afi;
struct isis_circuit *circuit = ifp->info;
if (circuit &&
!CHECK_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z)) {
SET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z);
for (afi = AFI_IP; afi <= AFI_IP6; afi++)
isis_circuit_switchover_routes(
circuit, afi == AFI_IP ? AF_INET : AF_INET6,
NULL, ifp->ifindex);
isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
}
return 0;
}
static int isis_ifp_destroy(struct interface *ifp)
{
struct isis_circuit *circuit = ifp->info;
if (circuit)
isis_circuit_disable(circuit);
return 0;
}
void isis_circuit_init(void)
2003-12-23 09:09:43 +01:00
{
/* Initialize Zebra interface data structure */
hook_register_prio(if_add, 0, isis_if_new_hook);
hook_register_prio(if_del, 0, isis_if_delete_hook);
2003-12-23 09:09:43 +01:00
/* Install interface node */
#ifdef FABRICD
if_cmd_init(isis_interface_config_write);
#else
if_cmd_init_default();
#endif
hook_register_prio(if_real, 0, isis_ifp_create);
hook_register_prio(if_up, 0, isis_ifp_up);
hook_register_prio(if_down, 0, isis_ifp_down);
hook_register_prio(if_unreal, 0, isis_ifp_destroy);
2003-12-23 09:09:43 +01:00
}