diff options
49 files changed, 880 insertions, 124 deletions
diff --git a/.github/commitlint.config.js b/.github/commitlint.config.js index bee965b814..2b420b6fbf 100644 --- a/.github/commitlint.config.js +++ b/.github/commitlint.config.js @@ -18,10 +18,12 @@ module.exports = { 'isisd', 'ldpd', 'lib', + 'mgmtd', 'multi', 'nhrpd', 'ospf6d', 'ospfd', + 'pathd', 'pbrd', 'pimd', 'pim6d', @@ -40,6 +42,5 @@ module.exports = { ], 'subject-empty': [2, 'never'], 'subject-full-stop': [2, 'never', '.'], - 'subject-case': [2, 'always', 'sentence-case'], }, }; diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index e9c66a9036..06bf3b3b95 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,7 +1,7 @@ name: commitlint on: - pull_request_target: + pull_request: types: - opened - reopened @@ -10,10 +10,12 @@ on: - unlabeled jobs: - lint: - if: github.repository == 'frrouting/frr' + commitlint: + if: github.repository == 'frrouting/frr' && github.base_ref == 'refs/heads/master' + name: Check if the commits meet the requirements of the guidelines permissions: contents: read + pull-requests: read runs-on: ubuntu-latest steps: - name: Checkout @@ -25,3 +27,4 @@ jobs: uses: wagoid/commitlint-github-action@v5 with: configFile: .github/commitlint.config.js + helpURL: 'https://docs.frrouting.org/projects/dev-guide/en/latest/workflow.html#submitting-patches-and-enhancements' diff --git a/babeld/message.c b/babeld/message.c index 687f768446..b5c2a58984 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -422,7 +422,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, debugf(BABEL_DEBUG_COMMON, "Received Hello from %s on %s that does not have all 0's in the unused section of flags, ignoring", format_address(from), ifp->name); - continue; + goto done; } /* @@ -434,7 +434,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, debugf(BABEL_DEBUG_COMMON, "Received Unicast Hello from %s on %s that FRR is not prepared to understand yet", format_address(from), ifp->name); - continue; + goto done; } DO_NTOHS(seqno, message + 4); @@ -452,7 +452,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, debugf(BABEL_DEBUG_COMMON, "Received hello from %s on %s should be ignored as that this version of FRR does not know how to properly handle interval == 0", format_address(from), ifp->name); - continue; + goto done; } changed = update_neighbour(neigh, seqno, interval); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 0cad119af1..414dafebd4 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -297,6 +297,9 @@ static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen, uint8_t llen = 0; uint8_t label_depth = 0; + if (plen < BGP_LABEL_BYTES) + return 0; + for (; data < lim; data += BGP_LABEL_BYTES) { memcpy(label, data, BGP_LABEL_BYTES); llen += BGP_LABEL_BYTES; @@ -359,6 +362,9 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN); addpath_id = ntohl(addpath_id); pnt += BGP_ADDPATH_ID_LEN; + + if (pnt >= lim) + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } /* Fetch prefix length. */ @@ -377,6 +383,13 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, /* Fill in the labels */ llen = bgp_nlri_get_labels(peer, pnt, psize, &label); + if (llen == 0) { + flog_err( + EC_BGP_UPDATE_RCV, + "%s [Error] Update packet error (wrong label length 0)", + peer->host); + return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH; + } p.prefixlen = prefixlen - BSIZE(llen); /* There needs to be at least one label */ @@ -384,8 +397,6 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, flog_err(EC_BGP_UPDATE_RCV, "%s [Error] Update packet error (wrong label length %d)", peer->host, prefixlen); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1e9f9429c5..56f548bfd5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2921,10 +2921,14 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, * in FIB, then it is advertised */ if (advertise) { - if (!bgp_check_withdrawal(bgp, dest)) - bgp_adj_out_set_subgroup( - dest, subgrp, &attr, selected); - else + if (!bgp_check_withdrawal(bgp, dest)) { + struct attr *adv_attr = + bgp_attr_intern(&attr); + + bgp_adj_out_set_subgroup(dest, subgrp, + adv_attr, + selected); + } else bgp_adj_out_unset_subgroup( dest, subgrp, 1, addpath_tx_id); } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 5c68545398..25a4403040 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -874,33 +874,39 @@ static void rfapiImportTableFlush(struct rfapi_import_table *it) for (afi = AFI_IP; afi < AFI_MAX; ++afi) { struct agg_node *rn; + struct agg_table *at; - for (rn = agg_route_top(it->imported_vpn[afi]); rn; - rn = agg_route_next(rn)) { - /* - * Each route_node has: - * aggregate: points to rfapi_it_extra with monitor - * chain(s) - * info: points to chain of bgp_path_info - */ - /* free bgp_path_info and its children */ - rfapiBgpInfoChainFree(rn->info); - rn->info = NULL; + at = it->imported_vpn[afi]; + if (at) { + for (rn = agg_route_top(at); rn; + rn = agg_route_next(rn)) { + /* + * Each route_node has: + * aggregate: points to rfapi_it_extra with + * monitor chain(s) + * info: points to chain of bgp_path_info + */ + /* free bgp_path_info and its children */ + rfapiBgpInfoChainFree(rn->info); + rn->info = NULL; - rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn); + rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn); + } + agg_table_finish(at); } - for (rn = agg_route_top(it->imported_encap[afi]); rn; - rn = agg_route_next(rn)) { - /* free bgp_path_info and its children */ - rfapiBgpInfoChainFree(rn->info); - rn->info = NULL; + if (at) { + at = it->imported_encap[afi]; + for (rn = agg_route_top(at); rn; + rn = agg_route_next(rn)) { + /* free bgp_path_info and its children */ + rfapiBgpInfoChainFree(rn->info); + rn->info = NULL; - rfapiMonitorExtraFlush(SAFI_ENCAP, rn); + rfapiMonitorExtraFlush(SAFI_ENCAP, rn); + } + agg_table_finish(at); } - - agg_table_finish(it->imported_vpn[afi]); - agg_table_finish(it->imported_encap[afi]); } if (it->monitor_exterior_orphans) { skiplist_free(it->monitor_exterior_orphans); @@ -4260,10 +4266,7 @@ void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h) h->resolve_nve_nexthop = NULL; } - agg_table_finish(h->it_ce->imported_vpn[AFI_IP]); - agg_table_finish(h->it_ce->imported_vpn[AFI_IP6]); - agg_table_finish(h->it_ce->imported_encap[AFI_IP]); - agg_table_finish(h->it_ce->imported_encap[AFI_IP6]); + rfapiImportTableFlush(h->it_ce); if (h->import_mac) { struct rfapi_import_table *it; diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index 2a08531bd7..61b9cf6acb 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -177,29 +177,29 @@ parser, but this is merely a dumb copy job. Here is a brief summary of the various token types along with examples. -+-----------------+-------------------------+-------------------------------------------------------+ -| Token type | Syntax | Description | -+=================+=========================+=======================================================+ -| ``WORD`` | ``show ip bgp`` | Matches itself. In the example every token is a WORD. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``VARIABLE`` | ``FOOBAR`` | Matches anything. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. | -+-----------------+-------------------------+-------------------------------------------------------+ -| ``ASNUM`` | ``<A.B|(1-4294967295>`` | Matches an AS in plain or dot format. | -+-----------------+-------------------------+-------------------------------------------------------+ ++-----------------+--------------------------+-------------------------------------------------------+ +| Token type | Syntax | Description | ++=================+==========================+=======================================================+ +| ``WORD`` | ``show ip bgp`` | Matches itself. In the example every token is a WORD. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``VARIABLE`` | ``FOOBAR`` | Matches anything. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. | ++-----------------+--------------------------+-------------------------------------------------------+ +| ``ASNUM`` | ``<A.B|(1-4294967295)>`` | Matches an AS in plain or dot format. | ++-----------------+--------------------------+-------------------------------------------------------+ When presented with user input, the parser will search over all defined commands in the current context to find a match. It is aware of the various diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 320824ec1d..f11fff5dee 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -95,7 +95,7 @@ March/July/November. Walking backwards from this date: are considered lowest priority (regardless of when they were opened.) - 4 weeks earlier, the stable branch separates from master (named - ``dev/MAJOR.MINOR`` at this point) and tagged as ```base_X.Y``. + ``dev/MAJOR.MINOR`` at this point) and tagged as ``base_X.Y``. Master is unfrozen and new features may again proceed. Part of unfreezing master is editing the ``AC_INIT`` statement in @@ -365,7 +365,6 @@ There is a built-in commit linter. Basic rules: `Check <https://github.com/FRRouting/frr/tree/master/.github/commitlint.config.js>`_ all the supported subsystems. -- Commit messages must start with a capital letter - Commit messages must not end with a period ``.`` Why was my pull request closed? diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 1798f1ad2a..946f0699f2 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2290,7 +2290,7 @@ Numbered Community Lists ^^^^^^^^^^^^^^^^^^^^^^^^ When number is used for BGP community list name, the number has -special meanings. Community list number in the range from 1 and 99 is +special meanings. Community list number in the range from 1 to 99 is standard community list. Community list number in the range from 100 to 500 is expanded community list. These community lists are called as numbered community lists. On the other hand normal community lists diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index d68fa67259..055841d230 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -79,6 +79,12 @@ writing, *isisd* does not support multiple ISIS processes. - wide Use new style of TLVs to carry wider metric. FRR uses this as a default value +.. clicmd:: advertise-high-metrics + + Advertise high metric value on all interfaces to gracefully shift traffic off the router. Reference: :rfc:`3277` + + For narrow metrics, the high metric value is 63; for wide metrics, 16777215; for transition metrics, 62. + .. clicmd:: set-overload-bit Set overload bit to avoid any transit traffic. diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index dd5f921bef..8644da2f08 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1499,6 +1499,10 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, return ferr_cfg_invalid("metric %d too large for narrow metric", metric); + /* Don't modify metric if advertise high metrics is configured */ + if (circuit->area && circuit->area->advertise_high_metrics) + return ferr_ok(); + /* inform ldp-sync of metric change * if ldp-sync is running need to save metric * and restore new values after ldp-sync completion. diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 5c7f610881..4a598aa8c9 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -440,6 +440,29 @@ void cli_show_isis_overload_on_startup(struct vty *vty, } /* + * XPath: /frr-isisd:isis/instance/advertise-high-metrics + */ +DEFPY_YANG(advertise_high_metrics, advertise_high_metrics_cmd, + "[no] advertise-high-metrics", + NO_STR "Advertise high metric value on all interfaces\n") +{ + nb_cli_enqueue_change(vty, "./advertise-high-metrics", NB_OP_MODIFY, + no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_advertise_high_metrics(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + if (yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " advertise-high-metrics\n"); + else if (show_defaults) + vty_out(vty, " no advertise-high-metrics\n"); +} + +/* * XPath: /frr-isisd:isis/instance/attach-send */ DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send", @@ -3160,6 +3183,8 @@ void isis_cli_init(void) install_element(ISIS_NODE, &metric_style_cmd); install_element(ISIS_NODE, &no_metric_style_cmd); + install_element(ISIS_NODE, &advertise_high_metrics_cmd); + install_element(ISIS_NODE, &area_passwd_cmd); install_element(ISIS_NODE, &domain_passwd_cmd); install_element(ISIS_NODE, &no_area_passwd_cmd); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 5caa61a4d1..7dc3a0eb3d 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -82,6 +82,13 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { + .xpath = "/frr-isisd:isis/instance/advertise-high-metrics", + .cbs = { + .cli_show = cli_show_advertise_high_metrics, + .modify = isis_instance_advertise_high_metrics_modify, + } + }, + { .xpath = "/frr-isisd:isis/instance/metric-style", .cbs = { .cli_show = cli_show_isis_metric_style, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index c90f6dca37..480b2ce041 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -26,6 +26,7 @@ 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_enabled_modify(struct nb_cb_modify_args *args); int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args); +int isis_instance_advertise_high_metrics_modify(struct nb_cb_modify_args *args); int isis_instance_metric_style_modify(struct nb_cb_modify_args *args); int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args); int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args); @@ -464,6 +465,9 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode, void cli_show_isis_overload_on_startup(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_advertise_high_metrics(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index ea021a4ff5..2b3355bc9f 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -361,6 +361,24 @@ int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args) } /* + * XPath: /frr-isisd:isis/instance/advertise-high-metrics + */ +int isis_instance_advertise_high_metrics_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool advertise_high_metrics; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + advertise_high_metrics = yang_dnode_get_bool(args->dnode, NULL); + area = nb_running_get_entry(args->dnode, NULL, true); + isis_area_advertise_high_metrics_set(area, advertise_high_metrics); + + return NB_OK; +} + +/* * XPath: /frr-isisd:isis/instance/metric-style */ int isis_instance_metric_style_modify(struct nb_cb_modify_args *args) diff --git a/isisd/isisd.c b/isisd/isisd.c index 852d7b88e8..586785b05f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2503,6 +2503,9 @@ static void common_isis_summary_vty(struct vty *vty, struct isis *isis) vty_out(vty, " RX counters per PDU type:\n"); pdu_counter_print(vty, " ", area->pdu_rx_counters); + vty_out(vty, " Advertise high metrics: %s\n", + area->advertise_high_metrics ? "Enabled" : "Disabled"); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((area->is_type & level) == 0) continue; @@ -3247,6 +3250,58 @@ void config_end_lsp_generate(struct isis_area *area) } } +void isis_area_advertise_high_metrics_set(struct isis_area *area, + bool advertise_high_metrics) +{ + struct listnode *node; + struct isis_circuit *circuit; + int max_metric; + char xpath[XPATH_MAXLEN]; + struct lyd_node *dnode; + int configured_metric_l1; + int configured_metric_l2; + + if (area->advertise_high_metrics == advertise_high_metrics) + return; + + if (advertise_high_metrics) { + if (area->oldmetric && area->newmetric) + max_metric = ISIS_NARROW_METRIC_INFINITY; + else if (area->newmetric) + max_metric = MAX_WIDE_LINK_METRIC; + else + max_metric = MAX_NARROW_LINK_METRIC; + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { + isis_circuit_metric_set(circuit, IS_LEVEL_1, + max_metric); + isis_circuit_metric_set(circuit, IS_LEVEL_2, + max_metric); + } + + area->advertise_high_metrics = true; + } else { + area->advertise_high_metrics = false; + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { + /* Get configured metric */ + snprintf(xpath, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s']", + circuit->interface->name); + dnode = yang_dnode_get(running_config->dnode, xpath); + + configured_metric_l1 = yang_dnode_get_uint32( + dnode, "./frr-isisd:isis/metric/level-1"); + configured_metric_l2 = yang_dnode_get_uint32( + dnode, "./frr-isisd:isis/metric/level-2"); + + isis_circuit_metric_set(circuit, IS_LEVEL_1, + configured_metric_l1); + isis_circuit_metric_set(circuit, IS_LEVEL_2, + configured_metric_l2); + } + } +} + /* * Returns the path of the file (non-volatile memory) that contains restart * information. diff --git a/isisd/isisd.h b/isisd/isisd.h index 0f1161e574..37a36fd37a 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -175,6 +175,8 @@ struct isis_area { uint32_t overload_on_startup_time; /* advertise prefixes of passive interfaces only? */ bool advertise_passive_only; + /* Are we advertising high metrics? */ + bool advertise_high_metrics; /* L1/L2 router identifier for inter-area traffic */ char attached_bit_send; char attached_bit_rcv_ignore; @@ -289,6 +291,8 @@ void isis_area_switchover_routes(struct isis_area *area, int family, void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); void isis_area_overload_on_startup_set(struct isis_area *area, uint32_t startup_time); +void isis_area_advertise_high_metrics_set(struct isis_area *area, + bool advertise_high_metrics); 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); diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 97e4c2ef01..42c3ef0535 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -170,7 +170,7 @@ static void adj_itimer(struct thread *thread) log_debug("%s: lsr-id %pI4", __func__, &adj->lsr_id); if (adj->source.type == HELLO_TARGETED) { - if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && + if (!CHECK_FLAG(adj->source.target->flags, F_TNBR_CONFIGURED) && adj->source.target->pw_count == 0 && adj->source.target->rlfa_count == 0) { /* remove dynamic targeted neighbor */ @@ -245,7 +245,7 @@ tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) struct tnbr * tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr) { - if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && + if (!CHECK_FLAG(tnbr->flags, (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && tnbr->pw_count == 0 && tnbr->rlfa_count == 0) { tnbr_del(xconf, tnbr); return (NULL); diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index b181e33a5b..906b5c1bf2 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -408,10 +408,10 @@ show_discovery_detail_msg(struct vty *vty, struct imsg *imsg, rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); vty_out (vty, "Local:\n"); vty_out (vty, " LSR Id: %pI4:0\n",&rtr_id); - if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED)) vty_out (vty, " Transport Address (IPv4): %s\n", log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr)); - if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_ENABLED)) vty_out (vty, " Transport Address (IPv6): %s\n", log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr)); vty_out (vty, "Discovery Sources:\n"); @@ -524,10 +524,10 @@ show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params, case IMSG_CTL_SHOW_DISCOVERY: rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); json_object_string_addf(json, "lsrId", "%pI4", &rtr_id); - if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED)) json_object_string_add(json, "transportAddressIPv4", log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr)); - if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_ENABLED)) json_object_string_add(json, "transportAddressIPv6", log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr)); json_interfaces = json_object_new_object(); @@ -968,11 +968,11 @@ show_nbr_capabilities(struct vty *vty, struct ctl_nbr *nbr) " - Typed Wildcard (0x050B)\n" " - Unrecognized Notification (0x0603)\n"); vty_out (vty, " Capabilities Received:\n"); - if (nbr->flags & F_NBR_CAP_DYNAMIC) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_DYNAMIC)) vty_out (vty," - Dynamic Announcement (0x0506)\n"); - if (nbr->flags & F_NBR_CAP_TWCARD) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_TWCARD)) vty_out (vty, " - Typed Wildcard (0x050B)\n"); - if (nbr->flags & F_NBR_CAP_UNOTIF) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_UNOTIF)) vty_out (vty," - Unrecognized Notification (0x0603)\n"); } @@ -1037,7 +1037,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) json_object_object_add(json_nbr, "receivedCapabilities", json_array); /* Dynamic Announcement (0x0506) */ - if (nbr->flags & F_NBR_CAP_DYNAMIC) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_DYNAMIC)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Dynamic Announcement"); @@ -1046,7 +1046,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) } /* Typed Wildcard (0x050B) */ - if (nbr->flags & F_NBR_CAP_TWCARD) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_TWCARD)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Typed Wildcard"); @@ -1055,7 +1055,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) } /* Unrecognized Notification (0x0603) */ - if (nbr->flags & F_NBR_CAP_UNOTIF) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_UNOTIF)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Unrecognized Notification"); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 0575f5abe1..4def3c7386 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1136,11 +1136,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } if (CHECK_FLAG(prefix_lsa->prefix.prefix_options, - OSPF6_PREFIX_OPTION_NU) - || CHECK_FLAG(prefix_lsa->prefix.prefix_options, - OSPF6_PREFIX_OPTION_LA)) { + OSPF6_PREFIX_OPTION_NU)) { if (is_debug) - zlog_debug("Prefix has NU/LA bit set, ignore"); + zlog_debug("Prefix has the NU bit set, ignore"); if (old) ospf6_route_remove(old, table); return; @@ -1153,7 +1151,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) if (!OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_R) || !OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_V6)) { if (is_debug) - zlog_debug("Prefix has NU/LA bit set, ignore"); + zlog_debug( + "Router-LSA has the V6-bit or R-bit unset, ignore"); if (old) ospf6_route_remove(old, table); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 05275c52ea..b2cdbc9b57 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1380,8 +1380,8 @@ ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p) void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, - struct in6_addr *nexthop, route_tag_t tag, - struct ospf6 *ospf6) + const struct in6_addr *nexthop, + route_tag_t tag, struct ospf6 *ospf6) { route_map_result_t ret; struct ospf6_route troute; @@ -1469,9 +1469,13 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, info->type = type; - if (nexthop_num && nexthop) + if (nexthop_num && nexthop) { ospf6_route_add_nexthop(match, ifindex, nexthop); - else + if (!IN6_IS_ADDR_UNSPECIFIED(nexthop) + && !IN6_IS_ADDR_LINKLOCAL(nexthop)) + memcpy(&info->forwarding, nexthop, + sizeof(struct in6_addr)); + } else ospf6_route_add_nexthop(match, ifindex, NULL); match->path.origin.id = htonl(info->id); @@ -1515,9 +1519,13 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, } info->type = type; - if (nexthop_num && nexthop) + if (nexthop_num && nexthop) { ospf6_route_add_nexthop(route, ifindex, nexthop); - else + if (!IN6_IS_ADDR_UNSPECIFIED(nexthop) + && !IN6_IS_ADDR_LINKLOCAL(nexthop)) + memcpy(&info->forwarding, nexthop, + sizeof(struct in6_addr)); + } else ospf6_route_add_nexthop(route, ifindex, NULL); route = ospf6_route_add(route, ospf6->external_table); diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 15982ca64c..d63e467278 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -114,7 +114,7 @@ extern int ospf6_asbr_is_asbr(struct ospf6 *o); extern void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, - struct in6_addr *nexthop, + const struct in6_addr *nexthop, route_tag_t tag, struct ospf6 *ospf6); extern void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, struct prefix *prefix, diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 72dfa240af..443032933d 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -267,7 +267,8 @@ int ospf6_num_nexthops(struct list *nh_list) return (listcount(nh_list)); } -void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr) +void ospf6_add_nexthop(struct list *nh_list, int ifindex, + const struct in6_addr *addr) { struct ospf6_nexthop *nh; struct ospf6_nexthop nh_match; diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 2d4fcc930e..c2125951ec 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -312,7 +312,7 @@ extern int ospf6_num_nexthops(struct list *nh_list); extern void ospf6_copy_nexthops(struct list *dst, struct list *src); extern void ospf6_merge_nexthops(struct list *dst, struct list *src); extern void ospf6_add_nexthop(struct list *nh_list, int ifindex, - struct in6_addr *addr); + const struct in6_addr *addr); extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route); extern int ospf6_num_nexthops(struct list *nh_list); extern bool ospf6_route_cmp_nexthops(struct ospf6_route *a, diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 6fe0a24926..0ccbb4d65d 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -252,7 +252,7 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) { struct zapi_route api; unsigned long ifindex; - struct in6_addr *nexthop; + const struct in6_addr *nexthop = &in6addr_any; struct ospf6 *ospf6; struct prefix_ipv6 p; @@ -272,7 +272,9 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) return 0; ifindex = api.nexthops[0].ifindex; - nexthop = &api.nexthops[0].gate.ipv6; + if (api.nexthops[0].type == NEXTHOP_TYPE_IPV6 + || api.nexthops[0].type == NEXTHOP_TYPE_IPV6_IFINDEX) + nexthop = &api.nexthops[0].gate.ipv6; if (IS_OSPF6_DEBUG_ZEBRA(RECV)) zlog_debug( diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index c7b501ee14..75df09ec35 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -1385,7 +1385,7 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty, nbr = pim_neighbor_find( up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, false); if (nbr) pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 8d19247415..978607d147 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -277,7 +277,7 @@ int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, New neighbor? */ - neigh = pim_neighbor_find(ifp, src_addr); + neigh = pim_neighbor_find(ifp, src_addr, false); if (!neigh) { /* Add as new neighbor */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0ba7b5a65e..d284912d1d 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1534,8 +1534,10 @@ void pim_if_create_pimreg(struct pim_instance *pim) pim->vrf->name); pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; - pim_if_new(pim->regiface, false, false, true, - false /*vxlan_term*/); + if (!pim->regiface->info) + pim_if_new(pim->regiface, false, false, true, + false /*vxlan_term*/); + /* * On vrf moves we delete the interface if there * is nothing going on with it. We cannot have diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 9edc3c1af2..0b7ea0ad9d 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -406,7 +406,7 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - pim_addr source_addr) + pim_addr source_addr, bool secondary) { struct pim_interface *pim_ifp; struct listnode *node; @@ -425,6 +425,13 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, } } + if (secondary) { + struct prefix p; + + pim_addr_to_prefix(&p, source_addr); + return pim_neighbor_find_by_secondary(ifp, &p); + } + return NULL; } diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index e00f99fe26..f7375745a1 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -38,7 +38,7 @@ struct pim_neighbor { void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - pim_addr source_addr); + pim_addr source_addr, bool secondary); struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, struct prefix *src); struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index d73f366d43..d164e7ed81 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -307,12 +307,11 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) return true; - nbr = pim_neighbor_find(ifp, znh->nexthop_addr); + nbr = pim_neighbor_find(ifp, znh->nexthop_addr, true); if (!nbr) continue; - return znh->ifindex == src_ifp->ifindex && - (!pim_addr_cmp(znh->nexthop_addr, src_ip)); + return znh->ifindex == src_ifp->ifindex; } return false; } @@ -373,12 +372,13 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, return true; /* MRIB (IGP) may be pointing at a router where PIM is down */ - nbr = pim_neighbor_find(ifp, nhaddr); + + nbr = pim_neighbor_find(ifp, nhaddr, true); + if (!nbr) continue; - return nh->ifindex == src_ifp->ifindex && - (!pim_addr_cmp(nhaddr, src_ip)); + return nh->ifindex == src_ifp->ifindex; } return false; } @@ -561,7 +561,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, src)) { nbr = pim_neighbor_find( nexthop->interface, - nexthop->mrib_nexthop_addr); + nexthop->mrib_nexthop_addr, true); if (!nbr && !if_is_loopback(nexthop->interface)) { if (PIM_DEBUG_PIM_NHT) @@ -603,7 +603,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, #else pim_addr nhaddr = nh_node->gate.ipv6; #endif - nbrs[i] = pim_neighbor_find(ifps[i], nhaddr); + nbrs[i] = pim_neighbor_find(ifps[i], nhaddr, true); if (nbrs[i] || pim_if_connected_to_source(ifps[i], src)) num_nbrs++; } @@ -954,7 +954,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, pim->vrf->vrf_id); if (ifps[i]) { nbrs[i] = pim_neighbor_find( - ifps[i], nexthop_tab[i].nexthop_addr); + ifps[i], nexthop_tab[i].nexthop_addr, true); + if (nbrs[i] || pim_if_connected_to_source(ifps[i], src)) num_nbrs++; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index a7a8b05753..1248db3de4 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -289,7 +289,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_JOIN_PRUNE: - neigh = pim_neighbor_find(ifp, sg.src); + neigh = pim_neighbor_find(ifp, sg.src, false); if (!neigh) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( @@ -304,7 +304,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_ASSERT: - neigh = pim_neighbor_find(ifp, sg.src); + neigh = pim_neighbor_find(ifp, sg.src, false); if (!neigh) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d59124cebd..e2ee6656d1 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1066,6 +1066,14 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) if (rp_info) { pim_addr nht_p; + if (pim_addr_is_any(rp_info->rp.rpf_addr)) { + if (PIM_DEBUG_PIM_NHT_RP) + zlog_debug( + "%s: Skipping NHT Register since RP is not configured for the group %pPA", + __func__, &group); + return &rp_info->rp; + } + /* Register addr with Zebra NHT */ nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 06765d93df..b17ae3131f 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -116,8 +116,8 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, i++; } else if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find(ifp, - nexthop_tab[i].nexthop_addr); + nbr = pim_neighbor_find( + ifp, nexthop_tab[i].nexthop_addr, true); if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug("ifp name: %s, pim nbr: %p", ifp->name, nbr); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index d63d530f93..b0f1158596 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -327,7 +327,7 @@ static void join_timer_stop(struct pim_upstream *up) if (up->rpf.source_nexthop.interface) nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -341,7 +341,7 @@ void join_timer_start(struct pim_upstream *up) if (up->rpf.source_nexthop.interface) { nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug( @@ -433,7 +433,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf, else { /* Remove it from jp agg from the nbr for suppression */ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); + if (nbr) { join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -485,7 +486,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_neighbor *nbr; nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); + if (nbr) join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index e39eca7a2c..29aac7f1c7 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -257,7 +257,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_neighbor *nbr; nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr); + old->rpf_addr, true); + if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 2a57f6c26e..df5d066023 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -396,12 +396,7 @@ def pytest_runtest_setup(item): def pytest_runtest_makereport(item, call): "Log all assert messages to default logger with error level" - # Nothing happened - if call.when == "call": - pause = topotest_extra_config["pause"] - else: - pause = False - + pause = bool(item.config.getoption("--pause")) title = "unset" if call.excinfo is None: diff --git a/tests/topotests/isis_advertise_high_metrics/__init__.py b/tests/topotests/isis_advertise_high_metrics/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/__init__.py diff --git a/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf new file mode 100644 index 0000000000..747c64ef4f --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r1/isisd.conf @@ -0,0 +1,19 @@ +hostname r1 +! debug isis adj-packets +! debug isis events +! debug isis update-packets +interface eth-r2 + ip router isis 1 + isis circuit-type level-2-only + isis network point-to-point +! +interface eth-r3 + ip router isis 1 + isis circuit-type level-2-only + isis metric 20 + isis network point-to-point +! +router isis 1 + is-type level-2-only + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00 +!
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf new file mode 100644 index 0000000000..b14ce0d88d --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r1/zebra.conf @@ -0,0 +1,5 @@ +interface eth-r2 + ip address 192.168.1.0/31 + +interface eth-r3 + ip address 192.168.1.2/31
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf new file mode 100644 index 0000000000..cee62ad57a --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r2/isisd.conf @@ -0,0 +1,18 @@ +hostname r2 +! debug isis adj-packets +! debug isis events +! debug isis update-packets +interface eth-r1 + ip router isis 1 + isis circuit-type level-2-only + isis network point-to-point +! +interface eth-r4 + ip router isis 1 + isis circuit-type level-2-only + isis network point-to-point +! +router isis 1 + is-type level-2-only + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 +!
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf new file mode 100644 index 0000000000..01de593415 --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r2/zebra.conf @@ -0,0 +1,5 @@ +interface eth-r1 + ip address 192.168.1.1/31 + +interface eth-r4 + ip address 192.168.1.7/31
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf new file mode 100644 index 0000000000..6d795f093c --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r3/isisd.conf @@ -0,0 +1,20 @@ +hostname r3 +! debug isis adj-packets +! debug isis events +! debug isis update-packets +interface eth-r1 + ip router isis 1 + isis circuit-type level-2-only + isis metric 20 + isis network point-to-point +! +interface eth-r4 + ip router isis 1 + isis circuit-type level-2-only + isis metric 20 + isis network point-to-point +! +router isis 1 + is-type level-2-only + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 +!
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf new file mode 100644 index 0000000000..668431ca4f --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r3/zebra.conf @@ -0,0 +1,5 @@ +interface eth-r1 + ip address 192.168.1.3/31 + +interface eth-r4 + ip address 192.168.1.4/31
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf b/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf new file mode 100644 index 0000000000..b281014b9e --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r4/isisd.conf @@ -0,0 +1,19 @@ +hostname r4 +! debug isis adj-packets +! debug isis events +! debug isis update-packets +interface eth-r2 + ip router isis 1 + isis circuit-type level-2-only + isis network point-to-point +! +interface eth-r3 + ip router isis 1 + isis circuit-type level-2-only + isis metric 20 + isis network point-to-point +! +router isis 1 + is-type level-2-only + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00 +!
\ No newline at end of file diff --git a/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf b/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf new file mode 100644 index 0000000000..6819dbb89e --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/r4/zebra.conf @@ -0,0 +1,5 @@ +interface eth-r2 + ip address 192.168.1.6/31 + +interface eth-r3 + ip address 192.168.1.5/31 diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py new file mode 100644 index 0000000000..5eef879e3f --- /dev/null +++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python + +# +# test_isis_advertise_high_metrics.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +r""" +test_isis_advertise_high_metrics.py: Advertise High Metrics FRR ISIS Test +""" + +import os +import re +import sys +import pytest +import json +from time import sleep +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.common_config import ( + retry, + stop_router, + start_router, +) +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.isisd] + + +def build_topo(tgen): + "Build function" + + # Add ISIS routers: + # r2 + # / \ + # r1 r4 + # \ / + # r3 + + # + # Define FRR Routers + # + for router in ["r1", "r2", "r3", "r4"]: + tgen.add_router(router) + # + # Define connections + # + switch = tgen.add_switch("s0") + switch.add_link(tgen.gears["r1"], nodeif="eth-r2") + switch.add_link(tgen.gears["r2"], nodeif="eth-r1") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"], nodeif="eth-r3") + switch.add_link(tgen.gears["r3"], nodeif="eth-r1") + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"], nodeif="eth-r4") + switch.add_link(tgen.gears["r4"], nodeif="eth-r2") + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"], nodeif="eth-r4") + switch.add_link(tgen.gears["r4"], nodeif="eth-r3") + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +@retry(retry_timeout=60) +def _check_interface_metrics(router, expected_metrics): + "Verfiy metrics on router's isis interfaces" + + tgen = get_topogen() + router = tgen.gears[router] + logger.info(f"check_interface_metrics {router}") + isis_interface_output = router.vtysh_cmd( + "show isis interface detail json" + ) + + intf_json = json.loads(isis_interface_output) + for i in range(len(expected_metrics)): + metric = intf_json["areas"][0]["circuits"][i]["interface"]["levels"][0]["metric"] + if (metric != expected_metrics[i]): + intf_name = intf_json["areas"][0]["circuits"][i]["interface"]["name"] + return "{} with expected metric {} on {} got {}".format( + router.name, expected_metrics[i], intf_name, metric + ) + return True + + +def check_interface_metrics(router, expected_metrics): + "Verfiy metrics on router's isis interfaces" + + assertmsg = _check_interface_metrics( + router, expected_metrics + ) + assert assertmsg is True, assertmsg + + +@retry(retry_timeout=60) +def _check_lsp_metrics(router, lsp, expected_metrics): + "Verfiy metrics on router's lsp" + tgen = get_topogen() + router = tgen.gears[router] + logger.info(f"check_lsp_metrics {router}") + isis_lsp_output = router.vtysh_cmd( + "show isis database detail {}".format(lsp) + ) + + metrics_list = [int(i) for i in re.findall(r"Metric: (\d+)", isis_lsp_output)] + if len(metrics_list) == 0: + return False + for metric in metrics_list: + if metric not in expected_metrics: + return "{} with expected metrics {} got {}".format( + router.name, expected_metrics, metrics_list + ) + + return True + + +def check_lsp_metrics(router, lsp, expected_metrics): + "Verfiy metrics on router's lsp" + + assertmsg = _check_lsp_metrics( + router, lsp, expected_metrics + ) + assert assertmsg is True, assertmsg + + +@retry(retry_timeout=60) +def _check_ip_route(router, destination, expected_interface): + "Verfiy IS-IS route" + + tgen = get_topogen() + router = tgen.gears[router] + logger.info(f"check_ip_route {router}") + route_output = router.vtysh_cmd( + "show ip route {} json".format(destination) + ) + route_json = json.loads(route_output) + + interface = route_json[destination][0]["nexthops"][0]["interfaceName"] + + if (interface != expected_interface): + return "{} with expected route to {} got {} expected {}".format( + router.name, destination, interface, expected_interface + ) + + return True + + +def check_ip_route(router, destination, expected_interface): + "Verfiy IS-IS route" + + assertmsg = _check_ip_route( + router, destination, expected_interface + ) + assert assertmsg is True, assertmsg + + +def test_isis_daemon_up(): + "Check isis daemon up before starting test" + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for router in ["r1", "r2", "r3", "r4"]: + r = tgen.gears[router] + daemons = r.vtysh_cmd( + "show daemons" + ) + assert "isisd" in daemons + + # Verify initial metric values. + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + check_lsp_metrics("r2", "r2.00-00", [10, 10]) + check_lsp_metrics("r3", "r3.00-00", [20, 20]) + check_lsp_metrics("r4", "r4.00-00", [10, 20]) + + +def test_isis_advertise_high_metrics(): + "Check that advertise high metrics behaves as expected" + + tgen = get_topogen() + net = get_topogen().net + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing advertise high metrics basic behavior") + + # Confirm low metrics values on each isis interface on r1 + r1 = tgen.gears["r1"] + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + # Configure advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + advertise-high-metrics + """ + ) + + # Confirm high wide metrics values on each isis interface on r1 + check_interface_metrics("r1", [16777215]) + + # Confirm high wide metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [16777215]) + + # Remove advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + no advertise-high-metrics + """ + ) + + # Confirm low metrics values on each isis interface on r1 + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + +def test_isis_advertise_high_metrics_narrow(): + "Check that advertise high metrics behaves as expected with narrow metrics" + + tgen = get_topogen() + net = get_topogen().net + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing advertise high metrics with narrow metric style") + + r1 = tgen.gears["r1"] + + # Configure narrow metric-style + r1.vtysh_cmd( + f""" + configure + router isis 1 + metric-style narrow + """ + ) + + # Confirm low metrics values on each isis interface on r1 + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + # Configure advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + advertise-high-metrics + """ + ) + + # Confirm high narrow metrics values on each isis interface on r1 + check_interface_metrics("r1", [63]) + + # Confirm high narrow metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [63]) + + # Remove advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + no advertise-high-metrics + """ + ) + + # Confirm low metrics values on each isis interface on r1 + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + # Remove narrow metric-style + r1.vtysh_cmd( + f""" + configure + router isis 1 + no metric-style narrow + """ + ) + + +def test_isis_advertise_high_metrics_transition(): + "Check that advertise high metrics behaves as expected with transition metrics" + tgen = get_topogen() + net = get_topogen().net + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing advertise high metrics with transition metric style") + + r1 = tgen.gears["r1"] + + # Configure transition metric-style + r1.vtysh_cmd( + f""" + configure + router isis 1 + metric-style transition + """ + ) + + # Confirm low metrics values on each isis interface on r1 + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + # Configure advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + advertise-high-metrics + """ + ) + + # Confirm high transition metrics values on each isis interface on r1 + check_interface_metrics("r1", [62]) + + # Confirm high transition metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [62]) + + # Remove advertise high metrics + r1.vtysh_cmd( + f""" + configure + router isis 1 + no advertise-high-metrics + """ + ) + + # Confirm low metrics values on each isis interface on r1 + check_interface_metrics("r1", [10, 20]) + + # Confirm low metrics values within isis database on r1 + check_lsp_metrics("r1", "r1.00-00", [10, 20]) + + # Remove narrow metric-style + r1.vtysh_cmd( + f""" + configure + router isis 1 + no metric-style transition + """ + ) + + +def test_isis_advertise_high_metrics_route(): + """ + Topology: + + r2 + / \ + r1 r4 + \ / + r3 + + Devices are configured with preferred route between r1 and r4: + r1 -> r2 -> r4 + Configure "advertise-high-metrics" on r2 and check that preferred route is: + r1 -> r3 -> r4. + Shut r3 and check that preferred route is: + r1 -> r2 -> r4. + """ + tgen = get_topogen() + net = get_topogen().net + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing advertise high metrics route behavior") + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + # Verify the preferred path from r1 to r4 (192.168.1.6) is currently via 192.168.1.1, eth-r2 + check_ip_route("r1", "192.168.1.6/31", "eth-r2") + + # Configure advertise high metrics on r2 + r2.vtysh_cmd( + f""" + configure + router isis 1 + advertise-high-metrics + """ + ) + + # Verify the preferred path from r1 to r4 (192.168.1.6) is now via 192.168.1.3, eth-r3 + check_ip_route("r1", "192.168.1.6/31", "eth-r3") + + # Shutdown r3 + logger.info("Stop router r3") + stop_router(tgen, "r3") + + # Verify the preferred path from r1 to r4 (192.168.1.6) is now via 192.168.1.1, eth-r2 + check_ip_route("r1", "192.168.1.6/31", "eth-r2") + + # Start r3 + logger.info("Start router r3") + start_router(tgen, "r3") + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index ff3ba5d12b..0c2cf232fb 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1169,6 +1169,13 @@ module frr-isisd { "Define the style of TLVs metric supported."; } + leaf advertise-high-metrics { + type boolean; + default "false"; + description + "Advertise high metric value on all interfaces."; + } + leaf purge-originator { type boolean; default "false"; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 59152df2f1..1ff188c76d 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -121,8 +121,6 @@ static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop) stream_putl(s, nexthop->ifindex); break; case NEXTHOP_TYPE_IPV6: - stream_put(s, &nexthop->gate.ipv6, 16); - break; case NEXTHOP_TYPE_IPV6_IFINDEX: stream_put(s, &nexthop->gate.ipv6, 16); stream_putl(s, nexthop->ifindex); |
