diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 5ca70eab0f..b48da9312f 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -593,6 +593,10 @@ void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " set-overload-bit\n"); } +#if CONFDATE > 20220119 +CPP_NOTICE( + "Use of `set-attached-bit` is deprecated please use attached-bit [send | receive]") +#endif /* * XPath: /frr-isisd:isis/instance/attached */ @@ -600,18 +604,57 @@ DEFPY_YANG(set_attached_bit, set_attached_bit_cmd, "[no] set-attached-bit", "Reset attached bit\n" "Set attached bit to identify as L1/L2 router for inter-area traffic\n") { - nb_cli_enqueue_change(vty, "./attached", NB_OP_MODIFY, + vty_out(vty, + "set-attached-bit deprecated please use attached-bit [send | receive]\n"); + + return CMD_SUCCESS; +} + +/* + * XPath: /frr-isisd:isis/instance/attach-send + */ +DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send", + "Reset attached bit\n" + "Set attached bit for inter-area traffic\n" + "Set attached bit in LSP sent to L1 router\n") +{ + nb_cli_enqueue_change(vty, "./attach-send", NB_OP_MODIFY, no ? "false" : "true"); return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); - vty_out(vty, " set-attached-bit\n"); + vty_out(vty, " attached-bit send\n"); +} + +/* + * XPath: /frr-isisd:isis/instance/attach-receive-ignore + */ +DEFPY_YANG( + attached_bit_receive_ignore, attached_bit_receive_ignore_cmd, + "[no] attached-bit receive ignore", + "Reset attached bit\n" + "Set attach bit for inter-area traffic\n" + "If LSP received with attached bit set, create default route to neighbor\n" + "Do not process attached bit\n") +{ + nb_cli_enqueue_change(vty, "./attach-receive-ignore", NB_OP_MODIFY, + no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + vty_out(vty, " attached-bit receive ignore\n"); } /* @@ -3206,6 +3249,8 @@ void isis_cli_init(void) install_element(ISIS_NODE, &set_overload_bit_cmd); install_element(ISIS_NODE, &set_attached_bit_cmd); + install_element(ISIS_NODE, &attached_bit_send_cmd); + install_element(ISIS_NODE, &attached_bit_receive_ignore_cmd); install_element(ISIS_NODE, &metric_style_cmd); install_element(ISIS_NODE, &no_metric_style_cmd); diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h index 25eae06cb0..3d6a20ee66 100644 --- a/isisd/isis_constants.h +++ b/isisd/isis_constants.h @@ -140,7 +140,7 @@ * LSP bit masks */ #define LSPBIT_P 0x80 -#define LSPBIT_ATT 0x78 +#define LSPBIT_ATT 0x08 /* only use the Default ATT bit */ #define LSPBIT_OL 0x04 #define LSPBIT_IST 0x03 @@ -158,7 +158,6 @@ #define ISIS_MASK_LSP_ATT_ERROR_BIT(x) ((x)&0x40) #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x) ((x)&0x20) #define ISIS_MASK_LSP_ATT_DELAY_BIT(x) ((x)&0x10) -#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x) ((x)&0x8) #define LLC_LEN 3 diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 47225ea2c3..4c70bd12b7 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -399,7 +399,50 @@ 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) { + for (ALL_LIST_ELEMENTS_RO(adjdb, node, + adj)) + if ((adj->level + == ISIS_ADJ_LEVEL2 + || adj->level + == ISIS_ADJ_LEVEL1AND2) + && 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_LEVEL2 + || adj->level == ISIS_ADJ_LEVEL1AND2) + && adj->adj_state == ISIS_ADJ_UP) + return true; + } + } + } + return false; +} + +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 +451,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 +680,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 +886,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 +912,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 +1271,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 +1358,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 +1567,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 +1666,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); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index a02e6a45b1..6d46e6b67e 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -59,10 +59,23 @@ const struct frr_yang_module_info frr_isisd_info = { .modify = isis_instance_dynamic_hostname_modify, }, }, + { + .xpath = "/frr-isisd:isis/instance/attach-send", + .cbs = { + .cli_show = cli_show_isis_attached_send, + .modify = isis_instance_attached_send_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/attach-receive-ignore", + .cbs = { + .cli_show = cli_show_isis_attached_receive, + .modify = isis_instance_attached_receive_modify, + }, + }, { .xpath = "/frr-isisd:isis/instance/attached", .cbs = { - .cli_show = cli_show_isis_attached, .modify = isis_instance_attached_modify, }, }, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 679bc6345d..8ecd8134e6 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -34,6 +34,8 @@ int isis_instance_is_type_modify(struct nb_cb_modify_args *args); int isis_instance_area_address_create(struct nb_cb_create_args *args); int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args); int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args); +int isis_instance_attached_send_modify(struct nb_cb_modify_args *args); +int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args); int isis_instance_attached_modify(struct nb_cb_modify_args *args); int isis_instance_overload_modify(struct nb_cb_modify_args *args); int isis_instance_metric_style_modify(struct nb_cb_modify_args *args); @@ -424,8 +426,10 @@ void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); +void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index ed0fea8824..45bbc9737b 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -272,9 +272,9 @@ int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-isisd:isis/instance/attached + * XPath: /frr-isisd:isis/instance/attach-send */ -int isis_instance_attached_modify(struct nb_cb_modify_args *args) +int isis_instance_attached_send_modify(struct nb_cb_modify_args *args) { struct isis_area *area; bool attached; @@ -284,11 +284,37 @@ int isis_instance_attached_modify(struct nb_cb_modify_args *args) area = nb_running_get_entry(args->dnode, NULL, true); attached = yang_dnode_get_bool(args->dnode, NULL); - isis_area_attached_bit_set(area, attached); + isis_area_attached_bit_send_set(area, attached); return NB_OK; } +/* + * XPath: /frr-isisd:isis/instance/attach-receive-ignore + */ +int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool attached; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + attached = yang_dnode_get_bool(args->dnode, NULL); + isis_area_attached_bit_receive_set(area, attached); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/attached + */ +int isis_instance_attached_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + /* * XPath: /frr-isisd:isis/instance/overload */ diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 72de5d6543..2d68aaa9ed 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -729,8 +729,8 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (!memcmp(iih.sys_id, circuit->isis->sysid, ISIS_SYS_ID_LEN)) { zlog_warn( - "ISIS-Adj (%s): Received IIH with own sysid - discard", - circuit->area->area_tag); + "ISIS-Adj (%s): Received IIH with own sysid on %s - discard", + circuit->area->area_tag, circuit->interface->name); circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index dee082fce1..ec0313f21e 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1046,6 +1046,32 @@ lspfragloop: } end: + + /* if attach bit set and we are a level-1 router + * and attach-bit-rcv-ignore is not configured + * add a default route toward this neighbor + */ + if ((lsp->hdr.lsp_bits & LSPBIT_ATT) == LSPBIT_ATT + && !spftree->area->attached_bit_rcv_ignore + && spftree->area->is_type == IS_LEVEL_1) { + struct prefix_pair ip_info = { {0} }; + if (IS_DEBUG_SPF_EVENTS) + zlog_debug("ISIS-Spf (%s): add default %s route", + rawlspid_print(lsp->hdr.lsp_id), + spftree->family == AF_INET ? "ipv4" + : "ipv6"); + + if (spftree->family == AF_INET) { + ip_info.dest.family = AF_INET; + vtype = VTYPE_IPREACH_INTERNAL; + } else { + ip_info.dest.family = AF_INET6; + vtype = VTYPE_IP6REACH_INTERNAL; + } + process_N(spftree, vtype, &ip_info, cost, depth + 1, NULL, + parent); + } + if (fragnode == NULL) fragnode = listhead(lsp->lspu.frags); else diff --git a/isisd/isisd.c b/isisd/isisd.c index eabebab4e0..d45690f4dc 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -316,6 +316,11 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing"); area->lfa_load_sharing[1] = yang_get_default_bool( "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing"); + area->attached_bit_send = + yang_get_default_bool("/frr-isisd:isis/instance/attach-send"); + area->attached_bit_rcv_ignore = yang_get_default_bool( + "/frr-isisd:isis/instance/attach-receive-ignore"); + #else area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */ @@ -332,6 +337,8 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->lsp_mtu = DEFAULT_LSP_MTU; area->lfa_load_sharing[0] = true; area->lfa_load_sharing[1] = true; + area->attached_bit_send = true; + area->attached_bit_rcv_ignore = false; #endif /* ifndef FABRICD */ area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW; area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW; @@ -2547,12 +2554,21 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit) #endif /* ifndef FABRICD */ } -void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit) +void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit) { - char new_attached_bit = attached_bit ? LSPBIT_ATT : 0; - if (new_attached_bit != area->attached_bit) { - area->attached_bit = new_attached_bit; + if (attached_bit != area->attached_bit_send) { + area->attached_bit_send = attached_bit; + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); + } +} + +void isis_area_attached_bit_receive_set(struct isis_area *area, + bool attached_bit) +{ + + if (attached_bit != area->attached_bit_rcv_ignore) { + area->attached_bit_rcv_ignore = attached_bit; lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } } diff --git a/isisd/isisd.h b/isisd/isisd.h index 9b903eed48..a09f741522 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -169,7 +169,8 @@ struct isis_area { /* are we overloaded? */ char overload_bit; /* L1/L2 router identifier for inter-area traffic */ - char attached_bit; + char attached_bit_send; + char attached_bit_rcv_ignore; uint16_t lsp_refresh[ISIS_LEVELS]; /* minimum time allowed before lsp retransmission */ uint16_t lsp_gen_interval[ISIS_LEVELS]; @@ -253,7 +254,9 @@ void isis_area_invalidate_routes(struct isis_area *area, int levels); void isis_area_verify_routes(struct isis_area *area); void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); -void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); +void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit); +void isis_area_attached_bit_receive_set(struct isis_area *area, + bool attached_bit); void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric); diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 812dd4159d..8757ab6b8b 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1043,9 +1043,24 @@ module frr-isisd { "Dynamic hostname support for IS-IS."; } + leaf attach-send { + type boolean; + default "true"; + description + "If true, attached bits are sent in LSP if L1/L2 router for inter-area traffic."; + } + + leaf attach-receive-ignore { + type boolean; + default "false"; + description + "If false, attached bits received in LSP, cause default route add, if L1 router for inter-area traffic."; + } + leaf attached { type boolean; default "false"; + status deprecated; description "If true, identify as L1/L2 router for inter-area traffic."; }