--- /dev/null
+/*
+ * 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"
+
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
+
+/* 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 {
+ enum fabricd_sync_state initial_sync_state;
+ time_t initial_sync_start;
+ struct isis_circuit *initial_sync_circuit;
+ struct thread *initial_sync_timeout;
+};
+
+struct fabricd *fabricd_new(void)
+{
+ struct fabricd *rv = XCALLOC(MTYPE_FABRICD_STATE, sizeof(*rv));
+
+ rv->initial_sync_state = FABRICD_SYNC_PENDING;
+ return rv;
+};
+
+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;
+}
+
+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;
+}
--- /dev/null
+/*
+ * 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 fabricd *fabricd_new(void);
+void fabricd_initial_sync_hello(struct isis_circuit *circuit);
+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);
+
+#endif
#include "isisd/isis_events.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
+#include "isisd/fabricd.h"
extern struct isis *isis;
}
}
+ 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;
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;
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
+#include "isisd/fabricd.h"
static int lsp_l1_refresh(struct thread *thread);
static int lsp_l2_refresh(struct thread *thread);
int level;
uint16_t rem_lifetime;
time_t now = monotime(NULL);
+ bool fabricd_sync_incomplete = false;
lsp_list = list_new();
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
dnode);
} else if (flags_any_set(lsp->SRMflags))
listnode_add(lsp_list, lsp);
+
+ if (fabricd_init_c) {
+ fabricd_sync_incomplete |=
+ ISIS_CHECK_FLAG(lsp->SSNflags,
+ fabricd_init_c);
+ fabricd_sync_incomplete |=
+ ISIS_CHECK_FLAG(lsp->SRMflags,
+ fabricd_init_c);
+ }
}
/*
}
}
+ if (fabricd_init_c && !fabricd_sync_incomplete)
+ fabricd_initial_sync_finish(area);
+
list_delete_and_null(&lsp_list);
return ISIS_OK;
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/isis_errors.h"
+#include "isisd/fabricd.h"
static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
int level)
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)) {
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 */
&& !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);
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 */
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 */
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
+#include "isisd/fabricd.h"
struct isis *isis = NULL;
*/
/* isis->debugs = 0xFFFF; */
isisMplsTE.status = disable; /* Only support TE metric */
+
QOBJ_REG(isis, isis);
}
listnode_add(isis->area_list, area);
area->isis = isis;
+ if (fabricd)
+ area->fabricd = fabricd_new();
QOBJ_REG(area, isis_area);
return area;
/* #define EXTREME_DEBUG */
/* #define EXTREME_DICT_DEBUG */
+struct fabricd;
+
struct isis {
unsigned long process_id;
int sysid_set;
*/
int lsp_regenerate_pending[ISIS_LEVELS];
+ struct fabricd *fabricd;
+
/*
* Configurables
*/
isisd/isis_zebra.h \
isisd/isisd.h \
isisd/iso_checksum.h \
+ isisd/fabricd.h \
# end
LIBISIS_SOURCES = \
isisd/isis_zebra.c \
isisd/isisd.c \
isisd/iso_checksum.c \
+ isisd/fabricd.c \
# end
ISIS_SOURCES = \