summaryrefslogtreecommitdiff
path: root/isisd/isis_lsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_lsp.c')
-rw-r--r--isisd/isis_lsp.c145
1 files changed, 125 insertions, 20 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 47225ea2c3..6d2303817b 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -399,7 +399,98 @@ static void lsp_seqno_update(struct isis_lsp *lsp0)
return;
}
-static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
+static bool isis_level2_adj_up(struct isis_area *curr_area)
+{
+ struct listnode *node, *cnode;
+ struct isis_circuit *circuit;
+ struct list *adjdb;
+ struct isis_adjacency *adj;
+ struct isis *isis = curr_area->isis;
+ struct isis_area *area;
+
+ /* lookup for a Level2 adjacency up in another area */
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ if (area->area_tag
+ && strcmp(area->area_tag, curr_area->area_tag) == 0)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ adjdb = circuit->u.bc.adjdb[1];
+ if (!adjdb || !adjdb->count)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
+ if (adj->level != ISIS_ADJ_LEVEL1
+ && adj->adj_state == ISIS_ADJ_UP)
+ return true;
+ }
+ } else if (circuit->circ_type == CIRCUIT_T_P2P
+ && circuit->u.p2p.neighbor) {
+ adj = circuit->u.p2p.neighbor;
+ if (adj->level != ISIS_ADJ_LEVEL1
+ && adj->adj_state == ISIS_ADJ_UP)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void isis_reset_attach_bit(struct isis_adjacency *curr_adj)
+{
+ struct listnode *node;
+ struct isis_area *curr_area = curr_adj->circuit->area;
+ struct isis *isis = curr_area->isis;
+ struct isis_area *area;
+ struct lspdb_head *head;
+ struct isis_lsp *lsp;
+ uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+
+ /* If new adjaceny is up and area is level2 or level1and2 verify if
+ * we have LSPs in other areas that should now set the attach bit.
+ *
+ * If adjacenty is down, verify if we no longer have another level2
+ * or level1and2 areas so that we should now remove the attach bit.
+ */
+ if (curr_area->is_type == IS_LEVEL_1)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ if (area->area_tag
+ && strcmp(area->area_tag, curr_area->area_tag) == 0)
+ continue;
+
+ if (!area->attached_bit_send)
+ continue;
+
+ head = &area->lspdb[IS_LEVEL_1 - 1];
+ memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
+ memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
+
+ lsp = lsp_search(head, lspid);
+ if (!lsp)
+ continue;
+
+ if (curr_adj->adj_state == ISIS_ADJ_UP
+ && !(lsp->hdr.lsp_bits & LSPBIT_ATT)) {
+ sched_debug(
+ "ISIS (%s): adj going up regenerate lsp-bits",
+ area->area_tag);
+ lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
+ } else if (curr_adj->adj_state == ISIS_ADJ_DOWN
+ && lsp->hdr.lsp_bits & LSPBIT_ATT
+ && !isis_level2_adj_up(area)) {
+ sched_debug(
+ "ISIS (%s): adj going down regenerate lsp-bits",
+ area->area_tag);
+ lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
+ }
+ }
+}
+
+static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
+ struct isis_area *area)
{
uint8_t lsp_bits = 0;
if (level == IS_LEVEL_1)
@@ -408,8 +499,13 @@ static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
lsp_bits = IS_LEVEL_1_AND_2;
if (overload_bit)
lsp_bits |= overload_bit;
- if (attached_bit)
- lsp_bits |= attached_bit;
+
+ /* only set the attach bit if we are a level-1-2 router and this is
+ * a level-1 LSP and we have a level-2 adjacency up from another area
+ */
+ if (area->is_type == IS_LEVEL_1_AND_2 && level == IS_LEVEL_1
+ && attached_bit && isis_level2_adj_up(area))
+ lsp_bits |= LSPBIT_ATT;
return lsp_bits;
}
@@ -632,13 +728,13 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
return " error";
/* we only focus on the default metric */
- pos += sprintf(pos, "%d/",
- ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
+ pos += snprintf(pos, buf_size, "%d/",
+ ISIS_MASK_LSP_ATT_BITS(lsp_bits) ? 1 : 0);
- pos += sprintf(pos, "%d/",
- ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
+ pos += snprintf(pos, buf_size, "%d/",
+ ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
- sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
+ snprintf(pos, buf_size, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
return buf;
}
@@ -838,7 +934,7 @@ static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
lsp_bits_generate(level, area->overload_bit,
- area->attached_bit),
+ area->attached_bit_send, area),
0, lsp0, level);
lsp->own_lsp = 1;
lsp_insert(&area->lspdb[level - 1], lsp);
@@ -864,7 +960,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
area->area_tag, level);
lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
- area->attached_bit);
+ area->attached_bit_send, area);
lsp_add_auth(lsp);
@@ -1223,10 +1319,10 @@ int lsp_generate(struct isis_area *area, int level)
oldlsp->hdr.lsp_id);
}
rem_lifetime = lsp_rem_lifetime(area, level);
- newlsp =
- lsp_new(area, lspid, rem_lifetime, seq_num,
- area->is_type | area->overload_bit | area->attached_bit,
- 0, NULL, level);
+ newlsp = lsp_new(area, lspid, rem_lifetime, seq_num,
+ lsp_bits_generate(area->is_type, area->overload_bit,
+ area->attached_bit_send, area),
+ 0, NULL, level);
newlsp->area = area;
newlsp->own_lsp = 1;
@@ -1310,8 +1406,9 @@ static int lsp_regenerate(struct isis_area *area, int level)
continue;
}
- frag->hdr.lsp_bits = lsp_bits_generate(
- level, area->overload_bit, area->attached_bit);
+ frag->hdr.lsp_bits =
+ lsp_bits_generate(level, area->overload_bit,
+ area->attached_bit_send, area);
/* Set the lifetime values of all the fragments to the same
* value,
* so that no fragment expires before the lsp is refreshed.
@@ -1518,8 +1615,8 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
lsp->level = level;
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
- lsp->hdr.lsp_bits =
- lsp_bits_generate(level, 0, circuit->area->attached_bit);
+ lsp->hdr.lsp_bits = lsp_bits_generate(
+ level, 0, circuit->area->attached_bit_send, area);
/*
* add self to IS neighbours
@@ -1617,8 +1714,10 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
rem_lifetime = lsp_rem_lifetime(circuit->area, level);
/* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
- circuit->area->is_type | circuit->area->attached_bit, 0,
- NULL, level);
+ lsp_bits_generate(circuit->area->is_type, 0,
+ circuit->area->attached_bit_send,
+ circuit->area),
+ 0, NULL, level);
lsp->area = circuit->area;
lsp_build_pseudo(lsp, circuit, level);
@@ -2036,6 +2135,12 @@ void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
{
lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+
+ /* when an adjacency state changes determine if we need to
+ * change attach_bits in other area's LSPs
+ */
+ isis_reset_attach_bit(adj);
+
return 0;
}