diff options
| -rw-r--r-- | bgpd/bgp_addpath.c | 83 | ||||
| -rw-r--r-- | bgpd/bgp_mplsvpn.c | 11 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 5 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 77 | ||||
| -rw-r--r-- | bgpd/subdir.am | 2 | ||||
| -rwxr-xr-x | configure.ac | 2 | ||||
| -rw-r--r-- | doc/manpages/watchfrr.rst | 29 | ||||
| -rw-r--r-- | doc/user/setup.rst | 31 | ||||
| -rw-r--r-- | isisd/isis_cli.c | 23 | ||||
| -rw-r--r-- | lib/command.h | 3 | ||||
| -rw-r--r-- | pbrd/pbr_nht.c | 4 | ||||
| -rw-r--r-- | pbrd/pbr_vty.c | 2 | ||||
| -rw-r--r-- | pimd/pim_cmd.c | 53 | ||||
| -rw-r--r-- | tools/frrcommon.sh.in | 13 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 12 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 2 |
16 files changed, 262 insertions, 90 deletions
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index 55a86f99fc..c7fd1ba0e2 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -175,6 +175,28 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, } } +static void bgp_addpath_flush_type_rn(struct bgp *bgp, afi_t afi, safi_t safi, + enum bgp_addpath_strat addpath_type, + struct bgp_node *rn) +{ + struct bgp_path_info *pi; + + idalloc_drain_pool( + bgp->tx_addpath.id_allocators[afi][safi][addpath_type], + &(rn->tx_addpath.free_ids[addpath_type])); + for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { + if (pi->tx_addpath.addpath_tx_id[addpath_type] + != IDALLOC_INVALID) { + idalloc_free( + bgp->tx_addpath + .id_allocators[afi][safi][addpath_type], + pi->tx_addpath.addpath_tx_id[addpath_type]); + pi->tx_addpath.addpath_tx_id[addpath_type] = + IDALLOC_INVALID; + } + } +} + /* * Purge all addpath ID's on a BGP instance associated with the addpath * strategy, and afi/safi combination. This lets us let go of all memory held to @@ -185,26 +207,24 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, static void bgp_addpath_flush_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *pi; + struct bgp_node *rn, *nrn; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { - idalloc_drain_pool( - bgp->tx_addpath.id_allocators[afi][safi][addpath_type], - &(rn->tx_addpath.free_ids[addpath_type])); - for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { - if (pi->tx_addpath.addpath_tx_id[addpath_type] - != IDALLOC_INVALID) { - idalloc_free( - bgp->tx_addpath - .id_allocators[afi][safi] - [addpath_type], - pi->tx_addpath - .addpath_tx_id[addpath_type]); - pi->tx_addpath.addpath_tx_id[addpath_type] = - IDALLOC_INVALID; - } + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + bgp_addpath_flush_type_rn(bgp, afi, safi, + addpath_type, nrn); + } else { + bgp_addpath_flush_type_rn(bgp, afi, safi, addpath_type, + rn); } } @@ -234,8 +254,7 @@ static void bgp_addpath_populate_path(struct id_alloc *allocator, static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *bi; + struct bgp_node *rn, *nrn; char buf[200]; struct id_alloc *allocator; @@ -255,9 +274,29 @@ static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, allocator = bgp->tx_addpath.id_allocators[afi][safi][addpath_type]; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; - rn = bgp_route_next(rn)) - for (bi = bgp_node_get_bgp_path_info(rn); bi; bi = bi->next) - bgp_addpath_populate_path(allocator, bi, addpath_type); + rn = bgp_route_next(rn)) { + struct bgp_path_info *bi; + + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + for (bi = bgp_node_get_bgp_path_info(nrn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } else { + for (bi = bgp_node_get_bgp_path_info(rn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } + } } /* diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index d0ccdcedfb..4baac3e57a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1073,9 +1073,13 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ return; } - if (debug) - zlog_debug("%s: updating to vrf %s", __func__, - bgp_vrf->name_pretty); + if (debug) { + char buf_prefix[PREFIX_STRLEN]; + + prefix2str(p, buf_prefix, sizeof(buf_prefix)); + zlog_debug("%s: updating %s to vrf %s", __func__, + buf_prefix, bgp_vrf->name_pretty); + } bgp_attr_dup(&static_attr, path_vpn->attr); /* shallow copy */ @@ -1132,6 +1136,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ memset(&info, 0, sizeof(info)); info.peer = bgp_vrf->peer_self; info.attr = &static_attr; + info.extra = path_vpn->extra; /* Used for source-vrf filter */ ret = route_map_apply(bgp_vrf->vpn_policy[afi] .rmap[BGP_VPN_POLICY_DIR_FROMVPN], p, RMAP_BGP, &info); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8e72b742a3..230df715de 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -254,8 +254,9 @@ static void bgp_path_info_free(struct bgp_path_info *path) bgp_unlink_nexthop(path); bgp_path_info_extra_free(&path->extra); bgp_path_info_mpath_free(&path->mpath); - bgp_addpath_free_info_data(&path->tx_addpath, - path->net ? &path->net->tx_addpath : NULL); + if (path->net) + bgp_addpath_free_info_data(&path->tx_addpath, + &path->net->tx_addpath); peer_unlock(path->peer); /* bgp_path_info peer reference */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index e28acdfbae..17109281bc 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -65,6 +65,10 @@ #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_routemap_clippy.c" +#endif + /* Memo of route-map commands. o Cisco route-map @@ -905,6 +909,53 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { "evpn route-type", route_match_evpn_route_type, route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +/* Route map commands for VRF route leak with source vrf matching */ +static route_map_result_t +route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_path_info *path; + char *vrf_name; + + if (type == RMAP_BGP) { + vrf_name = rule; + path = (struct bgp_path_info *)object; + + if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0) + return RMAP_NOMATCH; + + if (path->extra == NULL) + return RMAP_NOMATCH; + + if (strncmp(vrf_name, vrf_id_to_name( + path->extra->bgp_orig->vrf_id), VRF_NAMSIZ) + == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +static void *route_match_vrl_source_vrf_compile(const char *arg) +{ + uint8_t *vrf_name = NULL; + + vrf_name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + + return vrf_name; +} + +/* Free route map's compiled `route-type' value. */ +static void route_match_vrl_source_vrf_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { + "source-vrf", route_match_vrl_source_vrf, + route_match_vrl_source_vrf_compile, + route_match_vrl_source_vrf_free}; + /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -3538,6 +3589,29 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFPY(match_vrl_source_vrf, + match_vrl_source_vrf_cmd, + "match source-vrf NAME$vrf_name", + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_add(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_ADDED); +} + +DEFPY(no_match_vrl_source_vrf, + no_match_vrl_source_vrf_cmd, + "no match source-vrf NAME$vrf_name", + NO_STR + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_delete(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_DELETED); +} + DEFUN (match_peer, match_peer_cmd, "match peer <A.B.C.D|X:X::X:X|WORD>", @@ -4992,6 +5066,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); + route_map_install_match(&route_match_vrl_source_vrf_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -5030,6 +5105,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); + install_element(RMAP_NODE, &match_vrl_source_vrf_cmd); + install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); diff --git a/bgpd/subdir.am b/bgpd/subdir.am index aed2939d3e..d281fe4e59 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -224,6 +224,8 @@ bgpd/bgp_route_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_route.$(OBJEXT): bgpd/bgp_route_clippy.c bgpd/bgp_debug_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_debug.$(OBJEXT): bgpd/bgp_debug_clippy.c +bgpd/bgp_routemap_clippy.c: $(CLIPPY_DEPS) +bgpd/bgp_routemap.$(OBJEXT): bgpd/bgp_routemap_clippy.c bgpd/bgp_rpki_clippy.c: $(CLIPPY_DEPS) $(AUTOMAKE_DUMMY)bgpd/bgpd_bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c $(AUTOMAKE_DUMMY)bgpd/bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c diff --git a/configure.ac b/configure.ac index 4a05c0d69a..fcfc4bd2fb 100755 --- a/configure.ac +++ b/configure.ac @@ -1611,7 +1611,7 @@ CFLAGS="$CFLAGS $LIBYANG_CFLAGS" AC_CHECK_MEMBER([struct lyd_node.priv], [], [ AC_MSG_ERROR([m4_normalize([ libyang needs to be compiled with ENABLE_LYD_PRIV=ON. - See http://docs.frrouting.org/projects/dev-guide/en/latest/building-libyang.html for details.]) + Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html]) ]) ], [[#include <libyang/libyang.h>]]) CFLAGS="$ac_cflags_save" diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/watchfrr.rst index f0b733298d..dceb423f82 100644 --- a/doc/manpages/watchfrr.rst +++ b/doc/manpages/watchfrr.rst @@ -22,21 +22,6 @@ In order to avoid restarting the daemons in quick succession, you can supply the OPTIONS ======= -The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. These options are mandatory unless the --dry option is used: - -.. option:: -s command, --start-command command - - Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be sub‐ stituted with the daemon name. - -.. option:: -k command, --kill-command command - - Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -.. option:: -r command, --restart command - - Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -Other options: .. option:: --dry @@ -92,6 +77,20 @@ Other options: Display the usage information and exit. +The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. Reasonable default values are built into watchfrr, so the use of these options should no longer be necessary: + +.. option:: -s command, --start-command command + + Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -k command, --kill-command command + + Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -r command, --restart command + + Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + PREVIOUS OPTIONS ================ Prior versions of |DAEMON| supported some additional options that no longer exist::: diff --git a/doc/user/setup.rst b/doc/user/setup.rst index 3a09c50309..ffefe37905 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -72,13 +72,14 @@ This file has several parts. Here is an example: fabricd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) + #watchfrr_options="" - # If valgrind_enable is 'yes' the frr daemons will be started via valgrind. - # The use case for doing so is tracking down memory leaks, etc in frr. - valgrind_enable=no - valgrind=/usr/bin/valgrind + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. Breaking this file down: @@ -101,22 +102,8 @@ from the service script. Usually daemons will have ``--daemon`` and ``-A <address>`` specified in order to daemonize and listen for VTY commands on a particular address. -:: - - # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) - -Options for the ``watchfrr``, the watchdog daemon. - -:: - - valgrind_enable=no - valgrind=/usr/bin/valgrind - -Whether or not to start FRR daemons under Valgrind. This is primarily useful -for gathering information for bug reports and for developers. -``valgrind_enable`` should be ``no`` for production use. +The remaining file content regarding `watchfrr_options` and `*_wrap` settings +should not normally be needed; refer to the comments in case they are. Services -------- diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index bd8b58e8f0..ab5faf76b6 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -279,25 +279,26 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - const struct lyd_node *dnode = - yang_dnode_get(running_config->dnode, VTY_CURR_XPATH); + const struct lyd_node *dnode; - /* if both ipv4 and ipv6 are off delete the interface isis container too + dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-isisd:isis", VTY_CURR_XPATH); + if (!dnode) + return CMD_SUCCESS; + + /* + * If both ipv4 and ipv6 are off delete the interface isis container. */ - if (!strncmp(ip, "ipv6", strlen("ipv6"))) { - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv4-routing")) + if (strmatch(ip, "ipv6")) { + if (!yang_dnode_get_bool(dnode, "./ipv4-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "false"); - } else { /* no ipv4 */ - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv6-routing")) + } else { + if (!yang_dnode_get_bool(dnode, "./ipv6-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_DESTROY, NULL); else diff --git a/lib/command.h b/lib/command.h index 0faaa426ac..a5f9616dbf 100644 --- a/lib/command.h +++ b/lib/command.h @@ -318,6 +318,9 @@ struct cmd_node { #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) + +#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) #endif /* VTYSH_EXTRACT_PL */ /* Some macroes */ diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 6103bd7db5..f3bfad3190 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -164,8 +164,8 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) == pbrnc2->nexthop->gate.ipv4.s_addr; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: - return !!memcmp(&pbrnc1->nexthop->gate.ipv6, - &pbrnc2->nexthop->gate.ipv6, 16); + return !memcmp(&pbrnc1->nexthop->gate.ipv6, + &pbrnc2->nexthop->gate.ipv6, 16); case NEXTHOP_TYPE_BLACKHOLE: return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type; } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 2b6c38593b..f8232c9581 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -300,7 +300,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, char buf[PBR_NHC_NAMELEN]; if (no) { - vty_out(vty, "No nexthops to delete"); + vty_out(vty, "No nexthops to delete\n"); return CMD_WARNING_CONFIG_FAILED; } diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index d2d2445a15..193eddf68a 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6404,6 +6404,56 @@ static int pim_cmd_interface_add(struct interface *ifp) return 1; } +DEFPY_HIDDEN (pim_test_sg_keepalive, + pim_test_sg_keepalive_cmd, + "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group", + "Test code\n" + PIM_STR + VRF_CMD_HELP_STR + "Reset the Keepalive Timer\n" + "The Source we are resetting\n" + "The Group we are resetting\n") +{ + struct pim_upstream *up; + struct pim_instance *pim; + struct prefix_sg sg; + + sg.src = source; + sg.grp = group; + + if (!name) + pim = pim_get_pim_instance(VRF_DEFAULT); + else { + struct vrf *vrf = vrf_lookup_by_name(name); + + if (!vrf) { + vty_out(vty, "%% Vrf specified: %s does not exist\n", + name); + return CMD_WARNING; + } + + pim = pim_get_pim_instance(vrf->vrf_id); + } + + if (!pim) { + vty_out(vty, "%% Unable to find pim instance\n"); + return CMD_WARNING; + } + + up = pim_upstream_find(pim, &sg); + if (!up) { + vty_out(vty, "%% Unable to find %s specified\n", + pim_str_sg_dump(&sg)); + return CMD_WARNING; + } + + vty_out(vty, "Setting %s to current keep alive time: %d\n", + pim_str_sg_dump(&sg), pim->keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); + + return CMD_SUCCESS; +} + DEFPY_HIDDEN (interface_ip_pim_activeactive, interface_ip_pim_activeactive_cmd, "[no$no] ip pim active-active", @@ -8667,7 +8717,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all, return CMD_SUCCESS; } - void pim_cmd_init(void) { install_node(&interface_node, @@ -8676,6 +8725,8 @@ void pim_cmd_init(void) install_node(&debug_node, pim_debug_config_write); + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); + install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 37abfeb30d..76a0d617ba 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -67,9 +67,9 @@ vtysh_b () { daemon_inst() { # note this sets global variables ($dmninst, $daemon, $inst) dmninst="$1" - daemon="${dmninst%:*}" + daemon="${dmninst%-*}" inst="" - [ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}" + [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}" } daemon_list() { @@ -92,9 +92,12 @@ daemon_list() { enabled="$enabled $daemon" if [ -n "$inst" ]; then debug "$daemon multi-instance $inst" + oldifs="${IFS}" + IFS="${IFS}," for i in $inst; do - enabled="$enabled $daemon:$inst" + enabled="$enabled $daemon-$i" done + IFS="${oldifs}" fi else debug "$daemon disabled" @@ -119,7 +122,7 @@ daemon_prep() { inst="$2" [ "$daemon" = "watchfrr" ] && return 0 [ -x "$D_PATH/$daemon" ] || { - log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n" + log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed" return 1 } [ -r "$C_PATH/frr.conf" ] && return 0 @@ -279,7 +282,7 @@ load_old_config() { } [ -r "$C_PATH/daemons" ] || { - log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n" + log_failure_msg "cannot run $@: $C_PATH/daemons does not exist" exit 1 } . "$C_PATH/daemons" diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 41fd6ed7d6..9ff869e503 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -104,7 +104,7 @@ static int vty_close_pager(struct vty *vty) return 0; } -static void vtysh_pager_envdef(void) +static void vtysh_pager_envdef(bool fallback) { char *pager_defined; @@ -112,7 +112,7 @@ static void vtysh_pager_envdef(void) if (pager_defined) vtysh_pager_name = strdup(pager_defined); - else + else if (fallback) vtysh_pager_name = strdup(VTYSH_PAGER); } @@ -2893,7 +2893,7 @@ DEFUN (vtysh_terminal_paginate, vtysh_pager_name = NULL; if (strcmp(argv[0]->text, "no")) - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2913,7 +2913,7 @@ DEFUN (vtysh_terminal_length, if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) { /* "terminal no length" = use VTYSH_PAGER */ - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2922,7 +2922,7 @@ DEFUN (vtysh_terminal_length, vty_out(vty, "%% The \"terminal length\" command is deprecated and its value is ignored.\n" "%% Please use \"terminal paginate\" instead with OS TTY length handling.\n"); - vtysh_pager_envdef(); + vtysh_pager_envdef(true); } return CMD_SUCCESS; @@ -3479,6 +3479,7 @@ void vtysh_init_vty(void) /* set default output */ vty->of = stdout; + vtysh_pager_envdef(false); /* Initialize commands. */ cmd_init(0); @@ -3812,6 +3813,7 @@ void vtysh_init_vty(void) /* "write memory" command. */ install_element(ENABLE_NODE, &vtysh_write_memory_cmd); + install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_length_cmd); install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8afcc2b685..b71bf77df2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1879,6 +1879,8 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) goto done; } + route_unlock_node(rn); + srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx); op = dplane_ctx_get_op(ctx); |
