diff options
73 files changed, 1183 insertions, 963 deletions
diff --git a/babeld/babeld.c b/babeld/babeld.c index f61eac000f..0104620cd5 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -716,7 +716,7 @@ DEFUN (babel_set_smoothing_half_life, DEFUN (babel_distribute_list, babel_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -736,7 +736,7 @@ DEFUN (babel_distribute_list, DEFUN (babel_no_distribute_list, babel_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" @@ -758,7 +758,7 @@ DEFUN (babel_no_distribute_list, DEFUN (babel_ipv6_distribute_list, babel_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "IPv6\n" "Filter networks in routing updates\n" "Specify a prefix\n" @@ -779,7 +779,7 @@ DEFUN (babel_ipv6_distribute_list, DEFUN (babel_no_ipv6_distribute_list, babel_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", NO_STR "IPv6\n" "Filter networks in routing updates\n" diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index a03fb9f216..4091ab9caa 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -579,7 +579,7 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, pl = pl_find(label); if (pl) bs = pl->pl_bs; - } else { + } else if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -599,6 +599,9 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, } bs = bs_peer_find(&bpc); + } else { + vty_out(vty, "%% Invalid arguments\n"); + return NULL; } /* Find peer data. */ diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index d227cf7241..cafcc8e9c7 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -65,7 +65,7 @@ static inline int bgp_is_withdraw_label(mpls_label_t *label) return 0; } -static inline int bgp_is_valid_label(mpls_label_t *label) +static inline int bgp_is_valid_label(const mpls_label_t *label) { uint8_t *t = (uint8_t *)label; if (!t) @@ -99,7 +99,7 @@ static inline void bgp_unregister_for_label(struct bgp_dest *dest) } /* Label stream to value */ -static inline uint32_t label_pton(mpls_label_t *label) +static inline uint32_t label_pton(const mpls_label_t *label) { uint8_t *t = (uint8_t *)label; return ((((unsigned int)t[0]) << 12) | (((unsigned int)t[1]) << 4) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4b798cc264..fdaee9b600 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -102,6 +102,10 @@ DEFINE_HOOK(bgp_rpki_prefix_status, const struct prefix *prefix), (peer, attr, prefix)); +/* Render dest to prefix_rd based on safi */ +static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, + safi_t safi); + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -10712,14 +10716,15 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, enum bgp_show_type type, - void *output_arg, char *rd, int is_last, + void *output_arg, const char *rd, int is_last, unsigned long *output_cum, unsigned long *total_cum, unsigned long *json_header_depth, uint16_t show_flags, enum rpki_states rpki_target_state) { struct bgp_path_info *pi; struct bgp_dest *dest; - int header = 1; + bool header = true; + bool json_detail_header = false; int display; unsigned long output_count = 0; unsigned long total_count = 0; @@ -10731,7 +10736,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL); if (output_cum && *output_cum != 0) - header = 0; + header = false; if (use_json && !*json_header_depth) { if (all) @@ -10761,10 +10766,19 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, " \"%s\" : { ", rd); } + /* Check for 'json detail', where we need header output once per dest */ + if (use_json && CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL) && + type != bgp_show_type_dampend_paths && + type != bgp_show_type_damp_neighbor && + type != bgp_show_type_flap_statistics && + type != bgp_show_type_flap_neighbor) + json_detail_header = true; + /* Start processing of routes. */ for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); enum rpki_states rpki_curr_state = RPKI_NOT_BEING_USED; + bool json_detail = json_detail_header; pi = bgp_dest_get_bgp_path_info(dest); if (pi == NULL) @@ -11016,8 +11030,28 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, else vty_out(vty, (wide ? BGP_SHOW_HEADER_WIDE : BGP_SHOW_HEADER)); - header = 0; + header = false; + + } else if (json_detail && json_paths != NULL) { + const struct prefix_rd *prd; + json_object *jtemp; + + /* Use common detail header, for most types; + * need a json 'object'. + */ + + jtemp = json_object_new_object(); + prd = bgp_rd_from_dest(dest, safi); + + route_vty_out_detail_header( + vty, bgp, dest, prd, table->afi, + safi, jtemp); + + json_object_array_add(json_paths, jtemp); + + json_detail = false; } + if (rd != NULL && !display && !output_count) { if (!use_json) vty_out(vty, @@ -11176,6 +11210,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, } return CMD_SUCCESS; } + static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_show_type type, void *output_arg, uint16_t show_flags, enum rpki_states rpki_target_state) @@ -11260,7 +11295,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, /* Header of detailed BGP route information */ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, - struct bgp_dest *dest, struct prefix_rd *prd, + struct bgp_dest *dest, + const struct prefix_rd *prd, afi_t afi, safi_t safi, json_object *json) { struct bgp_path_info *pi; @@ -11470,7 +11506,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } } -static void bgp_show_path_info(struct prefix_rd *pfx_rd, +static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json, enum bgp_path_type pathtype, @@ -11530,6 +11566,23 @@ static void bgp_show_path_info(struct prefix_rd *pfx_rd, } } +/* + * Return rd based on safi + */ +static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, + safi_t safi) +{ + switch (safi) { + case SAFI_MPLS_VPN: + case SAFI_ENCAP: + case SAFI_EVPN: + return (struct prefix_rd *)(bgp_dest_get_prefix(dest)); + default: + return NULL; + + } +} + /* Display specified route of BGP table. */ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, @@ -12484,7 +12537,7 @@ DEFPY (show_ip_bgp_instance_all, JSON_STR "Increase table width for longer prefixes\n") { - afi_t afi = AFI_IP; + afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; struct bgp *bgp = NULL; int idx = 0; @@ -14086,7 +14139,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, "Detailed information on flowspec entries\n" JSON_STR) { - afi_t afi = AFI_IP; + afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; struct bgp *bgp = NULL; int idx = 0; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 46802d0d14..2fd80495d9 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -784,7 +784,7 @@ extern bool bgp_zebra_has_route_changed(struct bgp_path_info *selected); extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, - struct prefix_rd *prd, afi_t afi, + const struct prefix_rd *prd, afi_t afi, safi_t safi, json_object *json); extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 3fc478bc97..aa59499b04 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -4004,7 +4004,7 @@ static void bgp_route_map_event(const char *rmap_name) DEFUN_YANG (match_mac_address, match_mac_address_cmd, - "match mac address WORD", + "match mac address ACCESSLIST_MAC_NAME", MATCH_STR "mac address\n" "Match address of route\n" @@ -4024,7 +4024,7 @@ DEFUN_YANG (match_mac_address, DEFUN_YANG (no_match_mac_address, no_match_mac_address_cmd, - "no match mac address WORD", + "no match mac address ACCESSLIST_MAC_NAME", NO_STR MATCH_STR "mac\n" @@ -4576,7 +4576,7 @@ DEFUN_YANG (no_match_probability, DEFPY_YANG (match_ip_route_source, match_ip_route_source_cmd, - "match ip route-source WORD", + "match ip route-source ACCESSLIST4_NAME", MATCH_STR IP_STR "Match advertising source address of route\n" @@ -4600,7 +4600,7 @@ DEFPY_YANG (match_ip_route_source, DEFUN_YANG (no_match_ip_route_source, no_match_ip_route_source_cmd, - "no match ip route-source [WORD]", + "no match ip route-source [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 65806bb5f4..3725f242e1 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7048,7 +7048,7 @@ DEFUN (no_neighbor_interface, DEFUN (neighbor_distribute_list, neighbor_distribute_list_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list WORD <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" @@ -7079,7 +7079,7 @@ DEFUN (neighbor_distribute_list, ALIAS_HIDDEN( neighbor_distribute_list, neighbor_distribute_list_hidden_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list WORD <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "IP Access-list name\n" @@ -7088,7 +7088,7 @@ ALIAS_HIDDEN( DEFUN (no_neighbor_distribute_list, no_neighbor_distribute_list_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list WORD <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -7118,7 +7118,7 @@ DEFUN (no_neighbor_distribute_list, ALIAS_HIDDEN( no_neighbor_distribute_list, no_neighbor_distribute_list_hidden_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list WORD <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "IP Access-list name\n" diff --git a/debian/changelog b/debian/changelog index 99c75106db..f5b392274a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,20 @@ -frr (8.1~dev-1) UNRELEASED; urgency=medium +frr (8.2~dev-1) UNRELEASED; urgency=medium * New upstream release... - -- Ondřej Surý <ondrej@debian.org> Tue, 04 May 2021 22:52:47 +0200 + -- Jafar Al-Gharaibeh <jafar@atcorp.com> Mon, 08 Nov 2021 10:00:00 +0500 + +frr (8.1-0) unstable; urgency=medium + + * New upstream release FRR 8.1 + + -- Jafar Al-Gharaibeh <jafar@atcorp.com> Tue, 02 Nov 2021 14:00:00 +0500 + +frr (8.0-0) unstable; urgency=medium + + * New upstream release FRR 8.0 + + -- Martin Winter <mwinter@opensourcerouting.org> Wed, 21 Jul 2021 13:42:00 +0200 frr (7.5.1-1) unstable; urgency=medium diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst index af1677e89e..406d22d618 100644 --- a/doc/developer/building-frr-for-archlinux.rst +++ b/doc/developer/building-frr-for-archlinux.rst @@ -11,7 +11,9 @@ Installing Dependencies git autoconf automake libtool make cmake pcre readline texinfo \ pkg-config pam json-c bison flex python-pytest \ c-ares python python2-ipaddress python-sphinx \ - net-snmp perl libcap libelf + net-snmp perl libcap libelf libunwind + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index ce11126f70..c40b5de594 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -22,7 +22,9 @@ Add packages: readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ python-devel python-sphinx libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 109a7866d9..659752f6df 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -15,7 +15,9 @@ Add packages: automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python2-pytest \ c-ares-devel python2-devel libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index f8d8025f62..b2fdef9990 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,9 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libcap-dev libelf-dev + libsnmp-dev libcap-dev libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 6ce76ba158..dc869ece10 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -15,7 +15,9 @@ Installing Dependencies readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ python3-sphinx perl-core patch libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index e85cb80053..5e70b81d43 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -17,7 +17,9 @@ is first package install and asked) :: pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py36-pytest c-ares python3.6 py36-sphinx + bison flex py36-pytest c-ares python3.6 py36-sphinx libunwind + +.. include:: building-libunwind-note.rst Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index b97538b763..808207b831 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -17,7 +17,9 @@ is first package install and asked) .. code-block:: shell pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py36-pytest c-ares python3.6 py36-sphinx texinfo + bison flex py36-pytest c-ares python3.6 py36-sphinx texinfo libunwind + +.. include:: building-libunwind-note.rst Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst index ee6a36a14b..d9800a1638 100644 --- a/doc/developer/building-frr-for-opensuse.rst +++ b/doc/developer/building-frr-for-opensuse.rst @@ -14,7 +14,9 @@ Installing Dependencies readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\ pam-devel python3-pytest bison flex c-ares-devel python3-devel\ python3-Sphinx perl patch libcap-devel libyang-devel \ - libelf-devel + libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 3e8c6c0d0b..fcfd94ec2c 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -15,7 +15,9 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl libcap-dev \ - libelf-dev + libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index 28e7ca6518..fdfc25da9d 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -15,7 +15,9 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl \ - libcap-dev python2 libelf-dev + libcap-dev python2 libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst Note that Ubuntu 20 no longer installs python 2.x, so it must be installed explicitly. Ensure that your system has a symlink named diff --git a/doc/developer/building-libunwind-note.rst b/doc/developer/building-libunwind-note.rst new file mode 100644 index 0000000000..0beb1f8d37 --- /dev/null +++ b/doc/developer/building-libunwind-note.rst @@ -0,0 +1,6 @@ +.. note:: + + The ``libunwind`` library is optional but highly recommended, as it improves + backtraces printed for crashes and debugging. However, if it is not + available for some reason, it can simply be left out without any loss of + functionality. diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 61df6e0e60..79f8233978 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -136,6 +136,7 @@ language = None # directories to ignore when looking for source files. exclude_patterns = [ "_build", + "building-libunwind-note.rst", "building-libyang.rst", "topotests-snippets.rst", "topotests-markers.rst", diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index d16420c7e7..c8654d6725 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -23,6 +23,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1804.rst \ doc/developer/building-frr-for-ubuntu2004.rst \ + doc/developer/building-libunwind-note.rst \ doc/developer/building-libyang.rst \ doc/developer/building.rst \ doc/developer/cli.rst \ diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 16708adb50..69f276d551 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -244,6 +244,42 @@ Basic Config Commands Use unbuffered output for log and debug messages; normally there is some internal buffering. +.. clicmd:: log unique-id + + Include ``[XXXXX-XXXXX]`` log message unique identifier in the textual part + of log messages. This is enabled by default, but can be disabled with + ``no log unique-id``. Please make sure the IDs are enabled when including + logs for FRR bug reports. + + The unique identifiers are automatically generated based on source code + file name, format string (before filling out) and severity. They do not + change "randomly", but some cleanup work may cause large chunks of ID + changes between releases. The IDs always start with a letter, consist of + letters and numbers (and a dash for readability), are case insensitive, and + ``I``, ``L``, ``O`` & ``U`` are excluded. + + This option will not affect future logging targets which allow putting the + unique identifier in auxiliary metadata outside the log message text + content. (No such logging target exists currently, but RFC5424 syslog and + systemd's journald both support it.) + +.. clicmd:: debug unique-id XXXXX-XXXXX backtrace + + Print backtraces (call stack) for specific log messages, identified by + their unique ID (see above.) Includes source code location and current + event handler being executed. On some systems you may need to install a + `debug symbols` package to get proper function names rather than raw code + pointers. + + This command can be issued inside and outside configuration mode, and is + saved to configuration only if it was given in configuration mode. + + .. warning:: + + Printing backtraces can significantly slow down logging calls and cause + log files to quickly balloon in size. Remember to disable backtraces + when they're no longer needed. + .. clicmd:: service password-encryption Encrypt password. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 68b4d74dd6..db59c42773 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -3006,8 +3006,8 @@ following zebra command - .. clicmd:: evpn mh startup-delay (0-3600) -+Support with VRF network namespace backend -+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Support with VRF network namespace backend +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is possible to separate overlay networks contained in VXLAN interfaces from underlay networks by using VRFs. VRF-lite and VRF-netns backends can be used for that. In the latter case, it is necessary to set both bridge and vxlan interface diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index 65fa95b652..d9b500a8fd 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -858,7 +858,7 @@ ALIAS(no_match_interface, no_match_interface_val_cmd, "no match interface WORD", DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop WORD", + "match ip next-hop ACCESSLIST4_NAME", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -884,7 +884,7 @@ DEFUN (no_match_ip_next_hop, } ALIAS(no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, - "no match ip next-hop WORD", NO_STR MATCH_STR IP_STR + "no match ip next-hop ACCESSLIST4_NAME", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP Access-list name\n") @@ -927,7 +927,7 @@ ALIAS(no_match_ip_next_hop_prefix_list, DEFUN (match_ip_address, match_ip_address_cmd, - "match ip address WORD", + "match ip address ACCESSLIST4_NAME", MATCH_STR IP_STR "Match address of route\n" @@ -952,7 +952,7 @@ DEFUN (no_match_ip_address, } ALIAS(no_match_ip_address, no_match_ip_address_val_cmd, - "no match ip address WORD", NO_STR MATCH_STR IP_STR + "no match ip address ACCESSLIST4_NAME", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP Access-list name\n") @@ -1124,7 +1124,7 @@ ALIAS(no_set_tag, no_set_tag_val_cmd, "no set tag (0-65535)", NO_STR SET_STR DEFUN (eigrp_distribute_list, eigrp_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -1144,7 +1144,7 @@ DEFUN (eigrp_distribute_list, DEFUN (eigrp_no_distribute_list, eigrp_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index c09bdf4f4f..8810d6107d 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -116,7 +116,7 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) * Default values */ #ifndef FABRICD - circuit->is_type = yang_get_default_enum( + circuit->is_type_config = yang_get_default_enum( "/frr-interface:lib/interface/frr-isisd:isis/circuit-type"); circuit->flags = 0; @@ -156,7 +156,7 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) circuit->level_arg[i].circuit = circuit; } #else - circuit->is_type = IS_LEVEL_1_AND_2; + circuit->is_type_config = IS_LEVEL_1_AND_2; circuit->flags = 0; circuit->pad_hellos = 1; for (i = 0; i < 2; i++) { @@ -172,6 +172,8 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) } #endif /* ifndef FABRICD */ + circuit->is_type = circuit->is_type_config; + circuit_mt_init(circuit); isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1); isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2); @@ -253,6 +255,10 @@ void isis_circuit_deconfigure(struct isis_circuit *circuit, /* Free the index of SRM and SSN flags */ flags_free_index(&area->flags, circuit->idx); circuit->idx = 0; + + /* Reset IS type to configured */ + circuit->is_type = circuit->is_type_config; + /* Remove circuit from area */ assert(circuit->area == area); listnode_delete(area->circuit_list, circuit); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index e7b7a2434d..e286194d3e 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -122,6 +122,7 @@ struct isis_circuit { */ char *tag; /* area tag */ struct isis_passwd passwd; /* Circuit rx/tx password */ + int is_type_config; /* configured circuit is type */ int is_type; /* circuit is type == level of circuit * differentiated from circuit type (media) */ uint32_t hello_interval[ISIS_LEVELS]; /* hello-interval in seconds */ diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 195a3fcd2f..bf03d0a050 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -70,43 +70,12 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, return ret; } -struct if_iter { - struct vty *vty; - const char *tag; -}; - -static int if_iter_cb(const struct lyd_node *dnode, void *arg) -{ - struct if_iter *iter = arg; - const char *tag; - - if (!yang_dnode_exists(dnode, "frr-isisd:isis/area-tag")) - return YANG_ITER_CONTINUE; - - tag = yang_dnode_get_string(dnode, "frr-isisd:isis/area-tag"); - if (strmatch(tag, iter->tag)) { - char xpath[XPATH_MAXLEN]; - const char *name = yang_dnode_get_string(dnode, "name"); - const char *vrf = yang_dnode_get_string(dnode, "vrf"); - - snprintf( - xpath, XPATH_MAXLEN, - "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", - name, vrf); - nb_cli_enqueue_change(iter->vty, xpath, NB_OP_DESTROY, NULL); - } - - return YANG_ITER_CONTINUE; -} - DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag [vrf NAME$vrf_name]", NO_STR ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag\n" VRF_CMD_HELP_STR) { - struct if_iter iter; - if (!vrf_name) vrf_name = VRF_DEFAULT_NAME; @@ -118,12 +87,6 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, return CMD_ERR_NOTHING_TODO; } - iter.vty = vty; - iter.tag = tag; - - yang_dnode_iterate(if_iter_cb, &iter, vty->candidate_config->dnode, - "/frr-interface:lib/interface[vrf='%s']", vrf_name); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes_clear_pending( @@ -164,45 +127,11 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - char inst_xpath[XPATH_MAXLEN]; - const struct lyd_node *if_dnode, *inst_dnode; - const char *circ_type = NULL; - const char *vrf_name; - struct interface *ifp; - - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - /* if instance exists then inherit its type, create it otherwise */ - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - else - nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY, tag); nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", NB_OP_MODIFY, "true"); - if (circ_type) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); - - /* check if the interface is a loopback and if so set it as passive */ - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback_or_vrf(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -221,45 +150,11 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - char inst_xpath[XPATH_MAXLEN]; - const struct lyd_node *if_dnode, *inst_dnode; - const char *circ_type = NULL; - const char *vrf_name; - struct interface *ifp; - - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - /* if instance exists then inherit its type, create it otherwise */ - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - else - nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY, tag); nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "true"); - if (circ_type) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); - - /* check if the interface is a loopback and if so set it as passive */ - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback_or_vrf(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -1116,7 +1011,7 @@ void cli_show_isis_spf_ietf_backoff(struct vty *vty, * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name */ DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd, - "spf prefix-priority <critical|high|medium>$priority WORD$acl_name", + "spf prefix-priority <critical|high|medium>$priority ACCESSLIST_NAME$acl_name", "SPF configuration\n" "Configure a prefix priority list\n" "Specify critical priority prefixes\n" @@ -1134,7 +1029,7 @@ DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd, } DEFPY_YANG(no_spf_prefix_priority, no_spf_prefix_priority_cmd, - "no spf prefix-priority <critical|high|medium>$priority [WORD]", + "no spf prefix-priority <critical|high|medium>$priority [ACCESSLIST_NAME]", NO_STR "SPF configuration\n" "Configure a prefix priority list\n" @@ -2545,41 +2440,8 @@ DEFPY_YANG(no_isis_circuit_type, no_isis_circuit_type_cmd, "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { - char inst_xpath[XPATH_MAXLEN]; - const struct lyd_node *if_dnode, *inst_dnode; - const char *vrf_name; - const char *tag; - const char *circ_type = NULL; - - /* - * Default value depends on whether the circuit is part of an area, - * and the is-type of the area if there is one. So we need to do this - * here. - */ - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!yang_dnode_exists(if_dnode, "frr-isisd:isis/area-tag")) { - vty_out(vty, "%% ISIS is not configured on the interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - tag = yang_dnode_get_string(if_dnode, "frr-isisd:isis/area-tag"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); + NB_OP_MODIFY, NULL); return nb_cli_apply_changes(vty, NULL); } diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 0b987fc5cf..26c68db762 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -128,7 +128,7 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) { - if (circuit->state != C_STATE_UP) { + if (!circuit->area) { circuit->is_type = newtype; return; } @@ -151,6 +151,11 @@ void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) return; } + if (circuit->state != C_STATE_UP) { + circuit->is_type = newtype; + return; + } + if (!circuit->is_passive) { switch (circuit->is_type) { case IS_LEVEL_1: diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 62d8b8334a..9d494121c8 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -486,6 +486,9 @@ void isis_if_ldp_sync_enable(struct isis_circuit *circuit) if (if_is_loopback(circuit->interface)) return; + if (circuit->interface->vrf->vrf_id != VRF_DEFAULT) + return; + ils_debug("ldp_sync: enable if %s", circuit->interface->name); if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 4a01c728f0..07af46c04a 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2526,31 +2526,12 @@ int lib_interface_isis_destroy(struct nb_cb_destroy_args *args) int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args) { struct isis_circuit *circuit; - struct interface *ifp; - struct vrf *vrf; - const char *area_tag, *ifname, *vrfname; if (args->event == NB_EV_VALIDATE) { - /* libyang doesn't like relative paths across module boundaries - */ - ifname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./name"); - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./vrf"); - vrf = vrf_lookup_by_name(vrfname); - assert(vrf); - ifp = if_lookup_by_name(ifname, vrf->vrf_id); - - if (!ifp) - return NB_OK; - - circuit = circuit_scan_by_ifp(ifp); - area_tag = yang_dnode_get_string(args->dnode, NULL); - if (circuit && circuit->area && circuit->area->area_tag - && strcmp(circuit->area->area_tag, area_tag)) { + circuit = nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, false); + if (circuit) { snprintf(args->errmsg, args->errmsg_len, - "ISIS circuit is already defined on %s", - circuit->area->area_tag); + "Changing area tag is not allowed"); return NB_ERR_VALIDATION; } } @@ -2565,39 +2546,15 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args) { int circ_type = yang_dnode_get_enum(args->dnode, NULL); struct isis_circuit *circuit; - struct interface *ifp; - struct vrf *vrf; - const char *ifname, *vrfname; switch (args->event) { case NB_EV_VALIDATE: - /* libyang doesn't like relative paths across module boundaries - */ - ifname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./name"); - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./vrf"); - vrf = vrf_lookup_by_name(vrfname); - assert(vrf); - ifp = if_lookup_by_name(ifname, vrf->vrf_id); - if (!ifp) - break; - - circuit = circuit_scan_by_ifp(ifp); - if (circuit && circuit->state == C_STATE_UP - && circuit->area->is_type != IS_LEVEL_1_AND_2 - && circuit->area->is_type != circ_type) { - snprintf(args->errmsg, args->errmsg_len, - "Invalid circuit level for area %s", - circuit->area->area_tag); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->is_type_config = circ_type; isis_circuit_is_type_set(circuit, circ_type); break; } @@ -2979,24 +2936,8 @@ int lib_interface_isis_network_type_modify(struct nb_cb_modify_args *args) int lib_interface_isis_passive_modify(struct nb_cb_modify_args *args) { struct isis_circuit *circuit; - struct interface *ifp; bool passive = yang_dnode_get_bool(args->dnode, NULL); - /* validation only applies if we are setting passive to false */ - if (!passive && args->event == NB_EV_VALIDATE) { - circuit = nb_running_get_entry(args->dnode, NULL, false); - if (!circuit) - return NB_OK; - ifp = circuit->interface; - if (!ifp) - return NB_OK; - if (if_is_loopback_or_vrf(ifp)) { - snprintf(args->errmsg, args->errmsg_len, - "Loopback is always passive"); - return NB_ERR_VALIDATION; - } - } - if (args->event != NB_EV_APPLY) return NB_OK; @@ -3204,19 +3145,9 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; bool ldp_sync_enable; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -3248,19 +3179,9 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; uint16_t holddown; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -3281,19 +3202,9 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) { struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; diff --git a/isisd/isisd.c b/isisd/isisd.c index 8c26a57bef..b33f272f56 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2656,10 +2656,16 @@ void isis_area_is_type_set(struct isis_area *area, int is_type) area->is_type = is_type; - /* override circuit's is_type */ + /* + * If area's IS type is strict Level-1 or Level-2, override circuit's + * IS type. Otherwise use circuit's configured IS type. + */ if (area->is_type != IS_LEVEL_1_AND_2) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) isis_circuit_is_type_set(circuit, is_type); + } else { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + isis_circuit_is_type_set(circuit, circuit->is_type_config); } spftree_area_init(area); diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index 9d3d1a606e..11d6930f06 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -253,7 +253,7 @@ DEFPY (ldp_allow_broken_lsps, DEFPY (ldp_discovery_targeted_hello_accept, ldp_discovery_targeted_hello_accept_cmd, - "[no] discovery targeted-hello accept [from WORD$from_acl]", + "[no] discovery targeted-hello accept [from ACCESSLIST_NAME$from_acl]", NO_STR "Configure discovery parameters\n" "LDP Targeted Hellos\n" @@ -288,7 +288,7 @@ DEFPY (ldp_discovery_transport_address_ipv6, DEFPY (ldp_label_local_advertise, ldp_label_local_advertise_cmd, - "[no] label local advertise [{to WORD$to_acl|for WORD$for_acl}]", + "[no] label local advertise [{to ACCESSLIST_NAME$to_acl|for ACCESSLIST_NAME$for_acl}]", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" @@ -303,7 +303,7 @@ DEFPY (ldp_label_local_advertise, DEFPY (ldp_label_local_advertise_explicit_null, ldp_label_local_advertise_explicit_null_cmd, - "[no] label local advertise explicit-null [for WORD$for_acl]", + "[no] label local advertise explicit-null [for ACCESSLIST_NAME$for_acl]", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" @@ -317,7 +317,7 @@ DEFPY (ldp_label_local_advertise_explicit_null, DEFPY (ldp_label_local_allocate, ldp_label_local_allocate_cmd, - "[no] label local allocate <host-routes$host_routes|for WORD$for_acl>", + "[no] label local allocate <host-routes$host_routes|for ACCESSLIST_NAME$for_acl>", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" @@ -331,7 +331,7 @@ DEFPY (ldp_label_local_allocate, DEFPY (ldp_label_remote_accept, ldp_label_remote_accept_cmd, - "[no] label remote accept {from WORD$from_acl|for WORD$for_acl}", + "[no] label remote accept {from ACCESSLIST_NAME$from_acl|for ACCESSLIST_NAME$for_acl}", NO_STR "Configure label control and policies\n" "Configure remote/peer label control and policies\n" diff --git a/lib/atomlist.c b/lib/atomlist.c index 3668b083d0..b7c9516a00 100644 --- a/lib/atomlist.c +++ b/lib/atomlist.c @@ -18,6 +18,8 @@ #include "config.h" #endif +#include <assert.h> + #include "atomlist.h" void atomlist_add_head(struct atomlist_head *h, struct atomlist_item *item) diff --git a/lib/elf_py.c b/lib/elf_py.c index 1c306893ad..f230add695 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -636,6 +636,9 @@ static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx) Elf_Scn *scn = elf_getscn(ef->elf, i); GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + /* virtual address is kinda meaningless for TLS sections */ + if (shdr->sh_flags & SHF_TLS) + continue; if (addr < shdr->sh_addr || addr >= shdr->sh_addr + shdr->sh_size) continue; diff --git a/lib/filter.c b/lib/filter.c index 3a86fbce93..9c80808fe8 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -612,7 +612,7 @@ DEFUN (show_mac_access_list, DEFUN (show_mac_access_list_name, show_mac_access_list_name_cmd, - "show mac access-list WORD", + "show mac access-list ACCESSLIST_MAC_NAME", SHOW_STR "mac access lists\n" "List mac access lists\n" @@ -635,7 +635,7 @@ DEFUN (show_ip_access_list, DEFUN (show_ip_access_list_name, show_ip_access_list_name_cmd, - "show ip access-list WORD [json]", + "show ip access-list ACCESSLIST4_NAME [json]", SHOW_STR IP_STR "List IP access lists\n" @@ -661,7 +661,7 @@ DEFUN (show_ipv6_access_list, DEFUN (show_ipv6_access_list_name, show_ipv6_access_list_name_cmd, - "show ipv6 access-list WORD [json]", + "show ipv6 access-list ACCESSLIST6_NAME [json]", SHOW_STR IPV6_STR "List IPv6 access lists\n" @@ -839,12 +839,62 @@ static void access_list_init_ipv4(void) install_element(ENABLE_NODE, &show_ip_access_list_name_cmd); } +static void access_list_autocomplete_afi(afi_t afi, vector comps, + struct cmd_token *token) +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get(afi); + if (master == NULL) + return; + + for (access = master->str.head; access; access = next) { + next = access->next; + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, access->name)); + } +} + static struct cmd_node access_ipv6_node = { .name = "ipv6 access list", .node = ACCESS_IPV6_NODE, .prompt = "", }; +static void access_list_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP, comps, token); + access_list_autocomplete_afi(AFI_IP6, comps, token); + access_list_autocomplete_afi(AFI_L2VPN, comps, token); +} + +static void access_list4_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP, comps, token); +} + +static void access_list6_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP6, comps, token); +} + +static void access_list_mac_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_L2VPN, comps, token); +} + +static const struct cmd_variable_handler access_list_handlers[] = { + {.tokenname = "ACCESSLIST_NAME", + .completions = access_list_autocomplete}, + {.tokenname = "ACCESSLIST4_NAME", + .completions = access_list4_autocomplete}, + {.tokenname = "ACCESSLIST6_NAME", + .completions = access_list6_autocomplete}, + {.tokenname = "ACCESSLIST_MAC_NAME", + .completions = access_list_mac_autocomplete}, + {.completions = NULL}}; + static void access_list_reset_ipv6(void) { struct access_list *access; @@ -874,6 +924,8 @@ static void access_list_init_ipv6(void) void access_list_init(void) { + cmd_variable_handler_register(access_list_handlers); + access_list_init_ipv4(); access_list_init_ipv6(); access_list_init_mac(); diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 43618094ac..fb40c527dd 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -822,7 +822,7 @@ DEFPY_YANG( ALIAS( no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd, - "no ipv6 access-list WORD$name remark LINE...", + "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...", NO_STR IPV6_STR ACCESS_LIST_STR @@ -832,7 +832,7 @@ ALIAS( DEFPY_YANG( mac_access_list, mac_access_list_cmd, - "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", + "mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", MAC_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -898,7 +898,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list, no_mac_access_list_cmd, - "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", + "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", NO_STR MAC_STR ACCESS_LIST_STR @@ -938,7 +938,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list_all, no_mac_access_list_all_cmd, - "no mac access-list WORD$name", + "no mac access-list ACCESSLIST_MAC_NAME$name", NO_STR MAC_STR ACCESS_LIST_STR @@ -955,7 +955,7 @@ DEFPY_YANG( DEFPY_YANG( mac_access_list_remark, mac_access_list_remark_cmd, - "mac access-list WORD$name remark LINE...", + "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...", MAC_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -980,7 +980,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list_remark, no_mac_access_list_remark_cmd, - "no mac access-list WORD$name remark", + "no mac access-list ACCESSLIST_MAC_NAME$name remark", NO_STR MAC_STR ACCESS_LIST_STR @@ -1004,7 +1004,7 @@ DEFPY_YANG( ALIAS( no_mac_access_list_remark, no_mac_access_list_remark_line_cmd, - "no mac access-list WORD$name remark LINE...", + "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...", NO_STR MAC_STR ACCESS_LIST_STR diff --git a/lib/frrcu.h b/lib/frrcu.h index 3808259040..ae840926b5 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -17,6 +17,8 @@ #ifndef _FRRCU_H #define _FRRCU_H +#include <assert.h> + #include "memory.h" #include "atomlist.h" diff --git a/lib/log_vty.c b/lib/log_vty.c index cbb8de8976..9911323553 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -36,6 +36,8 @@ DEFINE_HOOK(zlog_rotate, (), ()); DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty)); +static unsigned logmsgs_with_persist_bt; + static const int log_default_lvl = LOG_DEBUG; static int log_config_stdout_lvl = ZLOG_DISABLED; @@ -267,6 +269,44 @@ DEFUN_HIDDEN (no_config_log_monitor, return CMD_SUCCESS; } +DEFPY (debug_uid_backtrace, + debug_uid_backtrace_cmd, + "[no] debug unique-id UID backtrace", + NO_STR + DEBUG_STR + "Options per individual log message, by unique ID\n" + "Log message unique ID (XXXXX-XXXXX)\n" + "Add backtrace to log when message is printed\n") +{ + struct xrefdata search, *xrd; + struct xrefdata_logmsg *xrdl; + uint8_t flag; + + strlcpy(search.uid, uid, sizeof(search.uid)); + xrd = xrefdata_uid_find(&xrefdata_uid, &search); + + if (!xrd) { + vty_out(vty, "%% no log message with ID \"%s\" found\n", uid); + return CMD_WARNING; + } + if (xrd->xref->type != XREFT_LOGMSG) { + vty_out(vty, "%% ID \"%s\" is not a log message\n", uid); + return CMD_WARNING; + } + xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata); + + flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT + : LOGMSG_FLAG_EPHEMERAL; + + if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag)) + return CMD_SUCCESS; + if (flag == LOGMSG_FLAG_PERSISTENT) + logmsgs_with_persist_bt += no ? -1 : 1; + + xrdl->fl_print_bt ^= flag; + return CMD_SUCCESS; +} + static int set_log_file(struct zlog_cfg_file *target, struct vty *vty, const char *fname, int loglevel) { @@ -751,6 +791,24 @@ void log_config_write(struct vty *vty) vty_out(vty, "no log error-category\n"); if (!zlog_get_prefix_xid()) vty_out(vty, "no log unique-id\n"); + + if (logmsgs_with_persist_bt) { + struct xrefdata *xrd; + struct xrefdata_logmsg *xrdl; + + vty_out(vty, "!\n"); + + frr_each (xrefdata_uid, &xrefdata_uid, xrd) { + if (xrd->xref->type != XREFT_LOGMSG) + continue; + + xrdl = container_of(xrd, struct xrefdata_logmsg, + xrefdata); + if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT) + vty_out(vty, "debug unique-id %s backtrace\n", + xrd->uid); + } + } } static int log_vty_init(const char *progname, const char *protoname, @@ -801,4 +859,7 @@ void log_cmd_init(void) install_element(CONFIG_NODE, &config_log_filterfile_cmd); install_element(CONFIG_NODE, &no_config_log_filterfile_cmd); install_element(CONFIG_NODE, &log_immediate_mode_cmd); + + install_element(ENABLE_NODE, &debug_uid_backtrace_cmd); + install_element(CONFIG_NODE, &debug_uid_backtrace_cmd); } diff --git a/lib/resolver.c b/lib/resolver.c index 4aba909f25..e3dba5f8ae 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -14,7 +14,8 @@ #include <ares.h> #include <ares_version.h> -#include "vector.h" +#include "typesafe.h" +#include "jhash.h" #include "thread.h" #include "lib_errors.h" #include "resolver.h" @@ -27,13 +28,78 @@ struct resolver_state { ares_channel channel; struct thread_master *master; struct thread *timeout; - vector read_threads, write_threads; }; static struct resolver_state state; static bool resolver_debug; -#define THREAD_RUNNING ((struct thread *)-1) +/* a FD doesn't necessarily map 1:1 to a request; we could be talking to + * multiple caches simultaneously, to see which responds fastest. + * Theoretically we could also be using the same fd for multiple lookups, + * but the c-ares API guarantees an n:1 mapping for fd => channel. + * + * Either way c-ares makes that decision and we just need to deal with + * whatever FDs it gives us. + */ + +DEFINE_MTYPE_STATIC(LIB, ARES_FD, "c-ares (DNS) file descriptor information"); +PREDECL_HASH(resolver_fds); + +struct resolver_fd { + struct resolver_fds_item itm; + + int fd; + struct resolver_state *state; + struct thread *t_read, *t_write; +}; + +static int resolver_fd_cmp(const struct resolver_fd *a, + const struct resolver_fd *b) +{ + return numcmp(a->fd, b->fd); +} + +static uint32_t resolver_fd_hash(const struct resolver_fd *item) +{ + return jhash_1word(item->fd, 0xacd04c9e); +} + +DECLARE_HASH(resolver_fds, struct resolver_fd, itm, resolver_fd_cmp, + resolver_fd_hash); + +static struct resolver_fds_head resfds[1] = {INIT_HASH(resfds[0])}; + +static struct resolver_fd *resolver_fd_get(int fd, + struct resolver_state *newstate) +{ + struct resolver_fd ref = {.fd = fd}, *res; + + res = resolver_fds_find(resfds, &ref); + if (!res && newstate) { + res = XCALLOC(MTYPE_ARES_FD, sizeof(*res)); + res->fd = fd; + res->state = newstate; + resolver_fds_add(resfds, res); + + if (resolver_debug) + zlog_debug("c-ares registered FD %d", fd); + } + return res; +} + +static void resolver_fd_drop_maybe(struct resolver_fd *resfd) +{ + if (resfd->t_read || resfd->t_write) + return; + + if (resolver_debug) + zlog_debug("c-ares unregistered FD %d", resfd->fd); + + resolver_fds_del(resfds, resfd); + XFREE(MTYPE_ARES_FD, resfd); +} + +/* end of FD housekeeping */ static void resolver_update_timeouts(struct resolver_state *r); @@ -41,9 +107,7 @@ static int resolver_cb_timeout(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); - r->timeout = THREAD_RUNNING; ares_process(r->channel, NULL, NULL); - r->timeout = NULL; resolver_update_timeouts(r); return 0; @@ -51,17 +115,16 @@ static int resolver_cb_timeout(struct thread *t) static int resolver_cb_socket_readable(struct thread *t) { - struct resolver_state *r = THREAD_ARG(t); - int fd = THREAD_FD(t); - struct thread **t_ptr; - - vector_set_index(r->read_threads, fd, THREAD_RUNNING); - ares_process_fd(r->channel, fd, ARES_SOCKET_BAD); - if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) { - t_ptr = (struct thread **)vector_get_index(r->read_threads, fd); - thread_add_read(r->master, resolver_cb_socket_readable, r, fd, - t_ptr); - } + struct resolver_fd *resfd = THREAD_ARG(t); + struct resolver_state *r = resfd->state; + + thread_add_read(r->master, resolver_cb_socket_readable, resfd, + resfd->fd, &resfd->t_read); + /* ^ ordering important: + * ares_process_fd may transitively call THREAD_OFF(resfd->t_read) + * combined with resolver_fd_drop_maybe, so resfd may be free'd after! + */ + ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD); resolver_update_timeouts(r); return 0; @@ -69,17 +132,16 @@ static int resolver_cb_socket_readable(struct thread *t) static int resolver_cb_socket_writable(struct thread *t) { - struct resolver_state *r = THREAD_ARG(t); - int fd = THREAD_FD(t); - struct thread **t_ptr; - - vector_set_index(r->write_threads, fd, THREAD_RUNNING); - ares_process_fd(r->channel, ARES_SOCKET_BAD, fd); - if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) { - t_ptr = (struct thread **)vector_get_index(r->write_threads, fd); - thread_add_write(r->master, resolver_cb_socket_writable, r, fd, - t_ptr); - } + struct resolver_fd *resfd = THREAD_ARG(t); + struct resolver_state *r = resfd->state; + + thread_add_write(r->master, resolver_cb_socket_writable, resfd, + resfd->fd, &resfd->t_write); + /* ^ ordering important: + * ares_process_fd may transitively call THREAD_OFF(resfd->t_write) + * combined with resolver_fd_drop_maybe, so resfd may be free'd after! + */ + ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd); resolver_update_timeouts(r); return 0; @@ -89,13 +151,11 @@ static void resolver_update_timeouts(struct resolver_state *r) { struct timeval *tv, tvbuf; - if (r->timeout == THREAD_RUNNING) - return; - THREAD_OFF(r->timeout); tv = ares_timeout(r->channel, NULL, &tvbuf); if (tv) { unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000; + thread_add_timer_msec(r->master, resolver_cb_timeout, r, timeoutms, &r->timeout); } @@ -105,43 +165,27 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable, int writable) { struct resolver_state *r = (struct resolver_state *)data; - struct thread *t, **t_ptr; - - if (readable) { - t = vector_lookup(r->read_threads, fd); - if (!t) { - t_ptr = (struct thread **)vector_get_index( - r->read_threads, fd); - thread_add_read(r->master, resolver_cb_socket_readable, - r, fd, t_ptr); - } - } else { - t = vector_lookup(r->read_threads, fd); - if (t) { - if (t != THREAD_RUNNING) { - THREAD_OFF(t); - } - vector_unset(r->read_threads, fd); - } - } + struct resolver_fd *resfd; - if (writable) { - t = vector_lookup(r->write_threads, fd); - if (!t) { - t_ptr = (struct thread **)vector_get_index( - r->write_threads, fd); - thread_add_read(r->master, resolver_cb_socket_writable, - r, fd, t_ptr); - } - } else { - t = vector_lookup(r->write_threads, fd); - if (t) { - if (t != THREAD_RUNNING) { - THREAD_OFF(t); - } - vector_unset(r->write_threads, fd); - } - } + resfd = resolver_fd_get(fd, (readable || writable) ? r : NULL); + if (!resfd) + return; + + assert(resfd->state == r); + + if (!readable) + THREAD_OFF(resfd->t_read); + else if (!resfd->t_read) + thread_add_read(r->master, resolver_cb_socket_readable, resfd, + fd, &resfd->t_read); + + if (!writable) + THREAD_OFF(resfd->t_write); + else if (!resfd->t_write) + thread_add_write(r->master, resolver_cb_socket_writable, resfd, + fd, &resfd->t_write); + + resolver_fd_drop_maybe(resfd); } @@ -271,8 +315,6 @@ void resolver_init(struct thread_master *tm) struct ares_options ares_opts; state.master = tm; - state.read_threads = vector_init(1); - state.write_threads = vector_init(1); ares_opts = (struct ares_options){ .sock_state_cb = &ares_socket_cb, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 918a2ebdcb..d7d4a9a81f 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -166,7 +166,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_address, match_ip_address_cmd, - "match ip address WORD$name", + "match ip address ACCESSLIST4_NAME$name", MATCH_STR IP_STR "Match address of route\n" @@ -186,7 +186,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_address, no_match_ip_address_cmd, - "no match ip address [WORD]", + "no match ip address [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR @@ -243,7 +243,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop WORD$name", + "match ip next-hop ACCESSLIST4_NAME$name", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -263,7 +263,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_next_hop, no_match_ip_next_hop_cmd, - "no match ip next-hop [WORD]", + "no match ip next-hop [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR @@ -358,7 +358,7 @@ DEFPY_YANG( DEFPY_YANG( match_ipv6_address, match_ipv6_address_cmd, - "match ipv6 address WORD$name", + "match ipv6 address ACCESSLIST6_NAME$name", MATCH_STR IPV6_STR "Match IPv6 address of route\n" @@ -378,7 +378,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ipv6_address, no_match_ipv6_address_cmd, - "no match ipv6 address [WORD]", + "no match ipv6 address [ACCESSLIST6_NAME]", NO_STR MATCH_STR IPV6_STR diff --git a/lib/typerb.h b/lib/typerb.h index d22d864aae..75a1de77b3 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -20,6 +20,7 @@ #ifndef _FRR_TYPERB_H #define _FRR_TYPERB_H +#include <string.h> #include "typesafe.h" #ifdef __cplusplus diff --git a/lib/typesafe.c b/lib/typesafe.c index f90b59daf0..3b65a2d02a 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> #include "typesafe.h" #include "memory.h" diff --git a/lib/typesafe.h b/lib/typesafe.h index 44c42ffbca..b284397d98 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -20,7 +20,6 @@ #include <stddef.h> #include <stdint.h> #include <stdbool.h> -#include <assert.h> #include "compiler.h" #ifdef __cplusplus diff --git a/lib/vector.c b/lib/vector.c index 38f9b1b85f..5497c24280 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -136,17 +136,6 @@ int vector_set_index(vector v, unsigned int i, void *val) return i; } -/* Make a specified index slot active and return its address. */ -void **vector_get_index(vector v, unsigned int i) -{ - vector_ensure(v, i); - - if (v->active <= i) - v->active = i + 1; - - return &v->index[i]; -} - /* Look up vector. */ void *vector_lookup(vector v, unsigned int i) { diff --git a/lib/vector.h b/lib/vector.h index 6208be1cc7..71c497a1b7 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -55,7 +55,6 @@ extern void vector_ensure(vector v, unsigned int num); extern int vector_empty_slot(vector v); extern int vector_set(vector v, void *val); extern int vector_set_index(vector v, unsigned int i, void *val); -extern void **vector_get_index(vector v, unsigned int i); extern void vector_unset(vector v, unsigned int i); extern void vector_unset_value(vector v, void *val); extern void vector_remove(vector v, unsigned int ix); diff --git a/lib/xref.c b/lib/xref.c index a41f91a228..0d3549d062 100644 --- a/lib/xref.c +++ b/lib/xref.c @@ -35,6 +35,8 @@ struct xref_block *xref_blocks; static struct xref_block **xref_block_last = &xref_blocks; +struct xrefdata_uid_head xrefdata_uid = INIT_RBTREE_UNIQ(xrefdata_uid); + static void base32(uint8_t **inpos, int *bitpos, char *out, size_t n_chars) { @@ -109,6 +111,8 @@ static void xref_add_one(const struct xref *xref) base32(&h, &bitpos, &xrefdata->uid[0], 5); xrefdata->uid[5] = '-'; base32(&h, &bitpos, &xrefdata->uid[6], 5); + + xrefdata_uid_add(&xrefdata_uid, xrefdata); } void xref_gcc_workaround(const struct xref *xref) diff --git a/lib/xref.h b/lib/xref.h index 6cff1a3769..0e3f00f690 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -22,6 +22,7 @@ #include <limits.h> #include <errno.h> #include "compiler.h" +#include "typesafe.h" #ifdef __cplusplus extern "C" { @@ -63,6 +64,8 @@ struct xref { /* type-specific bits appended by embedding this struct */ }; +PREDECL_RBTREE_UNIQ(xrefdata_uid); + struct xrefdata { /* pointer back to the const part; this will be initialized at * program startup by xref_block_add(). (Creating structs with @@ -88,8 +91,18 @@ struct xrefdata { uint32_t hashu32[2]; /* -- 32 bytes (on 64bit) -- */ + struct xrefdata_uid_item xui; }; +static inline int xrefdata_uid_cmp(const struct xrefdata *a, + const struct xrefdata *b) +{ + return strcmp(a->uid, b->uid); +} + +DECLARE_RBTREE_UNIQ(xrefdata_uid, struct xrefdata, xui, xrefdata_uid_cmp); +extern struct xrefdata_uid_head xrefdata_uid; + /* linker "magic" is used to create an array of pointers to struct xref. * the result is a contiguous block of pointers, each pointing to an xref * somewhere in the code. The linker gives us start and end pointers, we diff --git a/lib/zlog.c b/lib/zlog.c index 6fd52cae62..1b0751559d 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -47,12 +47,19 @@ #include <mach/mach_traps.h> #endif +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <dlfcn.h> +#endif + #include "memory.h" #include "atomlist.h" #include "printfrr.h" #include "frrcu.h" #include "zlog.h" #include "libfrr_trace.h" +#include "thread.h" DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message"); DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer"); @@ -508,6 +515,87 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref, XFREE(MTYPE_LOG_MESSAGE, msg->text); } +static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio) +{ + struct thread *tc = pthread_getspecific(thread_current); + const char *uid = xref->xref.xrefdata->uid; + bool found_thread = false; + + zlog(prio, "| (%s) message in thread %jd, at %s(), %s:%d", uid, + zlog_gettid(), xref->xref.func, xref->xref.file, xref->xref.line); + +#ifdef HAVE_LIBUNWIND + const char *threadfunc = tc ? tc->xref->funcname : NULL; + bool found_caller = false; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, off, sp; + Dl_info dlinfo; + + unw_getcontext(&uc); + + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + char buf[96], name[128] = "?"; + bool is_thread = false; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (unw_is_signal_frame(&cursor)) + zlog(prio, "| (%s) ---- signal ----", uid); + + if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) { + if (!strcmp(buf, xref->xref.func)) + found_caller = true; + if (threadfunc && !strcmp(buf, threadfunc)) + found_thread = is_thread = true; + + snprintf(name, sizeof(name), "%s+%#lx", buf, (long)off); + } + + if (!found_caller) + continue; + + if (dladdr((void *)ip, &dlinfo)) + zlog(prio, "| (%s) %-36s %16lx+%08lx %16lx %s", uid, + name, (long)dlinfo.dli_fbase, + (long)ip - (long)dlinfo.dli_fbase, (long)sp, + dlinfo.dli_fname); + else + zlog(prio, "| (%s) %-36s %16lx %16lx", uid, name, + (long)ip, (long)sp); + + if (is_thread) + zlog(prio, "| (%s) ^- scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); + } +#elif defined(HAVE_GLIBC_BACKTRACE) + void *frames[64]; + char **names = NULL; + int n_frames, i; + + n_frames = backtrace(frames, array_size(frames)); + if (n_frames < 0) + n_frames = 0; + if (n_frames) + names = backtrace_symbols(frames, n_frames); + + for (i = 0; i < n_frames; i++) { + void *retaddr = frames[i]; + char *loc = names[i]; + + zlog(prio, "| (%s) %16lx %-36s", uid, (long)retaddr, loc); + } + free(names); +#endif + if (!found_thread && tc) + zlog(prio, "| (%s) scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); +} + void vzlogx(const struct xref_logmsg *xref, int prio, const char *fmt, va_list ap) { @@ -545,6 +633,15 @@ void vzlogx(const struct xref_logmsg *xref, int prio, vzlog_tls(zlog_tls, xref, prio, fmt, ap); else vzlog_notls(xref, prio, fmt, ap); + + if (xref) { + struct xrefdata_logmsg *xrdl; + + xrdl = container_of(xref->xref.xrefdata, struct xrefdata_logmsg, + xrefdata); + if (xrdl->fl_print_bt) + zlog_backtrace_msg(xref, prio); + } } void zlog_sigsafe(const char *text, size_t len) diff --git a/lib/zlog.h b/lib/zlog.h index d9c8952ac5..6e84fe8923 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -54,10 +54,14 @@ struct xref_logmsg { const char *args; }; +/* whether flag was added in config mode or enable mode */ +#define LOGMSG_FLAG_EPHEMERAL (1 << 0) +#define LOGMSG_FLAG_PERSISTENT (1 << 1) + struct xrefdata_logmsg { struct xrefdata xrefdata; - /* nothing more here right now */ + uint8_t fl_print_bt; }; /* These functions are set up to write to stdout/stderr without explicit @@ -94,15 +98,19 @@ static inline void zlog_ref(const struct xref_logmsg *xref, #define _zlog_ecref(ec_, prio, msg, ...) \ do { \ - static struct xrefdata _xrefdata = { \ - .xref = NULL, \ - .uid = {}, \ - .hashstr = (msg), \ - .hashu32 = {(prio), (ec_)}, \ + static struct xrefdata_logmsg _xrefdata = { \ + .xrefdata = \ + { \ + .xref = NULL, \ + .uid = {}, \ + .hashstr = (msg), \ + .hashu32 = {(prio), (ec_)}, \ + }, \ }; \ static const struct xref_logmsg _xref __attribute__( \ (used)) = { \ - .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \ + .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \ + __func__), \ .fmtstring = (msg), \ .priority = (prio), \ .ec = (ec_), \ diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 6caee259b6..f35971ba8c 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -879,12 +879,12 @@ void ospf6_plist_update(struct prefix_list *plist) DEFUN (area_import_list, area_import_list_cmd, - "area <A.B.C.D|(0-4294967295)> import-list NAME", + "area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST6_NAME", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" "Set the filter for networks from other areas announced to the specified one\n" - "Name of the acess-list\n") + "Name of the access-list\n") { int idx_ipv4 = 1; int idx_name = 3; @@ -911,7 +911,7 @@ DEFUN (area_import_list, DEFUN (no_area_import_list, no_area_import_list_cmd, - "no area <A.B.C.D|(0-4294967295)> import-list NAME", + "no area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST6_NAME", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" @@ -940,12 +940,12 @@ DEFUN (no_area_import_list, DEFUN (area_export_list, area_export_list_cmd, - "area <A.B.C.D|(0-4294967295)> export-list NAME", + "area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST6_NAME", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" "Set the filter for networks announced to other areas\n" - "Name of the acess-list\n") + "Name of the access-list\n") { int idx_ipv4 = 1; int idx_name = 3; @@ -974,7 +974,7 @@ DEFUN (area_export_list, DEFUN (no_area_export_list, no_area_export_list_cmd, - "no area <A.B.C.D|(0-4294967295)> export-list NAME", + "no area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST6_NAME", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 6406e8efee..28798d8717 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -93,7 +93,7 @@ struct tlv_header { #define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t))) -#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) +#define TLV_SIZE(tlvh) (uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) #define TLV_HDR_TOP(lsah) \ (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE) diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index 78f842db6c..4dc2d8af83 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -157,8 +157,18 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + + /* Check TLV len against overall LSA */ + if (sum + TLV_SIZE(tlvh) > length) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s: Malformed packet: Invalid TLV len:%d", + __func__, TLV_SIZE(tlvh)); + return OSPF6_FAILURE; + } + switch (ntohs(tlvh->type)) { case GRACE_PERIOD_TYPE: gracePeriod = (struct grace_tlv_graceperiod *)tlvh; @@ -1235,8 +1245,20 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, zlog_debug(" TLV info:"); } - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + + /* Check TLV len */ + if (sum + TLV_SIZE(tlvh) > length) { + if (vty) + vty_out(vty, "%% Invalid TLV length: %d\n", + TLV_SIZE(tlvh)); + else if (IS_DEBUG_OSPF6_GR) + zlog_debug("%% Invalid TLV length: %d", + TLV_SIZE(tlvh)); + return OSPF6_FAILURE; + } + switch (ntohs(tlvh->type)) { case GRACE_PERIOD_TYPE: gracePeriod = (struct grace_tlv_graceperiod *)tlvh; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index bbb458d8ef..e7f18ae79c 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1775,7 +1775,7 @@ DEFUN (no_ospf_area_default_cost, DEFUN (ospf_area_export_list, ospf_area_export_list_cmd, - "area <A.B.C.D|(0-4294967295)> export-list NAME", + "area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST4_NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1799,7 +1799,7 @@ DEFUN (ospf_area_export_list, DEFUN (no_ospf_area_export_list, no_ospf_area_export_list_cmd, - "no area <A.B.C.D|(0-4294967295)> export-list NAME", + "no area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST4_NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -1827,7 +1827,7 @@ DEFUN (no_ospf_area_export_list, DEFUN (ospf_area_import_list, ospf_area_import_list_cmd, - "area <A.B.C.D|(0-4294967295)> import-list NAME", + "area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST4_NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1851,7 +1851,7 @@ DEFUN (ospf_area_import_list, DEFUN (no_ospf_area_import_list, no_ospf_area_import_list_cmd, - "no area <A.B.C.D|(0-4294967295)> import-list NAME", + "no area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST4_NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -9347,7 +9347,7 @@ DEFUN (no_ospf_redistribute_instance_source, DEFUN (ospf_distribute_list_out, ospf_distribute_list_out_cmd, - "distribute-list WORD out " FRR_REDIST_STR_OSPFD, + "distribute-list ACCESSLIST4_NAME out " FRR_REDIST_STR_OSPFD, "Filter networks in routing updates\n" "Access-list name\n" OUT_STR @@ -9369,7 +9369,7 @@ DEFUN (ospf_distribute_list_out, DEFUN (no_ospf_distribute_list_out, no_ospf_distribute_list_out_cmd, - "no distribute-list WORD out " FRR_REDIST_STR_OSPFD, + "no distribute-list ACCESSLIST4_NAME out " FRR_REDIST_STR_OSPFD, NO_STR "Filter networks in routing updates\n" "Access-list name\n" @@ -9863,161 +9863,10 @@ DEFUN (no_ospf_proactive_arp, return CMD_SUCCESS; } -/* Graceful Restart HELPER Commands */ -DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd, - "graceful-restart helper enable [A.B.C.D$address]", - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Enable Helper support\n" - "Advertising Router-ID\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - if (address_str) { - ospf_gr_helper_support_set_per_routerid(ospf, &address, - OSPF_GR_TRUE); - return CMD_SUCCESS; - } - - ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE); - - return CMD_SUCCESS; -} - -DEFPY(no_ospf_gr_helper_enable, - no_ospf_gr_helper_enable_cmd, - "no graceful-restart helper enable [A.B.C.D$address]", - NO_STR - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Enable Helper support\n" - "Advertising Router-ID\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - if (address_str) { - ospf_gr_helper_support_set_per_routerid(ospf, &address, - OSPF_GR_FALSE); - return CMD_SUCCESS; - } - - ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE); - return CMD_SUCCESS; -} - -#if CONFDATE > 20220921 -CPP_NOTICE( - "Time to remove the deprecated \"[no] graceful-restart helper-only\" commands") +#if CONFDATE > 20211209 +CPP_NOTICE("Time to remove broken OSPF GR helper") #endif -DEFPY_HIDDEN(ospf_gr_helper_only, ospf_gr_helper_only_cmd, - "graceful-restart helper-only [A.B.C.D]", - "OSPF Graceful Restart\n" - "Enable Helper support\n" - "Advertising router id\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - struct in_addr addr; - int ret; - - vty_out(vty, - "%% This command is deprecated. Please, use `graceful-restart helper enable` instead.\n"); - - if (argc == 3) { - ret = inet_aton(argv[2]->arg, &addr); - if (!ret) { - vty_out(vty, - "Please specify the valid routerid address.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE); - return CMD_SUCCESS; - } - - ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE); - - return CMD_SUCCESS; -} - -ALIAS_HIDDEN(no_ospf_gr_helper_enable, - no_ospf_gr_helper_only_cmd, - "no graceful-restart helper-only [A.B.C.D]", - NO_STR - "OSPF Graceful Restart\n" - "Disable Helper support\n" - "Advertising router id\n") - -DEFPY(ospf_gr_helper_enable_lsacheck, - ospf_gr_helper_enable_lsacheck_cmd, - "graceful-restart helper strict-lsa-checking", - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Enable strict LSA check\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_TRUE); - return CMD_SUCCESS; -} - -DEFPY(no_ospf_gr_helper_enable_lsacheck, - no_ospf_gr_helper_enable_lsacheck_cmd, - "no graceful-restart helper strict-lsa-checking", - NO_STR - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Disable strict LSA check\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_FALSE); - return CMD_SUCCESS; -} - -DEFPY(ospf_gr_helper_supported_grace_time, - ospf_gr_helper_supported_grace_time_cmd, - "graceful-restart helper supported-grace-time (10-1800)$interval", - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Supported grace timer\n" - "Grace interval(in seconds)\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_supported_gracetime_set(ospf, interval); - return CMD_SUCCESS; -} - -DEFPY(no_ospf_gr_helper_supported_grace_time, - no_ospf_gr_helper_supported_grace_time_cmd, - "no graceful-restart helper supported-grace-time (10-1800)$interval", - NO_STR - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Supported grace timer\n" - "Grace interval(in seconds)\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_supported_gracetime_set(ospf, OSPF_MAX_GRACE_INTERVAL); - return CMD_SUCCESS; -} - -DEFPY(ospf_gr_helper_planned_only, - ospf_gr_helper_planned_only_cmd, - "graceful-restart helper planned-only", - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Supported only planned restart\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_TRUE); - - return CMD_SUCCESS; -} - /* External Route Aggregation */ DEFUN (ospf_external_route_aggregation, ospf_external_route_aggregation_cmd, @@ -10100,256 +9949,6 @@ DEFUN (no_ospf_external_route_aggregation, return CMD_SUCCESS; } -DEFPY(no_ospf_gr_helper_planned_only, - no_ospf_gr_helper_planned_only_cmd, - "no graceful-restart helper planned-only", - NO_STR - "OSPF Graceful Restart\n" - "OSPF GR Helper\n" - "Supported only for planned restart\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - - ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_FALSE); - - return CMD_SUCCESS; -} - -static int ospf_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket, - void *arg) -{ - struct advRtr *rtr = bucket->data; - struct vty *vty = (struct vty *)arg; - static unsigned int count; - - vty_out(vty, "%-6pI4,", &rtr->advRtrAddr); - count++; - - if (count % 5 == 0) - vty_out(vty, "\n"); - - return HASHWALK_CONTINUE; -} - -static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf, - uint8_t use_vrf, json_object *json, - bool uj, bool detail) -{ - struct listnode *node; - struct ospf_interface *oi; - char buf[PREFIX_STRLEN]; - json_object *json_vrf = NULL; - - if (uj) { - if (use_vrf) - json_vrf = json_object_new_object(); - else - json_vrf = json; - } - - if (ospf->instance) { - if (uj) - json_object_int_add(json, "ospfInstance", - ospf->instance); - else - vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); - } - - ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); - - if (uj) { - if (use_vrf) - json_object_object_add(json, ospf_get_name(ospf), - json_vrf); - } else - vty_out(vty, "\n"); - - /* Show Router ID. */ - if (uj) { - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); - } else { - vty_out(vty, "\n OSPF Router with ID (%pI4)\n\n", - &ospf->router_id); - } - - if (!uj) { - - if (ospf->is_helper_supported) - vty_out(vty, - " Graceful restart helper support enabled.\n"); - else - vty_out(vty, - " Graceful restart helper support disabled.\n"); - - if (ospf->strict_lsa_check) - vty_out(vty, " Strict LSA check is enabled.\n"); - else - vty_out(vty, " Strict LSA check is disabled.\n"); - - if (ospf->only_planned_restart) - vty_out(vty, - " Helper supported for planned restarts only.\n"); - else - vty_out(vty, - " Helper supported for Planned and Unplanned Restarts.\n"); - - vty_out(vty, - " Supported Graceful restart interval: %d(in seconds).\n", - ospf->supported_grace_time); - - if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) { - vty_out(vty, " Enable Router list:\n"); - vty_out(vty, " "); - hash_walk(ospf->enable_rtr_list, - ospf_print_vty_helper_dis_rtr_walkcb, vty); - vty_out(vty, "\n\n"); - } - - if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) { - vty_out(vty, " Last Helper exit Reason :%s\n", - ospf_exit_reason2str(ospf->last_exit_reason)); - } - - if (ospf->active_restarter_cnt) - vty_out(vty, - " Number of Active neighbours in graceful restart: %d\n", - ospf->active_restarter_cnt); - else - vty_out(vty, "\n"); - - } else { - json_object_string_add( - json_vrf, "helperSupport", - (ospf->is_helper_supported) ? "Enabled" : "Disabled"); - json_object_string_add(json_vrf, "strictLsaCheck", - (ospf->strict_lsa_check) ? "Enabled" - : "Disabled"); - json_object_string_add( - json_vrf, "restartSupoort", - (ospf->only_planned_restart) - ? "Planned Restart only" - : "Planned and Unplanned Restarts"); - - json_object_int_add(json_vrf, "supportedGracePeriod", - ospf->supported_grace_time); - - if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) - json_object_string_add( - json_vrf, "LastExitReason", - ospf_exit_reason2str(ospf->last_exit_reason)); - - if (ospf->active_restarter_cnt) - json_object_int_add(json_vrf, "activeRestarterCnt", - ospf->active_restarter_cnt); - } - - - if (detail) { - int cnt = 1; - json_object *json_neighbors = NULL; - - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { - struct route_node *rn; - struct ospf_neighbor *nbr; - json_object *json_neigh; - - if (ospf_interface_neighbor_count(oi) == 0) - continue; - - if (uj) { - json_object_object_get_ex(json_vrf, "Neighbors", - &json_neighbors); - if (!json_neighbors) { - json_neighbors = - json_object_new_object(); - json_object_object_add(json_vrf, - "Neighbors", - json_neighbors); - } - } - - for (rn = route_top(oi->nbrs); rn; - rn = route_next(rn)) { - - if (!rn->info) - continue; - - nbr = rn->info; - - if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) - continue; - - if (!uj) { - vty_out(vty, " Neighbour %d :\n", cnt); - vty_out(vty, " Address : %pI4\n", - &nbr->address.u.prefix4); - vty_out(vty, " Routerid : %pI4\n", - &nbr->router_id); - vty_out(vty, - " Received Grace period : %d(in seconds).\n", - nbr->gr_helper_info - .recvd_grace_period); - vty_out(vty, - " Actual Grace period : %d(in seconds)\n", - nbr->gr_helper_info - .actual_grace_period); - vty_out(vty, - " Remaining GraceTime:%ld(in seconds).\n", - thread_timer_remain_second( - nbr->gr_helper_info - .t_grace_timer)); - vty_out(vty, - " Graceful Restart reason: %s.\n\n", - ospf_restart_reason2str( - nbr->gr_helper_info - .gr_restart_reason)); - cnt++; - } else { - json_neigh = json_object_new_object(); - json_object_string_add( - json_neigh, "srcAddr", - inet_ntop(AF_INET, &nbr->src, - buf, sizeof(buf))); - - json_object_string_add( - json_neigh, "routerid", - inet_ntop(AF_INET, - &nbr->router_id, - buf, sizeof(buf))); - json_object_int_add( - json_neigh, - "recvdGraceInterval", - nbr->gr_helper_info - .recvd_grace_period); - json_object_int_add( - json_neigh, - "actualGraceInterval", - nbr->gr_helper_info - .actual_grace_period); - json_object_int_add( - json_neigh, "remainGracetime", - thread_timer_remain_second( - nbr->gr_helper_info - .t_grace_timer)); - json_object_string_add( - json_neigh, "restartReason", - ospf_restart_reason2str( - nbr->gr_helper_info - .gr_restart_reason)); - json_object_object_add( - json_neighbors, - inet_ntop(AF_INET, &nbr->src, - buf, sizeof(buf)), - json_neigh); - } - } - } - } - return CMD_SUCCESS; -} - DEFUN (ospf_external_route_aggregation_no_adrvertise, ospf_external_route_aggregation_no_adrvertise_cmd, "summary-address A.B.C.D/M no-advertise", @@ -10438,108 +10037,6 @@ DEFUN (ospf_route_aggregation_timer, return CMD_SUCCESS; } -DEFPY (show_ip_ospf_gr_helper, - show_ip_ospf_gr_helper_cmd, - "show ip ospf [vrf <NAME|all>] graceful-restart helper [detail] [json]", - SHOW_STR - IP_STR - "OSPF information\n" - VRF_CMD_HELP_STR - "All VRFs\n" - "OSPF Graceful Restart\n" - "Helper details in the router\n" - "Detailed informtion\n" - JSON_STR) -{ - char *vrf_name = NULL; - bool all_vrf = false; - int ret = CMD_SUCCESS; - int idx_vrf = 0; - int idx = 0; - uint8_t use_vrf = 0; - bool uj = use_json(argc, argv); - struct ospf *ospf = NULL; - json_object *json = NULL; - struct listnode *node = NULL; - int inst = 0; - bool detail = false; - - OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - - if (argv_find(argv, argc, "detail", &idx)) - detail = true; - - if (uj) - json = json_object_new_object(); - - /* vrf input is provided */ - if (vrf_name) { - use_vrf = 1; - - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { - if (!ospf->oi_running) - continue; - - ret = ospf_show_gr_helper_details( - vty, ospf, use_vrf, json, uj, detail); - } - - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - - return ret; - } - - ospf = ospf_lookup_by_inst_name(inst, vrf_name); - - if (ospf == NULL || !ospf->oi_running) { - - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else - vty_out(vty, "%% OSPF instance not found\n"); - - return CMD_SUCCESS; - } - - } else { - /* Default Vrf */ - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - - if (ospf == NULL || !ospf->oi_running) { - - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else - vty_out(vty, "%% OSPF instance not found\n"); - - return CMD_SUCCESS; - } - - ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj, - detail); - } - - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - - return CMD_SUCCESS; -} -/* Graceful Restart HELPER commands end */ DEFUN (no_ospf_route_aggregation_timer, no_ospf_route_aggregation_timer_cmd, "no aggregation timer", @@ -12608,9 +12105,6 @@ void ospf_vty_show_init(void) /* "show ip ospf vrfs" commands. */ install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd); - /* "show ip ospf gr-helper details" command */ - install_element(VIEW_NODE, &show_ip_ospf_gr_helper_cmd); - /* "show ip ospf summary-address" command */ install_element(VIEW_NODE, &show_ip_ospf_external_aggregator_cmd); } @@ -12721,18 +12215,6 @@ static void ospf_vty_zebra_init(void) install_element(OSPF_NODE, &no_ospf_distance_ospf_cmd); install_element(OSPF_NODE, &ospf_distance_ospf_cmd); - /*Ospf garcefull restart helper configurations */ - install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd); - install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd); - install_element(OSPF_NODE, &ospf_gr_helper_only_cmd); - install_element(OSPF_NODE, &no_ospf_gr_helper_only_cmd); - install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd); - install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd); - install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd); - install_element(OSPF_NODE, &no_ospf_gr_helper_supported_grace_time_cmd); - install_element(OSPF_NODE, &ospf_gr_helper_planned_only_cmd); - install_element(OSPF_NODE, &no_ospf_gr_helper_planned_only_cmd); - /* External LSA summarisation config commands.*/ install_element(OSPF_NODE, &ospf_external_route_aggregation_cmd); install_element(OSPF_NODE, &no_ospf_external_route_aggregation_cmd); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 4cd94e0df9..e5ee7a82ad 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2446,8 +2446,6 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state, case PIM_REG_PRUNE: strlcpy(state_str, "RegP", state_str_len); break; - default: - strlcpy(state_str, "Unk", state_str_len); } return state_str; } diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index ddba33ff9d..fa7f1da79a 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1304,7 +1304,6 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, struct pim_msdp_mg *mg; struct listnode *mbrnode; struct pim_msdp_mg_mbr *mbr; - char mbr_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; int count = 0; @@ -1321,10 +1320,8 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, - sizeof(mbr_str)); - vty_out(vty, "%sip msdp mesh-group %s member %s\n", - spaces, mg->mesh_group_name, mbr_str); + vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", + spaces, mg->mesh_group_name, &mbr->mbr_ip); ++count; } } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index d21c7b4008..d0d120523d 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1720,8 +1720,6 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str, case PIM_REG_PRUNE: strlcpy(state_str, "RegPrune", state_str_len); break; - default: - strlcpy(state_str, "RegUnknown", state_str_len); } return state_str; } @@ -1785,7 +1783,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) } pim_null_register_send(up); break; - default: + case PIM_REG_NOINFO: break; } diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index a7286d1878..229104baff 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -199,6 +199,8 @@ Requires: initscripts BuildRequires: pam-devel %endif %if "%{initsystem}" == "systemd" +BuildRequires: systemd +BuildRequires: systemd-devel Requires(post): systemd Requires(preun): systemd Requires(postun): systemd @@ -394,6 +396,9 @@ routing state through standard SNMP MIBs. --disable-bgp-vnc \ %endif --enable-isisd \ +%if "%{initsystem}" == "systemd" + --enable-systemd \ +%endif --enable-rpki \ %if %{with_bfdd} --enable-bfdd \ @@ -768,9 +773,428 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog -* Fri Oct 30 2020 Martin Winter <mwinter@opensourcerouting.org> - %{version} -- Moved RPKI to subpackage -- Added SNMP subpackage +* Tue Nov 4 2021 Martin Winter <mwinter@opensourcerouting.org> - %{version} + +* Tue Nov 2 2021 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.1 +- FRR 8.1 brings a long list of enhancements and fixes with 1200 commits from +- 75 developers. Thanks to all contributers. +- New Features: +- Lua hooks are now feature complete, with one hook available for use (http://docs.frrouting.org/en/latest/scripting.html) +- Improvements to SRv6 (Segment Routing over IPv6) (http://docs.frrouting.org/en/latest/zebra.html#segment-routing-ipv6) +- Improvements to Prefix-SID (Type 5) +- EVPN route type-5 gateway IP overlay Index (http://docs.frrouting.org/en/latest/bgp.html#evpn-overlay-index-gateway-ip) +- OSPFv3 NSSA and NSSA totally stub areas (http://docs.frrouting.org/en/latest/ospf6d.html#ospf6-area) +- OSPFv3 ASBR summarization (http://docs.frrouting.org/en/latest/ospf6d.html#asbr-summarisation-support-in-ospfv3) +- OSPFv3 Graceful Restart (http://docs.frrouting.org/en/latest/ospf6d.html#graceful-restart) +- OSPFv2 Graceful Restart (restarting mode added, helper was already implemented) (http://docs.frrouting.org/en/latest/ospfd.html#graceful-restart) +- Behavior Changes +- Every node in running config now has an explicit "exit" tag +- Link bandwidth in BGP is now correctly encoded according to IEEE 754. To stay with old incorrect encoding use: +- `neighbor PEER disable-link-bw-encoding-ieee` +- Changelog +- alpine: + Fix path for daemons file install +- BGP: +- Add "json" option to "show bgp as-path-access-list" +- Add `disable-addpath-rx` knob +- Add an ability to set extcommunity to none in route-maps +- Add counter of displayed show bgp summary when filtering +- Add knob to config cond-adv scanner period +- Add route-map `match alias` command +- Add rpki source address configuration +- Add show bgp summary filter by neighbor or as +- Add terse display option on show bgp summary +- Allow for auto-completion of community alias's created +- Bgp knob to teardown session immediately when peer is unreachable +- Expand 'bgp default <afi>-<safi>' cmds +- Extend evpn next hop tracking to type-1 and type-4 routes +- Fix "no router bgp x vrf default" +- Flowspec redirect vrf uses vrf table instead of allocated table id +- Handle quick flaps of an evpn prefix properly +- Initial batch of evpn lttng tracepoints +- Limit processing to what is needed in rpki validation +- Modify vrf/view display in show bgp summary +- Set 4096 instead of 65535 as new max packet size for a new peer +- Set extended msg size only if we advertised and received capability +- Show bgp community alias in json community list output +- Show bgp prefixes by community alias +- Show max packet size per update-group +- Split soft reconfigure table task into several jobs to not block vtysh +- Store distance received from a redistribute statement +- Update route-type-1 legend to match output +- ISIS: +- Fix sending of lsp with null seqno +- lib: +- Add "json" option to "show ip[v6] access-list" +- Add "json" option to "show ip[v6] prefix-list" +- Add "json" option to "show route-map" +- Prevent grpc assert on missing yang node +- NHRP: +- Clear cache when shortcuts are cleared +- Fix corrupt address being shown for shortcuts with no cache entry +- Set prefix correctly in resolution request +- OSPF6: +- Add debug commands for lsa all and route all +- Add warning log for late hello packets +- Add write-multiplier configuration +- Don't update router-id if at least one adjacency is full +- Extend the "redistribute" command with more options +- Fix issue when displaying the redistribute command +- Fix logging of border router routes +- Json output for database dump show command +- Link state id in lsa database json output +- Send lsa update immediately when ospf instance is deleted +- OSPF: +- Fix crash when creating vlink in unknown vrf +- Gr conformance fix for hello packet dr election +- Print extra lsa information in some log messages +- Rfc conformance test case 25.23 issue fix +- Show ip ospf route json does not shown metric and tag +- Summary lsa is not originated when process is reset +- pathd: +- Handle pcinitiated configuration, main thread +- Handle pcinitiated messages, thread controller +- Handle srp_id correctly +- If pce ret no-path to pcreq don't retry pcreq nor delegate +- PBR: +- Add `match ip-protocol [tcp|udp]` +- Add ability to set/unset src and dest ports +- Nhg "add" edge case for last in table range +- Start inclusion of src and dst ports for pbrd +- PIM: +- Add tos/ttl check for igmp conformance +- Allow join prune intervals to be as small as 5 seconds +- Allow msdp group name 'default' +- Fix register suppress timer code +- Fix uaf/heap corruption in bsm code +- Fix command "no ip msdp mesh-group member" +- Igmp groups are not getting timeout +- Igmp memberships are not querier specific +- Igmp sockets need to be iface-bound too +- Prevent uninited usage of nexthop +- Support msdp global timers configuration +- vtysh +- Add cli timestamp '-t' flag +- Add error code if daemon is not running +- Fix searching commands in parent nodes +- yang: +- Add msdp timer configuration +- Fix bgp multicast prefix type +- Mark a couple of prefix-list/access-list leafs as mandatory +- Move multicast prefix type definition +- Replace an empty pattern with a zero-length restriction +- Rework pim msdp mesh group +- Simplify msdp peer handling +- zebra : +- Add "json" option to "show interface" +- Various improvment to dataplane interface +- Add message counts for `show zebra client` +- Add nhg id to show ip route json +- Add show command for ra interface lists +- Fix ipv4 routes with ipv6 link local next hops install in fpm +- Handle bridge mac address update in evpn contexts +- Move individual lines to table in `show zebra client` command +- Refresh vxlan evpn contexts, when bridge interface goes up +- Update zl3vni when bridge link refreshed in other namespaces + +* Wed Jul 21 2021 Martin Winter <mwinter@opensourcerouting.org> - 8.0 +- Major changes +- New daemon pathd for segment routing +- EVPN Multihoming is now fully supported +- OSPFv3 now supports VRFs +- TI-LFA has been implemented in IS-IS and OSPF +- Ability for Zebra to dump netlink messages in a human-friendly format +- LDP gained SNMP support +- libyang minimun version is now 2.0 +- BABEL: +- Add `distribute-list` commands +- Fix memory leak in connected route handling +- BGP: +- Add support for use of aliases with communities +- Add support of tcp-mss for neighbors +- Add support for EVPN Multihoming +- Add ability to show BGP routes from a particular table version +- Add support for for RFC 8050 (MRT add-path) +- Add SNMP support for MPLS VPN +- Add `show bgp summary wide` command to show more detailed output + on wide terminals +- Add ability for peer-groups to have `ttl-security hops` configured +- Add support for conditional Advertisement +- Add support for RFC 4271 Delay Open Timer +- Add a knob to not advertise until route is installed in fib +- Add BGP-wide configuration for graceful shutdown +- Add support for RFC 8654 extended messages +- Improve RPKI reporting as well as new show commands +- Improve handling of VRF route leaking +- Improve scaling behavior for dynamic neighbors +- Improve LL nexthop tracking to be interface based +- Improve route reachability handling with respect to blackhole routes +- Improve SNMP traps to RFC 4273 notifications +- Improve EVPN routes to use L3 NHG's where applicable +- Improvements to EVPN +- Improvements to update behavior +- Fix various issues with connection resolution +- Fix statistics commands in some situations +- Fix non-determistic locally-originated paths in bestpath selection +- Continue working on transitioning to YANG/Northbound configuration +- Various bug fixes and performance improvements +- EIGRP: +- Add `distribute-list` commands +- Ensure received AS number is the same as ours in all situations +- Properly validate TLV lengths in some situations +- IS-IS: +- Add ldb-sync functionality +- Add TI-LFA functionality +- Add support for Anycast-SID's +- Add support for classic LFA RFC 5286 +- Add `show isis fast-reroute summary` command +- Add support for Remote LFA RFC 7490 +- Fix Attach-bit processing in some scenarios +- Cleanup BFD integration +- Various bug fixes and performance improvements +- LDP: +- Add SNMP support +- Support for LDP IGP Synchronization +- Support for RLFA clients +- Various bug fixes and performance improvements +- LIBFRR: +- Various bugfixes and performance improvements +- NHRP: +- Add `nhrp multicast-nflog-group (1-65535)` command +- Add configuration options for vici socket path +- Add support for forwarding multicast packets +- Fix handling of MTU +- Fix handling of NAT extension +- Retry IPsec under some conditions +- OSPFv2: +- Add OSPF GR helper support +- Add JSON support for various commands +- Add `summary-address A.B.C.D/M ...` commands +- Add `area X nssa suppress-fa` command +- Add support for TI-LFA +- Add support for BFD profiles +- Add support for Traffic Engineering database +- Add support for usage of DMPVPN with OSPF +- Add `clear ip ospf neighbor` commands +- Add YANG support for route-maps +- Improvements to SNMP +- Fixes for type 5 and type 7 LSA handling +- Various bug fixes and performance improvements +- OSPFv3: +- Add support for VRFs +- Add JSON support to a bunch of commands +- Add ability to control maximum paths for routes +- Add `show ipv6 ospf6 vrfs` command +- Add support for BFD profiles +- Fix to not send hellos on loopbacks +- Cleanup area handling around interfaces +- YANG support for route-maps +- Various bug fixes and performance improvements +- OSPFCLIENT: +- Cleanup trust of user input +- PATHd: +- Add support of SR-TE policy management daemon +- Add optional support for PCEP to pathd +- Integrate PCEP-LIB into FRR +- PBR: +- Add `set installable` nhg command +- Improve interface up/down event handling +- PIM: +- Add YANG integration +- Add JSON support to various commands +- Add BFD profile support +- Fixes to IGMP conformance +- Fixes to behavior surrounding Prune and Prune-pending +- Various bug fixes and performance improvements +- RIPNG: +- Fix interface wakeup after shutdown +- SHARP: +- Add ability to use Nexthop Groups +- Add v4 redistribute watching +- Add TED support +- Various bug fixes +- STATIC: +- Fix nexthop handling in some situations +- Forbid blackhole and non-blackhole nexthops in a single route +- VRRP: +- printf formatting cleanups +- VTYSH: +- Add a `show history` command +- Add `show memory <daemon>` support +- Start deprecation cycle for `address-family evpn` +- Display version with --help +- Various bug fixes +- WATCHFRR: +- Fix some crashes +- ZEBRA: +- Add JSON support to various commands +- Add Human readable netlink dumps +- Add L2 NHG support +- Add support for LSPs to FPM dataplane +- Add ability for other protocol daemons to install nexthop groups into the kernel +- Add YANG support for route-maps +- Improve scale performance when handling a large number of VRF's +- Improve network namespace handling +- Improve asic-offload handling +- Improve FreeBSD interface and route handling +- Improve handling of neighbors in kernel dataplane plugin +- Improve label manager +- Improve route-map processing +- Improve debug-ability of routes and VRFs +- Improve FPM dataplane plugin +- Improve handling of reachability / nexthop tracking on shutdown interfaces +- Improve EVPN support +- Fix startup handling of `set src X` +- Various bug fixes and performance improvements + +* Wed Mar 3 2021 Martin Winter <mwinter@opensourcerouting.org> - 7.5.1 +- BABEL: +- Fix connected route leak on change +- BFD: +- Session lookup was sometimes wrong +- Memory leak and handling cleanups +- In some situations handle vrf appropriately when receiving packets +- BGP: +- Peer Group Inheritance Fixes +- Dissallow attempt to peer peers reachable via blackholes +- Send BMP down message when reachability fails +- Cleanup handling of aggregator data when the AGG AS is 0 +- Handle `neighbor <peer-group allowas-in` config changes properly +- Properly parse community and lcommunity values in some circumstances +- Allow peer-groups to configure `ttl-security hops` +- Prevent v6 routes with v4 nexthops from being installed +- Allow `default-originate` to be cleared from a peer group +- Fix evpn route-map vni filter at origin +- local routes were using non-default distance +- Properly track if the nexthop was updated in some circumstances +- Cleanup `show running` when running bgp with `-e X` values +- Various Memory leaks in show commands +- Properly withdraw exported routes when deleting a VRF +- Avoid resetting ebgp-multihop if peer setting is the same as peer-group +- Properly encode flowspec rules to zebra in some rare circumstances +- Generate statistics for routes in bgp when we have exactly 1 route +- Properly apply route-map for the default-originate command +- EIGRP: +- Properly set MTU for eigrp packets sent +- Various memory leaks and using uninited data fixes +- ISIS: +- When last area address is removed, resign if we were the DR +- Various memory leaks and using uninited data fixes +- LDP: +- Various memory leaks and using uninited data fixes +- NHRP: +- Use onlink routes when prefix == nh +- Shortcut routes are installed with proper nexthop +- OSPF: +- Prevent duplicate packet read in multiple vrf situation +- Fix area removal at interface level +- Restore Point to MultiPoint interface types +- Correctly handle MTU change on startup +- Multi Instance initialization sometimes was not successful +- NSSA translate-always was not working properly +- OSPFv3: +- Don't send hellos on loopback interfaces +- Handle ECMP better when a sub-path is removed +- Memory leak and handling fixes +- Fix Link LSA not updating when router priority is modified +- Some output from show commands was wrong +- Intra area remote connected prefixes sometimes not installed +- PBR: +- Various memory leaks and using uninited data fixes +- PIM: +- SGRpt prune received during prune didn't override holdtime +- Various memory leaks and using uninited data fixes +- STATIC: +- Fix VRF and usage on startup in some instances +- Tableid was being mishandled in some cases +- VTYSH: +- Disable bracketed paste in readline. +- WATCHFRR: +- Various memory leaks and using uninited data fixes +- ZEBRA: +- Always install blackhole routes using kernel routes instead of nexthops +- Various memory leaks and using uninited data fixes +- Dissallow resolution to duplicate nexthops that created infinite nexthops +- Apply the route-map delay-timer globally +- Some routes were stuck in Queued state when using the FPM +- Better handle vrf creation when using namespaces +- Set NUD_NOARP on sticky mac entries in addtion to NTF_STICKY +- Allow `set src X` to work on startup +- FRR Library: +- Fix a variety of memory leaks +- Fix VRF Creation in some instances +- RPKI context editing was not properly handled in reload situations +- routemap code was not properly handling modification of CLI in some instances +- SNAPCRAFT: +- Update to using rtrlib 0.7.0 +- Fix passthrough path for Libyang 1.x +- ALPINE: +- Remove old docker deps + +* Mon Nov 2 2020 Donald Sharp <sharpd@nvidia.com> - 7.5 +- BFD +- Profile support +- Minimum ttl support +- BGP +- rpki VRF support +- GR fixes +- Add wide option to display of routes +- Add `maximum-prefix <num> force` +- Add `bestpath-routes` to neighbor command +- Add `bgp shutdown message MSG...` command +- Add v6 Flowspec support +- Add `neighbor <neigh> shutdown rtt` command +- Allow update-delay to be applied globaly +- EVPN +- Beginning of MultiHoming Support +- ISIS +- Segment Routing Support +- VRF Support +- Guard against adj timer display overflow +- Add support for Anycast-SIDs +- Add support for Topology Independent LFA (TI-LFA) +- Add `lsp-gen-interval 2` to isis configuration +- OSPF +- Segment Routing support for ECMP +- Various LSA fixes +- Prevent crash if transferring config amongst instances +- PBR +- Adding json support to commands +- DSCP/ECN based PBR Matching +- PIM +- Add more json support to commands +- Fix missing mesh-group commands +- MSDP SA forwarding +- Clear (s,g,rpt) ifchannel on (*, G) prune received +- Fix igmp querier election and IP address mapping +- Crash fix when RP is removed +- STATIC +- Northbound Support +- YANG +- Filter and route-map Support +- OSPF model definition +- BGP model definition +- VTYSH +- Speed up output across daemons +- Fix build-time errors for some --enable flags +- Speed up output of configuration across daemons +- ZEBRA +- nexthop group support for FPM +- northbound support for rib model +- Backup nexthop support +- netlink batching support +- Allow upper level protocols to request ARP +- Add json output for zebra ES, ES-EVI and access vlan dumps +- +- Upgrade to using libyang1.0.184 +- +- RPM +- Moved RPKI to subpackage +- Added SNMP subpackage +- +- As always there are too many bugfixes to list individually. This release +- compromises just over 1k of commits by the community, with contributors from +- 70 people. * Tue Jun 30 2020 Martin Winter <mwinter@opensourcerouting.org> - 7.4 - BGPd diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 5590b1833d..58c28e54c0 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -327,7 +327,7 @@ void cli_show_rip_network_interface(struct vty *vty, */ DEFPY_YANG (rip_offset_list, rip_offset_list_cmd, - "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", + "[no] offset-list ACCESSLIST4_NAME$acl <in|out>$direction (0-16)$metric [IFNAME]", NO_STR "Modify RIP metric\n" "Access-list name\n" @@ -1026,7 +1026,7 @@ DEFPY_YANG (clear_ip_rip, DEFUN (rip_distribute_list, rip_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -1046,7 +1046,7 @@ DEFUN (rip_distribute_list, DEFUN (rip_no_distribute_list, rip_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index 63b75e723d..5bf3103a78 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -233,7 +233,7 @@ void cli_show_ripng_network_interface(struct vty *vty, */ DEFPY_YANG (ripng_offset_list, ripng_offset_list_cmd, - "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", + "[no] offset-list ACCESSLIST6_NAME$acl <in|out>$direction (0-16)$metric [IFNAME]", NO_STR "Modify RIPng metric\n" "Access-list name\n" @@ -511,7 +511,7 @@ DEFPY_YANG (clear_ipv6_rip, DEFUN (ripng_ipv6_distribute_list, ripng_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "IPv6\n" "Filter networks in routing updates\n" "Specify a prefix\n" @@ -532,7 +532,7 @@ DEFUN (ripng_ipv6_distribute_list, DEFUN (ripng_no_ipv6_distribute_list, ripng_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", NO_STR "IPv6\n" "Filter networks in routing updates\n" diff --git a/tests/.gitignore b/tests/.gitignore index 8cc2aa98f9..53dbd68c9a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -41,6 +41,7 @@ /lib/test_prefix2str /lib/test_printfrr /lib/test_privs +/lib/test_resolver /lib/test_ringbuf /lib/test_segv /lib/test_seqlock diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 8be81cc4cb..7c9febe2ca 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -60,6 +60,7 @@ static void vty_do_exit(int isexit) } const struct frr_yang_module_info *const *test_yang_modules = NULL; +int test_log_prio = ZLOG_DISABLED; /* main routine. */ int main(int argc, char **argv) @@ -73,7 +74,7 @@ int main(int argc, char **argv) /* master init. */ master = thread_master_create(NULL); - zlog_aux_init("NONE: ", ZLOG_DISABLED); + zlog_aux_init("NONE: ", test_log_prio); /* Library inits. */ cmd_init(1); diff --git a/tests/lib/cli/common_cli.h b/tests/lib/cli/common_cli.h index 3042ff5b12..6660b27ef7 100644 --- a/tests/lib/cli/common_cli.h +++ b/tests/lib/cli/common_cli.h @@ -37,6 +37,8 @@ extern void test_init(int argc, char **argv); */ extern struct thread_master *master; +extern int test_log_prio; + extern int dump_args(struct vty *vty, const char *descr, int argc, struct cmd_token *argv[]); diff --git a/tests/lib/test_resolver.c b/tests/lib/test_resolver.c new file mode 100644 index 0000000000..0b3dccc820 --- /dev/null +++ b/tests/lib/test_resolver.c @@ -0,0 +1,81 @@ +/* + * FRR c-ares integration test + * Copyright (C) 2021 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* this test is not run automatically since tests MUST NOT rely on any outside + * state. DNS is most definitely "outside state". A testbed may not have any + * internet connectivity at all. It may not have working DNS. Or worst of + * all, whatever name we use to test may have a temporary failure entirely + * beyond our control. + * + * The only way this test could be run in a testbed is with an all-local DNS + * setup, which considering the resolver code is rarely touched is not worth + * the time at all. Instead, after touching the resolver code, manually run + * this test and throw some names at it. + */ + +#include <zebra.h> + +#include "vty.h" +#include "command.h" +#include "resolver.h" +#include "log.h" +#include "sockunion.h" + +#include "tests/lib/cli/common_cli.h" + +extern struct thread_master *master; + +static void resolver_result(struct resolver_query *resq, const char *errstr, + int numaddrs, union sockunion *addr) +{ + int i; + + if (numaddrs <= 0) { + zlog_warn("hostname resolution failed: %s", errstr); + return; + } + + for (i = 0; i < numaddrs; i++) + zlog_info("resolver result: %pSU", &addr[i]); +} + +struct resolver_query query; + +DEFUN (test_resolve, + test_resolve_cmd, + "resolve WORD", + "DNS resolver\n" + "Name to resolve\n") +{ + resolver_resolve(&query, AF_UNSPEC, argv[1]->arg, resolver_result); + return CMD_SUCCESS; +} + +__attribute__((_CONSTRUCTOR(2000))) +static void test_setup(void) +{ + test_log_prio = LOG_DEBUG; +} + +void test_init(int argc, char **argv) +{ + resolver_init(master); + + install_element(VIEW_NODE, &test_resolve_cmd); +} diff --git a/tests/subdir.am b/tests/subdir.am index f21e12ecbb..cd6e4101dd 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -132,6 +132,12 @@ check_PROGRAMS += \ # end endif +if CARES +check_PROGRAMS += \ + tests/lib/test_resolver \ + # end +endif + tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c mkdir -p tests/lib/cli sed \ @@ -351,6 +357,10 @@ tests_lib_test_privs_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_privs_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_privs_LDADD = $(ALL_TESTS_LDADD) tests_lib_test_privs_SOURCES = tests/lib/test_privs.c +tests_lib_test_resolver_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_resolver_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_resolver_LDADD = $(ALL_TESTS_LDADD) lib/libfrrcares.la +tests_lib_test_resolver_SOURCES = tests/lib/test_resolver.c tests/lib/cli/common_cli.c tests_lib_test_ringbuf_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_ringbuf_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD) diff --git a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py index f35c20e16c..93a2339299 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -195,16 +195,16 @@ def test_bfd_ospf_interface_failure_rt2_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. - topotest.sleep(2, 'Wait for BFD down notification') + topotest.sleep(2, "Wait for BFD down notification") router_compare_json_output( "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 1, 0 + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 10, 2 ) # Check recovery, this can take some time @@ -234,15 +234,15 @@ def test_bfd_ospf_interface_failure_rt3_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. - topotest.sleep(2, 'Wait for BFD down notification') + topotest.sleep(2, "Wait for BFD down notification") router_compare_json_output( "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 1, 0 + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 10, 2 ) # Check recovery, this can take some time diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 34892d4a3a..044a6c0438 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -94,16 +94,16 @@ { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", + "next-hop": "r1", "parent": "r3(4)", "type": "TE-IS", - "vertex": "r3" + "vertex": "r1" }, { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", + "next-hop": "r1", + "parent": "r1(4)", "type": "IP TE", "vertex": "10.0.20.0/24" } @@ -121,10 +121,10 @@ { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", + "next-hop": "r1", "parent": "r3(4)", "type": "TE-IS", - "vertex": "r3" + "vertex": "r1" } ] } diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index a216e3588e..35a57d0a99 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -122,7 +122,7 @@ class BgpRib: luResult(target, True, title, logstr) def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): - logstr = "RequireVpnRoutes %s" % str(wantroutes) + logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": vrfstr = "vrf %s" % (vrf) diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py index 2c7c6df37e..b7a10d630a 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py @@ -100,6 +100,8 @@ TC8. Verify helper functionality when dut is helping RR and new grace lsa def setup_module(mod): + return pytest.skip("OSPF GR helper mode is currently broken") + """ Sets up the pytest environment diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index debf7ad766..4b69d82887 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -139,6 +139,8 @@ def build_topo(tgen): def setup_module(mod): + return pytest.skip("OSPF GR helper mode is currently broken") + "Sets up the pytest environment" tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9610f71d09..ab3e55d100 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -493,8 +493,8 @@ static int rtadv_timer(struct thread *thread) RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) FOR_ALL_INTERFACES (vrf, ifp) { - if (if_is_loopback_or_vrf(ifp) - || !if_is_operative(ifp)) + if (if_is_loopback_or_vrf(ifp) || !if_is_operative(ifp) + || (vrf_is_backend_netns() && ifp->vrf_id != zvrf->vrf->vrf_id)) continue; zif = ifp->info; diff --git a/zebra/table_manager.c b/zebra/table_manager.c index 9f3b44f944..82d6a0a6a2 100644 --- a/zebra/table_manager.c +++ b/zebra/table_manager.c @@ -82,7 +82,6 @@ void table_manager_enable(struct zebra_vrf *zvrf) zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager)); zvrf->tbl_mgr->lc_list = list_new(); zvrf->tbl_mgr->lc_list->del = delete_table_chunk; - hook_register(zserv_client_close, release_daemon_table_chunks); } /** diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index ec68f585e3..b1d2f1f0b3 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -613,7 +613,7 @@ static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt) int count = 0; RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - ifp = if_lookup_by_name_vrf(ifname, vrf); + ifp = if_lookup_by_name_vrf(port_str, vrf); if (ifp) { count++; if (!vrf_is_backend_netns()) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index d051ed67a0..66d6d4b4f2 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -705,6 +705,8 @@ void zebra_vrf_init(void) vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, zebra_vrf_delete, zebra_vrf_update); + hook_register(zserv_client_close, release_daemon_table_chunks); + vrf_cmd_init(vrf_config_write); if (vrf_is_backend_netns() && ns_have_netns()) { |
