#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"
+#include "isisd/isis_pdu_counter.h"
static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
int level)
/* Update PDU length */
stream_putw_at(circuit->snd_stream, lenp, length);
+ pdu_counter_count(circuit->area->pdu_tx_counters, pdu_type);
retval = circuit->tx(circuit, level);
if (retval != ISIS_OK)
- flog_err(ISIS_ERR_PACKET,
- "ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(EC_ISIS_PACKET,
+ "ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
return retval;
}
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)) {
static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
uint8_t *ssnpa)
{
+ /* keep a copy of the raw pdu for NB notifications */
+ size_t pdu_start = stream_get_getp(circuit->rcv_stream);
+ size_t pdu_end = stream_get_endp(circuit->rcv_stream);
+ char raw_pdu[pdu_end - pdu_start];
bool p2p_hello = (pdu_type == P2P_HELLO);
int level = p2p_hello ? 0
: (pdu_type == L1_LAN_HELLO) ? ISIS_LEVEL1
? "P2P IIH"
: (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH";
+
+ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
+ pdu_end - pdu_start);
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Rcvd %s on %s, cirType %s, cirID %u",
circuit->area->area_tag, pdu_name,
if (p2p_hello) {
if (circuit->circ_type != CIRCUIT_T_P2P) {
zlog_warn("p2p hello on non p2p circuit");
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "p2p hello on non p2p circuit",
+ raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
} else {
if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
zlog_warn("lan hello on non broadcast circuit");
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "lan hello on non broadcast circuit",
+ raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
zlog_debug(
"level %d LAN Hello received over circuit with externalDomain = true",
level);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit,
+ "LAN Hello received over circuit with externalDomain = true",
+ raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
circuit->area->area_tag,
circuit->interface->name);
}
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "Interface level mismatch", raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
}
"ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16,
circuit->area->area_tag, pdu_name,
circuit->interface->name, iih.pdu_len);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(circuit, "Invalid PDU length",
+ raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
if (!p2p_hello && !(level & iih.circ_type)) {
- flog_err(ISIS_ERR_PACKET,
- "Level %d LAN Hello with Circuit Type %d", level,
- iih.circ_type);
+ flog_err(EC_ISIS_PACKET,
+ "Level %d LAN Hello with Circuit Type %d", level,
+ iih.circ_type);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "LAN Hello with wrong IS-level", raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_ERROR;
}
if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
circuit->rcv_stream, &iih.tlvs, &error_log)) {
zlog_warn("isis_unpack_tlvs() failed: %s", error_log);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs",
+ raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
if (!iih.tlvs->area_addresses.count) {
zlog_warn("No Area addresses TLV in %s", pdu_name);
+#ifndef FABRICD
+ /* send northbound notification */
+ isis_notif_area_mismatch(circuit, raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
if (!iih.tlvs->protocols_supported.count) {
zlog_warn("No supported protocols TLV in %s", pdu_name);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "No supported protocols TLV", raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
- if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd,
- circuit->rcv_stream, false)) {
+ int auth_code = isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd,
+ circuit->rcv_stream, false);
+ if (auth_code != ISIS_AUTH_OK) {
isis_event_auth_failure(circuit->area->area_tag,
"IIH authentication failure",
iih.sys_id);
+#ifndef FABRICD
+ /* send northbound notification */
+ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
+ pdu_end - pdu_start);
+ if (auth_code == ISIS_AUTH_FAILURE)
+ isis_notif_authentication_failure(circuit, raw_pdu);
+ else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ isis_notif_authentication_type_failure(circuit,
+ raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
zlog_warn(
"ISIS-Adj (%s): Received IIH with own sysid - discard",
circuit->area->area_tag);
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "Received IIH with our own sysid", raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
circuit->area->area_tag, level,
circuit->interface->name);
}
+#ifndef FABRICD
+ /* send northbound notification */
+ isis_notif_area_mismatch(circuit, raw_pdu);
+#endif /* ifndef FABRICD */
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)
"ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH",
circuit->area->area_tag);
}
-
+#ifndef FABRICD
+ isis_notif_reject_adjacency(
+ circuit, "Neither IPv4 not IPv6 considered usable",
+ raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
return retval;
}
+static void lsp_flood_or_update(struct isis_lsp *lsp,
+ struct isis_circuit *circuit,
+ bool circuit_scoped)
+{
+ if (!circuit_scoped)
+ lsp_flood(lsp, circuit);
+ else
+ fabricd_update_lsp_no_flood(lsp, circuit);
+}
+
/*
* Process Level 1/2 Link State
* ISO - 10589
* 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;
+ size_t pdu_start = stream_get_getp(circuit->rcv_stream);
+ size_t pdu_end = stream_get_endp(circuit->rcv_stream);
+ char raw_pdu[pdu_end - pdu_start];
+
+ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
+ pdu_end - pdu_start);
+
+ 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);
hdr.checksum = stream_getw(circuit->rcv_stream);
hdr.lsp_bits = stream_getc(circuit->rcv_stream);
+#ifndef FABRICD
+ /* send northbound notification */
+ isis_notif_lsp_received(circuit, rawlspid_print(hdr.lsp_id), hdr.seqno,
+ time(NULL), sysid_print(hdr.lsp_id));
+#endif /* ifndef FABRICD */
+
if (pdu_len_validate(hdr.pdu_len, circuit)) {
zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %" PRIu16,
circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
struct isis_passwd *passwd = (level == ISIS_LEVEL1)
? &circuit->area->area_passwd
: &circuit->area->domain_passwd;
- if (!isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, true)) {
+ int auth_code = isis_tlvs_auth_is_valid(tlvs, passwd,
+ circuit->rcv_stream, true);
+ if (auth_code != ISIS_AUTH_OK) {
isis_event_auth_failure(circuit->area->area_tag,
"LSP authentication failure",
hdr.lsp_id);
+#ifndef FABRICD
+ /* send northbound notification */
+ if (auth_code == ISIS_AUTH_FAILURE)
+ isis_notif_authentication_failure(circuit, raw_pdu);
+ else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ isis_notif_authentication_type_failure(circuit,
+ raw_pdu);
+#endif /* ifndef FABRICD */
goto out;
}
* 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),
lsp_confusion);
tlvs = NULL;
/* ii */
- lsp_set_all_srmflags(lsp);
+ lsp_flood_or_update(lsp, NULL,
+ circuit_scoped);
/* v */
ISIS_FLAGS_CLEAR_ALL(
lsp->SSNflags); /* FIXME:
* 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)
} /* 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)
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);
+ lsp_flood_or_update(lsp, NULL,
+ circuit_scoped);
} 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)
zlog_debug(
- "ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08" PRIx32,
+ "ISIS-Upd (%s): (1) "
+ "re-originating LSP %s new seq "
+ "0x%08" PRIx32,
circuit->area->area_tag,
rawlspid_print(hdr.lsp_id),
lsp->hdr.seqno);
* is
* "greater" than that held by S, ... */
- if (hdr.seqno > lsp->hdr.seqno) {
+ if (comp == LSP_NEWER) {
/* 7.3.16.1 */
lsp_inc_seqno(lsp, hdr.seqno);
- if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
zlog_debug(
"ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08" PRIx32,
circuit->area->area_tag,
rawlspid_print(hdr.lsp_id),
lsp->hdr.seqno);
+ }
+ lsp_flood(lsp, NULL);
+ } else if (comp == LSP_EQUAL) {
+ isis_tx_queue_del(circuit->tx_queue, lsp);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_SET_FLAG(lsp->SSNflags, circuit);
+ } else {
+ isis_tx_queue_add(circuit->tx_queue, lsp,
+ TX_LSP_NORMAL);
+ ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
}
- /* If the received LSP is older or equal,
- * resend the LSP which will act as ACK */
- lsp_set_all_srmflags(lsp);
} else {
/* 7.3.15.1 e) - This lsp originated on another system */
if (!lsp0) {
zlog_debug(
"Got lsp frag, while zero lsp not in database");
- return ISIS_OK;
+ goto out;
}
}
/* i */
circuit->area, level, false);
tlvs = NULL;
}
- /* ii */
- lsp_set_all_srmflags(lsp);
- /* iii */
- ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+ lsp_flood_or_update(lsp, circuit, circuit_scoped);
/* iv */
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
}
/* 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;
}
/* 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);
}
}
retval = ISIS_OK;
out:
+ fabricd_trigger_csnp(circuit->area, circuit_scoped);
+
isis_free_tlvs(tlvs);
return retval;
}
static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
const uint8_t *ssnpa)
{
+#ifndef FABRICD
+ size_t pdu_start = stream_get_getp(circuit->rcv_stream);
+ size_t pdu_end = stream_get_endp(circuit->rcv_stream);
+ char raw_pdu[pdu_end - pdu_start];
+#endif /* ifndef FABRICD */
+
bool is_csnp = (pdu_type == L1_COMPLETE_SEQ_NUM
|| pdu_type == L2_COMPLETE_SEQ_NUM);
char typechar = is_csnp ? 'C' : 'P';
uint16_t pdu_len = stream_getw(circuit->rcv_stream);
uint8_t rem_sys_id[ISIS_SYS_ID_LEN];
+
stream_get(rem_sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
stream_forward_getp(circuit->rcv_stream, 1); /* Circuit ID - unused */
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 */
struct isis_passwd *passwd = (level == IS_LEVEL_1)
? &circuit->area->area_passwd
: &circuit->area->domain_passwd;
- if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)
- && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream,
- false)) {
- isis_event_auth_failure(circuit->area->area_tag,
- "SNP authentication failure",
- rem_sys_id);
- goto out;
+ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) {
+ int auth_code = isis_tlvs_auth_is_valid(
+ tlvs, passwd, circuit->rcv_stream, false);
+ if (auth_code != ISIS_AUTH_OK) {
+ isis_event_auth_failure(circuit->area->area_tag,
+ "SNP authentication failure",
+ rem_sys_id);
+#ifndef FABRICD
+ /* send northbound notification */
+ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
+ pdu_end - pdu_start);
+ if (auth_code == ISIS_AUTH_FAILURE)
+ isis_notif_authentication_failure(circuit,
+ raw_pdu);
+ else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ isis_notif_authentication_type_failure(circuit,
+ raw_pdu);
+#endif /* ifndef FABRICD */
+ goto out;
+ }
}
struct isis_lsp_entry *entry_head =
}
}
+ 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) {
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 {
continue;
}
}
- struct isis_lsp *lsp =
- lsp_new(circuit->area, entry->id,
+ lsp = lsp_new(circuit->area, entry->id,
entry->rem_lifetime, 0, 0,
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;
}
}
}
}
/* 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);
+ list_delete(&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);
break;
case L1_LINK_STATE:
case L2_LINK_STATE:
+ case FS_LINK_STATE:
*size = ISIS_LSP_HDR_LEN;
break;
case L1_COMPLETE_SEQ_NUM:
int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
{
int retval = ISIS_OK;
+ size_t pdu_start = stream_get_getp(circuit->rcv_stream);
+ size_t pdu_end = stream_get_endp(circuit->rcv_stream);
+ char raw_pdu[pdu_end - pdu_start];
+
+ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
+ pdu_end - pdu_start);
/* Verify that at least the 8 bytes fixed header have been received */
if (stream_get_endp(circuit->rcv_stream) < ISIS_FIXED_HDR_LEN) {
- flog_err(ISIS_ERR_PACKET, "PDU is too short to be IS-IS.");
+ flog_err(EC_ISIS_PACKET, "PDU is too short to be IS-IS.");
return ISIS_ERROR;
}
uint8_t pdu_type = stream_getc(circuit->rcv_stream)
& 0x1f; /* bits 6-8 are reserved */
uint8_t version2 = stream_getc(circuit->rcv_stream);
+
stream_forward_getp(circuit->rcv_stream, 1); /* reserved */
uint8_t max_area_addrs = stream_getc(circuit->rcv_stream);
+ pdu_counter_count(circuit->area->pdu_rx_counters, pdu_type);
+
if (idrp == ISO9542_ESIS) {
- flog_err(LIB_ERR_DEVELOPMENT,
- "No support for ES-IS packet IDRP=%" PRIx8, idrp);
+ flog_err(EC_LIB_DEVELOPMENT,
+ "No support for ES-IS packet IDRP=%" PRIx8, idrp);
return ISIS_ERROR;
}
if (idrp != ISO10589_ISIS) {
- flog_err(ISIS_ERR_PACKET, "Not an IS-IS packet IDRP=%" PRIx8,
- idrp);
+ flog_err(EC_ISIS_PACKET, "Not an IS-IS packet IDRP=%" PRIx8,
+ idrp);
return ISIS_ERROR;
}
if (id_len != 0 && id_len != ISIS_SYS_ID_LEN) {
flog_err(
- ISIS_ERR_PACKET,
+ EC_ISIS_PACKET,
"IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8
", while the parameter for this IS is %u",
id_len, ISIS_SYS_ID_LEN);
}
if (length != expected_length) {
- flog_err(ISIS_ERR_PACKET,
- "Exepected fixed header length = %" PRIu8
- " but got %" PRIu8,
- expected_length, length);
+ flog_err(EC_ISIS_PACKET,
+ "Exepected fixed header length = %" PRIu8
+ " but got %" PRIu8,
+ expected_length, length);
return ISIS_ERROR;
}
if (stream_get_endp(circuit->rcv_stream) < length) {
flog_err(
- ISIS_ERR_PACKET,
+ EC_ISIS_PACKET,
"PDU is too short to contain fixed header of given PDU type.");
return ISIS_ERROR;
}
}
/* 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,
+ EC_ISIS_PACKET,
"maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8
" while the parameter for this IS is %u",
max_area_addrs, isis->max_area_addrs);
+#ifndef FABRICD
+ /* send northbound notification */
+ isis_notif_max_area_addr_mismatch(circuit, max_area_addrs,
+ raw_pdu);
+#endif /* ifndef FABRICD */
return ISIS_ERROR;
}
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:
stream_putc(stream, 0); /* Max Area Addresses 0 => 3 */
}
-static void put_hello_hdr(struct isis_circuit *circuit, int level,
- size_t *len_pointer)
+static uint8_t hello_pdu_type(struct isis_circuit *circuit, int level)
{
- uint8_t pdu_type;
-
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- pdu_type = (level == IS_LEVEL_1) ? L1_LAN_HELLO : L2_LAN_HELLO;
+ return (level == IS_LEVEL_1) ? L1_LAN_HELLO : L2_LAN_HELLO;
else
- pdu_type = P2P_HELLO;
+ return P2P_HELLO;
+}
+
+static void put_hello_hdr(struct isis_circuit *circuit, int level,
+ size_t *len_pointer)
+{
+ uint8_t pdu_type = hello_pdu_type(circuit, level);
isis_circuit_stream(circuit, &circuit->snd_stream);
fill_fixed_hdr(pdu_type, circuit->snd_stream);
&& !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);
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);
isis_free_tlvs(tlvs);
+ pdu_counter_count(circuit->area->pdu_tx_counters,
+ hello_pdu_type(circuit, level));
retval = circuit->tx(circuit, level);
if (retval != ISIS_OK)
- flog_err(ISIS_ERR_PACKET,
- "ISIS-Adj (%s): Send L%d IIH on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(EC_ISIS_PACKET,
+ "ISIS-Adj (%s): Send L%d IIH on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
return retval;
}
-int send_lan_l1_hello(struct thread *thread)
+static int send_hello_cb(struct thread *thread)
{
- struct isis_circuit *circuit;
- int retval;
+ struct isis_circuit_arg *arg = THREAD_ARG(thread);
+ assert(arg);
+
+ struct isis_circuit *circuit = arg->circuit;
+ int level = arg->level;
- circuit = THREAD_ARG(thread);
assert(circuit);
- circuit->u.bc.t_send_lan_hello[0] = NULL;
- if (!(circuit->area->is_type & IS_LEVEL_1)) {
- zlog_warn(
- "ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
- circuit->area->area_tag);
- return 1;
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ circuit->u.p2p.t_send_p2p_hello = NULL;
+ send_hello(circuit, 1);
+ send_hello_sched(circuit, ISIS_LEVEL1,
+ 1000 * circuit->hello_interval[1]);
+ return ISIS_OK;
+ }
+
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ zlog_warn("ISIS-Hello (%s): Trying to send hello on unknown circuit type %d",
+ circuit->area->area_tag, circuit->circ_type);
+ return ISIS_WARNING;
+ }
+
+ circuit->u.bc.t_send_lan_hello[level - 1] = NULL;
+ if (!(circuit->is_type & level)) {
+ zlog_warn("ISIS-Hello (%s): Trying to send L%d IIH in L%d-only circuit",
+ circuit->area->area_tag, level, 3 - level);
+ return ISIS_WARNING;
}
- if (circuit->u.bc.run_dr_elect[0])
- isis_dr_elect(circuit, 1);
+ if (circuit->u.bc.run_dr_elect[level - 1])
+ isis_dr_elect(circuit, level);
- retval = send_hello(circuit, 1);
+ int rv = send_hello(circuit, level);
/* set next timer thread */
- thread_add_timer(master, send_lan_l1_hello, circuit,
- isis_jitter(circuit->hello_interval[0], IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[0]);
-
- return retval;
+ send_hello_sched(circuit, level, 1000 * circuit->hello_interval[level - 1]);
+ return rv;
}
-int send_lan_l2_hello(struct thread *thread)
+static void _send_hello_sched(struct isis_circuit *circuit,
+ struct thread **threadp,
+ int level, long delay)
{
- struct isis_circuit *circuit;
- int retval;
+ if (*threadp) {
+ if (thread_timer_remain_msec(*threadp) < (unsigned long)delay)
+ return;
- circuit = THREAD_ARG(thread);
- assert(circuit);
- circuit->u.bc.t_send_lan_hello[1] = NULL;
-
- if (!(circuit->area->is_type & IS_LEVEL_2)) {
- zlog_warn("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
- circuit->area->area_tag);
- return 1;
+ thread_cancel(*threadp);
}
- if (circuit->u.bc.run_dr_elect[1])
- isis_dr_elect(circuit, 2);
-
- retval = send_hello(circuit, 2);
-
- /* set next timer thread */
- thread_add_timer(master, send_lan_l2_hello, circuit,
- isis_jitter(circuit->hello_interval[1], IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[1]);
-
- return retval;
+ thread_add_timer_msec(master, send_hello_cb,
+ &circuit->level_arg[level - 1],
+ isis_jitter(delay, IIH_JITTER),
+ threadp);
}
-int send_p2p_hello(struct thread *thread)
+void send_hello_sched(struct isis_circuit *circuit, int level, long delay)
{
- struct isis_circuit *circuit;
-
- circuit = THREAD_ARG(thread);
- assert(circuit);
- circuit->u.p2p.t_send_p2p_hello = NULL;
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ _send_hello_sched(circuit, &circuit->u.p2p.t_send_p2p_hello,
+ ISIS_LEVEL1, delay);
+ return;
+ }
- send_hello(circuit, 1);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ zlog_warn("%s: encountered unknown circuit type %d on %s",
+ __func__, circuit->circ_type,
+ circuit->interface->name);
+ return;
+ }
- /* set next timer thread */
- thread_add_timer(master, send_p2p_hello, circuit,
- isis_jitter(circuit->hello_interval[1], IIH_JITTER),
- &circuit->u.p2p.t_send_p2p_hello);
+ for (int loop_level = ISIS_LEVEL1; loop_level <= ISIS_LEVEL2; loop_level++) {
+ if (!(loop_level & level))
+ continue;
- return ISIS_OK;
+ _send_hello_sched(
+ circuit,
+ &circuit->u.bc.t_send_lan_hello[loop_level - 1],
+ loop_level,
+ delay
+ );
+ }
}
+
/*
* Count the maximum number of lsps that can be accomodated by a given size.
*/
|| dict_count(circuit->area->lspdb[level - 1]) == 0)
return ISIS_OK;
+ uint8_t pdu_type = (level == ISIS_LEVEL1) ? L1_COMPLETE_SEQ_NUM
+ : L2_COMPLETE_SEQ_NUM;
+
isis_circuit_stream(circuit, &circuit->snd_stream);
- fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_COMPLETE_SEQ_NUM
- : L2_COMPLETE_SEQ_NUM,
- circuit->snd_stream);
+ fill_fixed_hdr(pdu_type, circuit->snd_stream);
size_t len_pointer = stream_get_endp(circuit->snd_stream);
stream_putw(circuit->snd_stream, 0);
stream_get_endp(circuit->snd_stream));
}
+ pdu_counter_count(circuit->area->pdu_tx_counters, pdu_type);
int retval = circuit->tx(circuit, level);
if (retval != ISIS_OK) {
- flog_err(ISIS_ERR_PACKET,
- "ISIS-Snp (%s): Send L%d CSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(EC_ISIS_PACKET,
+ "ISIS-Snp (%s): Send L%d CSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
isis_free_tlvs(tlvs);
return retval;
}
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 */
if (!circuit->snd_stream)
return ISIS_ERROR;
+ uint8_t pdu_type = (level == ISIS_LEVEL1) ? L1_PARTIAL_SEQ_NUM
+ : L2_PARTIAL_SEQ_NUM;
+
isis_circuit_stream(circuit, &circuit->snd_stream);
- fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_PARTIAL_SEQ_NUM
- : L2_PARTIAL_SEQ_NUM,
- circuit->snd_stream);
+ fill_fixed_hdr(pdu_type, circuit->snd_stream);
size_t len_pointer = stream_get_endp(circuit->snd_stream);
stream_putw(circuit->snd_stream, 0); /* length is filled in later */
stream_get_endp(circuit->snd_stream));
}
+ pdu_counter_count(circuit->area->pdu_tx_counters, pdu_type);
int retval = circuit->tx(circuit, level);
if (retval != ISIS_OK) {
- flog_err(ISIS_ERR_PACKET,
- "ISIS-Snp (%s): Send L%d PSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(EC_ISIS_PACKET,
+ "ISIS-Snp (%s): Send L%d PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
isis_free_tlvs(tlvs);
return retval;
}
/*
* ISO 10589 - 7.3.14.3
*/
-int send_lsp(struct thread *thread)
+void send_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp,
+ enum isis_tx_type tx_type)
{
- struct isis_circuit *circuit;
- struct isis_lsp *lsp;
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;
* the circuit's MTU. So handle and log this case here. */
if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) {
flog_err(
- ISIS_ERR_PACKET,
+ EC_ISIS_PACKET,
"ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
"s on %s. LSP Size is %zu while interface stream size is %zu.",
lsp->hdr.checksum, lsp->hdr.rem_lifetime,
circuit->interface->name, stream_get_endp(lsp->pdu),
stream_get_size(circuit->snd_stream));
+#ifndef FABRICD
+ /* send a northbound notification */
+ isis_notif_lsp_too_large(circuit, stream_get_endp(lsp->pdu),
+ rawlspid_print(lsp->hdr.lsp_id));
+#endif /* ifndef FABRICD */
if (isis->debugs & DEBUG_PACKET_DUMP)
zlog_dump_data(STREAM_DATA(lsp->pdu),
stream_get_endp(lsp->pdu));
/* 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
+ zlog_debug("ISIS-Upd (%s): Sending %sL%d LSP %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
"s on %s",
- circuit->area->area_tag, lsp->level,
+ circuit->area->area_tag,
+ (tx_type == TX_LSP_CIRCUIT_SCOPED)
+ ? "Circuit scoped " : "",
+ lsp->level,
rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno,
lsp->hdr.checksum, lsp->hdr.rem_lifetime,
circuit->interface->name);
stream_get_endp(circuit->snd_stream));
}
+ uint8_t pdu_type = (tx_type == TX_LSP_CIRCUIT_SCOPED) ? FS_LINK_STATE
+ : (lsp->level == ISIS_LEVEL1) ? L1_LINK_STATE
+ : L2_LINK_STATE;
+
clear_srm = 0;
+ pdu_counter_count(circuit->area->pdu_tx_counters, pdu_type);
retval = circuit->tx(circuit, lsp->level);
if (retval != ISIS_OK) {
- flog_err(ISIS_ERR_PACKET,
- "ISIS-Upd (%s): Send L%d LSP on %s failed %s",
- circuit->area->area_tag, lsp->level,
- circuit->interface->name,
- (retval == ISIS_WARNING) ? "temporarily"
- : "permanently");
+ flog_err(EC_ISIS_PACKET,
+ "ISIS-Upd (%s): Send L%d LSP on %s failed %s",
+ circuit->area->area_tag, lsp->level,
+ circuit->interface->name,
+ (retval == ISIS_WARNING) ? "temporarily"
+ : "permanently");
}
out:
* to clear
* the fag.
*/
- ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+ isis_tx_queue_del(circuit->tx_queue, lsp);
}
-
- return retval;
}