blob: 0f642a777880abba10af8e5b5f4714ce498f38ff [file] [log] [blame]
/*
* IS-IS Rout(e)ing protocol - isis_csm.c
* IS-IS circuit state machine
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
*
* 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; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <zebra.h>
#include "log.h"
#include "memory.h"
#include "if.h"
#include "linklist.h"
#include "command.h"
#include "thread.h"
#include "hash.h"
#include "prefix.h"
#include "stream.h"
#include "isisd/dict.h"
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_tlv.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"
extern struct isis *isis;
static const char *csm_statestr[] = {
"C_STATE_NA",
"C_STATE_INIT",
"C_STATE_CONF",
"C_STATE_UP"
};
#define STATE2STR(S) csm_statestr[S]
static const char *csm_eventstr[] = {
"NO_STATE",
"ISIS_ENABLE",
"IF_UP_FROM_Z",
"ISIS_DISABLE",
"IF_DOWN_FROM_Z",
};
#define EVENT2STR(E) csm_eventstr[E]
struct isis_circuit *
isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
{
int old_state;
old_state = circuit ? circuit->state : C_STATE_NA;
if (isis->debugs & DEBUG_EVENTS)
zlog_debug ("CSM_EVENT: %s", EVENT2STR (event));
switch (old_state)
{
case C_STATE_NA:
if (circuit)
zlog_warn ("Non-null circuit while state C_STATE_NA");
assert (circuit == NULL);
switch (event)
{
case ISIS_ENABLE:
circuit = isis_circuit_new ();
isis_circuit_configure (circuit, (struct isis_area *) arg);
circuit->state = C_STATE_CONF;
break;
case IF_UP_FROM_Z:
circuit = isis_circuit_new ();
isis_circuit_if_add (circuit, (struct interface *) arg);
listnode_add (isis->init_circ_list, circuit);
circuit->state = C_STATE_INIT;
break;
case ISIS_DISABLE:
zlog_warn ("circuit already disabled");
break;
case IF_DOWN_FROM_Z:
zlog_warn ("circuit already disconnected");
break;
}
break;
case C_STATE_INIT:
assert (circuit);
switch (event)
{
case ISIS_ENABLE:
isis_circuit_configure (circuit, (struct isis_area *) arg);
if (isis_circuit_up (circuit) != ISIS_OK)
{
isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
break;
}
circuit->state = C_STATE_UP;
isis_event_circuit_state_change (circuit, circuit->area, 1);
listnode_delete (isis->init_circ_list, circuit);
break;
case IF_UP_FROM_Z:
assert (circuit);
zlog_warn ("circuit already connected");
break;
case ISIS_DISABLE:
zlog_warn ("circuit already disabled");
break;
case IF_DOWN_FROM_Z:
isis_circuit_if_del (circuit, (struct interface *) arg);
listnode_delete (isis->init_circ_list, circuit);
isis_circuit_del (circuit);
circuit = NULL;
break;
}
break;
case C_STATE_CONF:
assert (circuit);
switch (event)
{
case ISIS_ENABLE:
zlog_warn ("circuit already enabled");
break;
case IF_UP_FROM_Z:
isis_circuit_if_add (circuit, (struct interface *) arg);
if (isis_circuit_up (circuit) != ISIS_OK)
{
zlog_err("Could not bring up %s because of invalid config.",
circuit->interface->name);
zlog_err("Clearing config for %s. Please re-examine it.",
circuit->interface->name);
if (circuit->ip_router)
{
circuit->ip_router = 0;
circuit->area->ip_circuits--;
}
if (circuit->ipv6_router)
{
circuit->ipv6_router = 0;
circuit->area->ipv6_circuits--;
}
circuit_update_nlpids(circuit);
isis_circuit_deconfigure(circuit, circuit->area);
listnode_add (isis->init_circ_list, circuit);
circuit->state = C_STATE_INIT;
break;
}
circuit->state = C_STATE_UP;
isis_event_circuit_state_change (circuit, circuit->area, 1);
break;
case ISIS_DISABLE:
isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
isis_circuit_del (circuit);
circuit = NULL;
break;
case IF_DOWN_FROM_Z:
zlog_warn ("circuit already disconnected");
break;
}
break;
case C_STATE_UP:
assert (circuit);
switch (event)
{
case ISIS_ENABLE:
zlog_warn ("circuit already configured");
break;
case IF_UP_FROM_Z:
zlog_warn ("circuit already connected");
break;
case ISIS_DISABLE:
isis_circuit_down (circuit);
isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
circuit->state = C_STATE_INIT;
isis_event_circuit_state_change (circuit,
(struct isis_area *)arg, 0);
listnode_add (isis->init_circ_list, circuit);
break;
case IF_DOWN_FROM_Z:
isis_circuit_down (circuit);
isis_circuit_if_del (circuit, (struct interface *) arg);
circuit->state = C_STATE_CONF;
isis_event_circuit_state_change (circuit, circuit->area, 0);
break;
}
break;
default:
zlog_warn ("Invalid circuit state %d", old_state);
}
if (isis->debugs & DEBUG_EVENTS)
zlog_debug ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state),
circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA));
return circuit;
}