diff options
Diffstat (limited to 'isisd/isis_lsp.c')
| -rw-r--r-- | isisd/isis_lsp.c | 145 |
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; } |
