diff options
| -rw-r--r-- | .clang-format | 2 | ||||
| -rw-r--r-- | README | 12 | ||||
| -rw-r--r-- | bgpd/bgp_advertise.c | 6 | ||||
| -rw-r--r-- | bgpd/bgp_io.c | 71 | ||||
| -rw-r--r-- | bgpd/bgp_io.h | 19 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 17 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 43 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 6 | ||||
| -rw-r--r-- | lib/frr_pthread.c | 1 | ||||
| -rw-r--r-- | lib/frr_pthread.h | 3 | ||||
| -rw-r--r-- | ospfd/ospf_abr.c | 67 | ||||
| -rw-r--r-- | ospfd/ospf_apiserver.c | 33 | ||||
| -rw-r--r-- | ospfd/ospf_ase.c | 7 | ||||
| -rw-r--r-- | ospfd/ospf_ia.c | 4 | ||||
| -rw-r--r-- | ospfd/ospf_lsa.c | 33 | ||||
| -rw-r--r-- | ospfd/ospf_nsm.c | 18 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 4 | ||||
| -rw-r--r-- | ospfd/ospfd.c | 25 | ||||
| -rwxr-xr-x | tools/frr-reload.py | 9 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 165 | ||||
| -rw-r--r-- | vtysh/vtysh.h | 1 | ||||
| -rw-r--r-- | vtysh/vtysh_main.c | 2 |
23 files changed, 341 insertions, 211 deletions
diff --git a/.clang-format b/.clang-format index 21fe9d7c5e..cc5a95baf6 100644 --- a/.clang-format +++ b/.clang-format @@ -57,3 +57,5 @@ ForEachMacros: - SUBGRP_FOREACH_ADJ_SAFE - AF_FOREACH - FOREACH_AFI_SAFI + # ospfd + - LSDB_LOOP @@ -1,12 +1,14 @@ -FRRouting is free software that manages various IPv4 and IPv6 routing -protocols. +FRRouting is free software that implements and manages various IPv4 and IPv6 +routing protocols. -Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, -RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS, -EIGRP and NHRP. +Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng, +IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and +NHRP. See the file REPORTING-BUGS to report bugs. +See COMMUNITY.md for information on contributing. + Free RRRouting is free software. See the file COPYING for copying conditions. Public email discussion can be found at https://lists.frrouting.org/listinfo diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 840cc35751..29b6ca6bfa 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -246,8 +246,6 @@ void bgp_sync_init(struct peer *peer) BGP_ADV_FIFO_INIT(&sync->withdraw); BGP_ADV_FIFO_INIT(&sync->withdraw_low); peer->sync[afi][safi] = sync; - peer->hash[afi][safi] = hash_create(baa_hash_key, baa_hash_cmp, - "BGP Sync Hash"); } } @@ -260,9 +258,5 @@ void bgp_sync_delete(struct peer *peer) if (peer->sync[afi][safi]) XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); peer->sync[afi][safi] = NULL; - - if (peer->hash[afi][safi]) - hash_free(peer->hash[afi][safi]); - peer->hash[afi][safi] = NULL; } } diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 5ab14d5cd6..98a8ec6e02 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -51,19 +51,37 @@ static bool validate_header(struct peer *); #define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred #define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error -/* Start and stop routines for I/O pthread + control variables +/* Plumbing & control variables for thread lifecycle * ------------------------------------------------------------------------ */ -_Atomic bool bgp_io_thread_run; -_Atomic bool bgp_io_thread_started; +bool bgp_io_thread_run; +pthread_mutex_t *running_cond_mtx; +pthread_cond_t *running_cond; -void bgp_io_init() +/* Unused callback for thread_add_read() */ +static int bgp_io_dummy(struct thread *thread) { return 0; } + +/* Poison pill task */ +static int bgp_io_finish(struct thread *thread) { bgp_io_thread_run = false; - bgp_io_thread_started = false; + return 0; } -/* Unused callback for thread_add_read() */ -static int bgp_io_dummy(struct thread *thread) { return 0; } +/* Extern lifecycle control functions. init -> start -> stop + * ------------------------------------------------------------------------ */ +void bgp_io_init() +{ + bgp_io_thread_run = false; + + running_cond_mtx = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); + running_cond = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_cond_t)); + + pthread_mutex_init(running_cond_mtx, NULL); + pthread_cond_init(running_cond, NULL); + + /* unlocked in bgp_io_wait_running() */ + pthread_mutex_lock(running_cond_mtx); +} void *bgp_io_start(void *arg) { @@ -80,9 +98,12 @@ void *bgp_io_start(void *arg) struct thread task; - atomic_store_explicit(&bgp_io_thread_run, true, memory_order_seq_cst); - atomic_store_explicit(&bgp_io_thread_started, true, - memory_order_seq_cst); + pthread_mutex_lock(running_cond_mtx); + { + bgp_io_thread_run = true; + pthread_cond_signal(running_cond); + } + pthread_mutex_unlock(running_cond_mtx); while (bgp_io_thread_run) { if (thread_fetch(fpt->master, &task)) { @@ -96,29 +117,35 @@ void *bgp_io_start(void *arg) return NULL; } -static int bgp_io_finish(struct thread *thread) +void bgp_io_wait_running() { - atomic_store_explicit(&bgp_io_thread_run, false, memory_order_seq_cst); - return 0; + while (!bgp_io_thread_run) + pthread_cond_wait(running_cond, running_cond_mtx); + + /* locked in bgp_io_init() */ + pthread_mutex_unlock(running_cond_mtx); } int bgp_io_stop(void **result, struct frr_pthread *fpt) { thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL); pthread_join(fpt->thread, result); + + pthread_mutex_destroy(running_cond_mtx); + pthread_cond_destroy(running_cond); + + XFREE(MTYPE_PTHREAD_PRIM, running_cond_mtx); + XFREE(MTYPE_PTHREAD_PRIM, running_cond); + return 0; } /* Extern API -------------------------------------------------------------- */ -void bgp_io_running(void) -{ - while (!atomic_load_explicit(&bgp_io_thread_started, - memory_order_seq_cst)) - frr_pthread_yield(); -} void bgp_writes_on(struct peer *peer) { + assert(bgp_io_thread_run); + assert(peer->status != Deleted); assert(peer->obuf); assert(peer->ibuf); @@ -136,6 +163,8 @@ void bgp_writes_on(struct peer *peer) void bgp_writes_off(struct peer *peer) { + assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); thread_cancel_async(fpt->master, &peer->t_write, NULL); @@ -146,6 +175,8 @@ void bgp_writes_off(struct peer *peer) void bgp_reads_on(struct peer *peer) { + assert(bgp_io_thread_run); + assert(peer->status != Deleted); assert(peer->ibuf); assert(peer->fd); @@ -165,6 +196,8 @@ void bgp_reads_on(struct peer *peer) void bgp_reads_off(struct peer *peer) { + assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); thread_cancel_async(fpt->master, &peer->t_read, NULL); diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 73587366d7..7cfd1db710 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -31,27 +31,26 @@ /** * Initializes data structures and flags for the write thread. * - * This function should be called from the main thread before + * This function must be called from the main thread before * bgp_writes_start() is invoked. */ extern void bgp_io_init(void); /** - * Ensure that the BGP IO thread is actually up and running + * Start function for write thread. * - * This function must be called immediately after the thread - * has been created for running. This is because we want - * to make sure that the io thread is ready before other - * threads start attempting to use it. + * @param arg - unused */ -extern void bgp_io_running(void); +extern void *bgp_io_start(void *arg); /** - * Start function for write thread. + * Wait until the IO thread is ready to accept jobs. * - * @param arg - unused + * This function must be called immediately after the thread has been created + * for running. Use of other functions before calling this one will result in + * undefined behavior. */ -extern void *bgp_io_start(void *arg); +extern void bgp_io_wait_running(void); /** * Start function for write thread. diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c691233c57..ad3fac20f1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2719,7 +2719,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* AS path local-as loop check. */ if (peer->change_local_as) { - if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) + if (peer->allowas_in[afi][safi]) + aspath_loop_count = peer->allowas_in[afi][safi]; + else if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) aspath_loop_count = 1; if (aspath_loop_check(attr->aspath, peer->change_local_as) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 76c315de7f..19cfb2d91d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2692,6 +2692,19 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, return bgp_vty_return(vty, ret); } +DEFUN (bgp_default_shutdown, + bgp_default_shutdown_cmd, + "[no] bgp default shutdown", + NO_STR + BGP_STR + "Configure BGP defaults\n" + "Do not automatically activate peers upon configuration\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->autoshutdown = !strmatch(argv[0]->text, "no"); + return CMD_SUCCESS; +} + DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>", @@ -3238,7 +3251,6 @@ DEFUN (no_neighbor_password, return bgp_vty_return(vty, ret); } - DEFUN (neighbor_activate, neighbor_activate_cmd, "neighbor <A.B.C.D|X:X::X:X|WORD> activate", @@ -11555,6 +11567,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_listen_range_cmd); install_element(BGP_NODE, &no_bgp_listen_range_cmd); + /* "neighbors auto-shutdown" command */ + install_element(BGP_NODE, &bgp_default_shutdown_cmd); + /* "neighbor remote-as" commands. */ install_element(BGP_NODE, &neighbor_remote_as_cmd); install_element(BGP_NODE, &neighbor_interface_config_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5356cfd2fc..7db73043cc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -866,8 +866,7 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi) /* peer global config reset */ static void peer_global_config_reset(struct peer *peer) { - - int v6only; + int saved_flags = 0; peer->change_local_as = 0; peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1); @@ -885,13 +884,11 @@ static void peer_global_config_reset(struct peer *peer) else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; - /* This is a per-peer specific flag and so we must preserve it */ - v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); - + /* These are per-peer specific flags and so we must preserve them */ + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN); peer->flags = 0; - - if (v6only) - SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + SET_FLAG(peer->flags, saved_flags); peer->config = 0; peer->holdtime = 0; @@ -1498,8 +1495,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer_af_create(peer, afi, safi); } + /* auto shutdown if configured */ + if (bgp->autoshutdown) + peer_flag_set(peer, PEER_FLAG_SHUTDOWN); /* Set up peer's events and timers. */ - if (!active && peer_active(peer)) + else if (!active && peer_active(peer)) bgp_timer_set(peer); return peer; @@ -2340,7 +2340,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, struct peer *peer) { struct peer *conf; - int v6only; + int saved_flags = 0; conf = group->conf; @@ -2358,14 +2358,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* GTSM hops */ peer->gtsm_hops = conf->gtsm_hops; - /* this flag is per-neighbor and so has to be preserved */ - v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); - - /* peer flags apply */ + /* These are per-peer specific flags and so we must preserve them */ + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN); peer->flags = conf->flags; - - if (v6only) - SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + SET_FLAG(peer->flags, saved_flags); /* peer config apply */ peer->config = conf->config; @@ -7152,6 +7149,10 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n", bgp->default_subgroup_pkt_queue_max); + /* BGP default autoshutdown neighbors */ + if (bgp->autoshutdown) + vty_out(vty, " bgp default auto-shutdown\n"); + /* BGP client-to-client reflection. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) vty_out(vty, " no bgp client-to-client reflection\n"); @@ -7486,13 +7487,11 @@ void bgp_pthreads_run() pthread_attr_setschedpolicy(&attr, SCHED_FIFO); /* - * Please ensure that the io thread is running - * by calling bgp_io_running. The BGP threads - * depend on it being running when we start - * looking for it. + * I/O related code assumes the thread is ready for work at all times, + * so we wait until it is. */ frr_pthread_run(PTHREAD_IO, &attr, NULL); - bgp_io_running(); + bgp_io_wait_running(); frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8e843eb659..c4ac4b0adb 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -390,6 +390,9 @@ struct bgp { /* Actual coalesce time */ uint32_t coalesce_time; + /* Auto-shutdown new peers */ + bool autoshutdown; + u_int32_t addpath_tx_id; int addpath_tx_used[AFI_MAX][SAFI_MAX]; @@ -916,9 +919,6 @@ struct peer { /* Send prefix count. */ unsigned long scount[AFI_MAX][SAFI_MAX]; - /* Announcement attribute hash. */ - struct hash *hash[AFI_MAX][SAFI_MAX]; - /* Notify data. */ struct bgp_notify notify; diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 19dfbaf54b..de522e5ef9 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -26,6 +26,7 @@ #include "hash.h" DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); +DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives"); static unsigned int next_id = 0; diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index f6000340a7..7915b43a46 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -21,8 +21,11 @@ #define _FRR_PTHREAD_H #include <pthread.h> +#include "memory.h" #include "thread.h" +DECLARE_MTYPE(PTHREAD_PRIM); + struct frr_pthread { /* pthread id */ diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index f7aa94ad18..ea94bab6b3 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -327,8 +327,7 @@ static int ospf_abr_nssa_am_elected(struct ospf_area *area) struct router_lsa *rlsa; struct in_addr *best = NULL; - LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - { + LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) { /* sanity checks */ if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA) || IS_LSA_SELF(lsa)) @@ -978,7 +977,7 @@ static void ospf_abr_process_nssa_translates(struct ospf *ospf) inet_ntoa(area->area_id)); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_abr_translate_nssa(area, lsa); + ospf_abr_translate_nssa(area, lsa); } if (IS_DEBUG_OSPF_NSSA) @@ -1325,14 +1324,14 @@ ospf_abr_unapprove_translates(struct ospf *ospf) /* For NSSA Translations */ and we would want to flush any residuals anyway */ LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) { - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - if (IS_DEBUG_OSPF_NSSA) - zlog_debug( - "ospf_abr_unapprove_translates(): " - "approved unset on link id %s", - inet_ntoa(lsa->data->id)); - } + if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) { + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_abr_unapprove_translates(): " + "approved unset on link id %s", + inet_ntoa(lsa->data->id)); + } if (IS_DEBUG_OSPF_NSSA) zlog_debug("ospf_abr_unapprove_translates(): Stop"); @@ -1355,24 +1354,24 @@ static void ospf_abr_unapprove_summaries(struct ospf *ospf) "considering area %s", inet_ntoa(area->area_id)); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "ospf_abr_unapprove_summaries(): " - "approved unset on summary link id %s", - inet_ntoa(lsa->data->id)); - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - } + if (ospf_lsa_is_self_originated(ospf, lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_abr_unapprove_summaries(): " + "approved unset on summary link id %s", + inet_ntoa(lsa->data->id)); + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + } LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "ospf_abr_unapprove_summaries(): " - "approved unset on asbr-summary link id %s", - inet_ntoa(lsa->data->id)); - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - } + if (ospf_lsa_is_self_originated(ospf, lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_abr_unapprove_summaries(): " + "approved unset on asbr-summary link id %s", + inet_ntoa(lsa->data->id)); + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + } } if (IS_DEBUG_OSPF_EVENT) @@ -1633,7 +1632,7 @@ static void ospf_abr_remove_unapproved_translates(struct ospf *ospf) zlog_debug("ospf_abr_remove_unapproved_translates(): Start"); LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_abr_remove_unapproved_translates_apply(ospf, lsa); + ospf_abr_remove_unapproved_translates_apply(ospf, lsa); if (IS_DEBUG_OSPF_NSSA) zlog_debug("ospf_abr_remove_unapproved_translates(): Stop"); @@ -1657,14 +1656,14 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf) inet_ntoa(area->area_id)); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) - if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) - ospf_lsa_flush_area(lsa, area); + if (ospf_lsa_is_self_originated(ospf, lsa)) + if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area(lsa, area); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) - if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) - ospf_lsa_flush_area(lsa, area); + if (ospf_lsa_is_self_originated(ospf, lsa)) + if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area(lsa, area); } if (IS_DEBUG_OSPF_EVENT) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 8c1ad5ff0c..9ebaeffa69 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1313,22 +1313,28 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, /* Check msg type. */ if (mask & Power2[OSPF_ROUTER_LSA]) LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_NETWORK_LSA]) LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_SUMMARY_LSA]) LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_ASBR_SUMMARY_LSA]) LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_LINK_LSA]) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_AREA_LSA]) LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); } } @@ -1336,14 +1342,16 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, if (ospf->lsdb) { if (mask & Power2[OSPF_AS_EXTERNAL_LSA]) LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback(lsa, (void *)¶m, + seqnum); } /* For AS-external opaque LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_OPAQUE_AS_LSA]) LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback(lsa, (void *)¶m, + seqnum); } /* Send a reply back to client with return code */ @@ -1945,16 +1953,19 @@ void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv, case OSPF_OPAQUE_LINK_LSA: for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback( + lsa, (void *)¶m, 0); break; case OSPF_OPAQUE_AREA_LSA: for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback( + lsa, (void *)¶m, 0); break; case OSPF_OPAQUE_AS_LSA: LSDB_LOOP(OPAQUE_LINK_LSDB(ospf), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback(lsa, + (void *)¶m, 0); break; default: break; diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 368987a2ba..d2af974833 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -649,7 +649,7 @@ static int ospf_ase_calculate_timer(struct thread *t) /* Calculate external route for each AS-external-LSA */ LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, lsa); /* This version simple adds to the table all NSSA areas */ if (ospf->anyNSSA) @@ -661,11 +661,12 @@ static int ospf_ase_calculate_timer(struct thread *t) if (area->external_routing == OSPF_AREA_NSSA) LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, + lsa); } /* kevinm: And add the NSSA routes in ospf_top */ LSDB_LOOP(NSSA_LSDB(ospf), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, lsa); /* Compare old and new external routing table and install the difference info zebra/kernel */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c index c65d8b8743..e570f3337a 100644 --- a/ospfd/ospf_ia.c +++ b/ospfd/ospf_ia.c @@ -283,7 +283,7 @@ static void ospf_examine_summaries(struct ospf_area *area, struct route_node *rn; LSDB_LOOP(lsdb_rt, rn, lsa) - process_summary_lsa(area, rt, rtrs, lsa); + process_summary_lsa(area, rt, rtrs, lsa); } int ospf_area_is_transit(struct ospf_area *area) @@ -583,7 +583,7 @@ static void ospf_examine_transit_summaries(struct ospf_area *area, struct route_node *rn; LSDB_LOOP(lsdb_rt, rn, lsa) - process_transit_summary_lsa(area, rt, rtrs, lsa); + process_transit_summary_lsa(area, rt, rtrs, lsa); } void ospf_ia_routing(struct ospf *ospf, struct route_table *rt, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index a2961992de..0f1dd63dfb 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1872,8 +1872,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, if (area->external_routing != OSPF_AREA_NSSA && !type7) continue; - LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - { + LSDB_LOOP (NSSA_LSDB(area), rn, lsa) { if (lsa->data->id.s_addr == type5->data->id.s_addr) { type7 = lsa; @@ -3007,27 +3006,27 @@ int ospf_lsa_maxage_walker(struct thread *thread) for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); } /* for AS-external-LSAs. */ if (ospf->lsdb) { LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); } OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker, @@ -3350,20 +3349,20 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf) } LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); } if (need_to_flush_ase) { LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); } /* diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c87001294d..54d5dd5d16 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -280,37 +280,37 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr) ospf_proactively_arp(nbr); LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) { LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); } if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) { LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); } if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT) LSDB_LOOP(EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); if (CHECK_FLAG(nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP(OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); return 0; } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a1384eebdd..bc95118345 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -6167,7 +6167,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, show_database_header[type]); LSDB_LOOP(AREA_LSDB(area, type), rn, lsa) - show_lsa_summary(vty, lsa, self); + show_lsa_summary(vty, lsa, self); vty_out(vty, "\n"); } @@ -6189,7 +6189,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, vty_out(vty, "%s\n", show_database_header[type]); LSDB_LOOP(AS_LSDB(ospf, type), rn, lsa) - show_lsa_summary(vty, lsa, self); + show_lsa_summary(vty, lsa, self); vty_out(vty, "\n"); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1926197430..862e87e40f 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -159,8 +159,8 @@ void ospf_router_id_update(struct ospf *ospf) struct ospf_lsa *lsa; LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - if (IS_LSA_SELF(lsa)) - ospf_lsa_flush_schedule(ospf, lsa); + if (IS_LSA_SELF(lsa)) + ospf_lsa_flush_schedule(ospf, lsa); } ospf->router_id = router_id; @@ -183,8 +183,7 @@ void ospf_router_id_update(struct ospf *ospf) struct route_node *rn; struct ospf_lsa *lsa; - LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - { + LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) { /* AdvRouter and Router ID is the same. */ if (IPV4_ADDR_SAME(&lsa->data->adv_router, &ospf->router_id)) { @@ -693,9 +692,9 @@ static void ospf_finish_final(struct ospf *ospf) stream_free(ospf->ibuf); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_discard_from_db(ospf, ospf->lsdb, lsa); + ospf_discard_from_db(ospf, ospf->lsdb, lsa); LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_discard_from_db(ospf, ospf->lsdb, lsa); + ospf_discard_from_db(ospf, ospf->lsdb, lsa); ospf_lsdb_delete_all(ospf->lsdb); ospf_lsdb_free(ospf->lsdb); @@ -830,20 +829,20 @@ static void ospf_area_free(struct ospf_area *area) /* Free LSDBs. */ LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); ospf_opaque_type10_lsa_term(area); ospf_lsdb_delete_all(area->lsdb); diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 2c651ffbd5..0b7e80962c 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -434,7 +434,14 @@ end new_ctx = False log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) - elif "vni " in line: + # The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates + # a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE') + # does not. + elif ("vni " in line and + len(ctx_keys) == 2 and + ctx_keys[0].startswith('router bgp') and + ctx_keys[1] == 'address-family l2vpn evpn'): + main_ctx_key = [] # Save old context first diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 76343ded60..097f39fcf0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -46,6 +46,9 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy") +/* Destination for vtysh output */ +FILE *outputfile; + /* Struct VTY. */ struct vty *vty; @@ -138,16 +141,25 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, bufvalid += nread; - end = memmem(buf, bufvalid - buf, terminator, - sizeof(terminator)); - if (end + sizeof(terminator) + 1 > bufvalid) + if (bufvalid - buf >= 4) + end = memmem(bufvalid - 4, 4, terminator, + sizeof(terminator)); + + if (end && end + sizeof(terminator) + 1 > bufvalid) /* found \0\0\0 but return code hasn't been read yet */ end = NULL; if (end) ret = end[sizeof(terminator)]; - while (bufvalid > buf && (end > buf || !end)) { - size_t textlen = (end ? end : bufvalid) - buf; + /* + * calculate # bytes we have, up to & not including the + * terminator if present + */ + size_t textlen = (end ? end : bufvalid) - buf; + + /* feed line processing callback if present */ + while (callback && bufvalid > buf && (end > buf || !end)) { + textlen = (end ? end : bufvalid) - buf; char *eol = memchr(buf, '\n', textlen); if (eol) /* line break */ @@ -165,8 +177,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, /* continue reading */ break; - /* eol is at a line end now, either \n => \0 or \0\0\0 - */ + /* eol is at line end now, either \n => \0 or \0\0\0 */ assert(eol && eol <= bufvalid); if (fp) { @@ -186,6 +197,14 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, end -= eol - buf; } + /* else if no callback, dump raw */ + if (!callback) { + if (fp) + fwrite(buf, 1, textlen, fp); + memmove(buf, buf + textlen, bufvalid - buf - textlen); + bufvalid -= textlen; + } + if (bufvalid == buf + bufsz) { char *new; bufsz *= 2; @@ -375,21 +394,21 @@ static int vtysh_execute_func(const char *line, int pager) fprintf(stdout, "%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { - /* FIXME: Don't open pager for exit commands. popen() causes - * problems - * if exited from vtysh at all. This hack shouldn't cause any - * problem - * but is really ugly. */ - if (pager && vtysh_pager_name + /* + * FIXME: Don't open pager for exit commands. popen() causes + * problems if exited from vtysh at all. This hack shouldn't + * cause any problem but is really ugly. + */ + fp = outputfile; + if (pager && vtysh_pager_name && outputfile == stdout && (strncmp(line, "exit", 4) != 0)) { fp = popen(vtysh_pager_name, "w"); if (fp == NULL) { perror("popen failed for pager"); - fp = stdout; + fp = outputfile; } else closepager = 1; - } else - fp = stdout; + } if (!strcmp(cmd->string, "configure terminal")) { for (i = 0; i < array_size(vtysh_client); i++) { @@ -405,7 +424,7 @@ static int vtysh_execute_func(const char *line, int pager) if (vline == NULL) { if (pager && vtysh_pager_name && fp - && closepager) { + && fp != outputfile && closepager) { if (pclose(fp) == -1) { perror("pclose failed for pager"); } @@ -455,7 +474,7 @@ static int vtysh_execute_func(const char *line, int pager) (*cmd->func)(cmd, vty, 0, NULL); } } - if (pager && vtysh_pager_name && fp && closepager) { + if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) { if (pclose(fp) == -1) { perror("pclose failed for pager"); } @@ -537,19 +556,19 @@ int vtysh_mark_file(const char *filename) switch (vty->node) { case LDP_IPV4_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_IPV4_NODE; } break; case LDP_IPV6_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_IPV6_NODE; } break; case LDP_PSEUDOWIRE_NODE: if (strncmp(vty_buf_copy, " ", 2)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_L2VPN_NODE; } break; @@ -558,7 +577,7 @@ int vtysh_mark_file(const char *filename) } if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') { - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); continue; } @@ -566,7 +585,7 @@ int vtysh_mark_file(const char *filename) vline = cmd_make_strvec(vty->buf); if (vline == NULL) { - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); continue; } @@ -609,15 +628,15 @@ int vtysh_mark_file(const char *filename) || prev_node == BGP_IPV6M_NODE || prev_node == BGP_EVPN_NODE) && (tried == 1)) { - fprintf(stdout, "exit-address-family\n"); + fprintf(outputfile, "exit-address-family\n"); } else if ((prev_node == BGP_EVPN_VNI_NODE) && (tried == 1)) { - fprintf(stdout, "exit-vni\n"); + fprintf(outputfile, "exit-vni\n"); } else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { - fprintf(stdout, "exit\n"); + fprintf(outputfile, "exit\n"); } else if (tried) { - fprintf(stdout, "end\n"); + fprintf(outputfile, "end\n"); } } /* If command didn't succeed in any node, continue with return @@ -667,12 +686,12 @@ int vtysh_mark_file(const char *filename) u_int i; int cmd_stat = CMD_SUCCESS; - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute( &vtysh_client[i], vty->buf, - stdout); + outputfile); if (cmd_stat != CMD_SUCCESS) break; } @@ -686,7 +705,7 @@ int vtysh_mark_file(const char *filename) } } /* This is the end */ - fprintf(stdout, "\nend\n"); + fprintf(outputfile, "\nend\n"); vty_close(vty); XFREE(MTYPE_VTYSH_CMD, vty_buf_copy); @@ -749,7 +768,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp) if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute( &vtysh_client[i], vty->buf, - stdout); + outputfile); /* * CMD_WARNING - Can mean that the * command was @@ -1854,7 +1873,7 @@ DEFUN (vtysh_show_thread, fprintf(stdout, "Thread statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } return ret; @@ -1875,7 +1894,7 @@ DEFUN (vtysh_show_work_queues, fprintf(stdout, "Work queue statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } @@ -1905,7 +1924,7 @@ DEFUN (vtysh_show_work_queues_daemon, } ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n", - stdout); + outputfile); return ret; } @@ -1932,9 +1951,9 @@ static int show_per_daemon(const char *line, const char *headline) for (i = 0; i < array_size(vtysh_client); i++) if (vtysh_client[i].fd >= 0) { - fprintf(stdout, headline, vtysh_client[i].name); + fprintf(outputfile, headline, vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } @@ -2226,20 +2245,19 @@ DEFUN (vtysh_write_terminal, { u_int i; char line[] = "do write terminal\n"; - FILE *fp = NULL; + FILE *fp = outputfile; - if (vtysh_pager_name) { + if (fp == stdout && vtysh_pager_name) { fp = popen(vtysh_pager_name, "w"); if (fp == NULL) { perror("popen"); exit(1); } - } else - fp = stdout; + } - vty_out(vty, "Building configuration...\n"); - vty_out(vty, "\nCurrent configuration:\n"); - vty_out(vty, "!\n"); + fprintf(outputfile, "Building configuration...\n"); + fprintf(outputfile, "\nCurrent configuration:\n"); + fprintf(outputfile, "!\n"); for (i = 0; i < array_size(vtysh_client); i++) if ((argc < 3) @@ -2251,7 +2269,7 @@ DEFUN (vtysh_write_terminal, vtysh_config_dump(fp); - if (vtysh_pager_name && fp) { + if (vtysh_pager_name && fp && fp != outputfile) { fflush(fp); if (pclose(fp) == -1) { perror("pclose"); @@ -2260,7 +2278,7 @@ DEFUN (vtysh_write_terminal, fp = NULL; } - vty_out(vty, "end\n"); + fprintf(outputfile, "end\n"); return CMD_SUCCESS; } @@ -2429,7 +2447,7 @@ DEFUN (vtysh_write_memory, char line[] = "do write memory\n"; u_int i; - fprintf(stdout, + fprintf(outputfile, "Note: this version of vtysh never writes vtysh.conf\n"); /* If integrated frr.conf explicitely set. */ @@ -2441,7 +2459,7 @@ DEFUN (vtysh_write_memory, if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1) ret = vtysh_client_execute(&vtysh_client[i], "do write integrated", - stdout); + outputfile); if (ret != CMD_SUCCESS) { printf("\nWarning: attempting direct configuration write without " @@ -2452,10 +2470,10 @@ DEFUN (vtysh_write_memory, return ret; } - fprintf(stdout, "Building Configuration...\n"); + fprintf(outputfile, "Building Configuration...\n"); for (i = 0; i < array_size(vtysh_client); i++) - ret = vtysh_client_execute(&vtysh_client[i], line, stdout); + ret = vtysh_client_execute(&vtysh_client[i], line, outputfile); return ret; } @@ -2484,7 +2502,7 @@ DEFUN (vtysh_terminal_length, lines = strtol(argv[idx_number]->arg, &endptr, 10); if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed\n"); + fprintf(outputfile, "length is malformed\n"); return CMD_WARNING; } @@ -2527,8 +2545,8 @@ DEFUN (vtysh_show_daemons, for (i = 0; i < array_size(vtysh_client); i++) if (vtysh_client[i].fd >= 0) - vty_out(vty, " %s", vtysh_client[i].name); - vty_out(vty, "\n"); + fprintf(outputfile, " %s", vtysh_client[i].name); + fprintf(outputfile, "\n"); return CMD_SUCCESS; } @@ -2703,6 +2721,38 @@ DEFUN (config_list, return cmd_list_cmds(vty, argc == 2); } +DEFUN (vtysh_output_file, + vtysh_output_file_cmd, + "output file FILE", + "Direct vtysh output to file\n" + "Direct vtysh output to file\n" + "Path to dump output to\n") +{ + const char *path = argv[argc - 1]->arg; + outputfile = fopen(path, "a"); + if (!outputfile) { + fprintf(stdout, "Failed to open file '%s': %s\n", path, + safe_strerror(errno)); + outputfile = stdout; + } + return CMD_SUCCESS; +} + +DEFUN (no_vtysh_output_file, + no_vtysh_output_file_cmd, + "no output file [FILE]", + NO_STR + "Direct vtysh output to file\n" + "Direct vtysh output to file\n" + "Path to dump output to\n") +{ + if (outputfile != stdout) { + fclose(outputfile); + outputfile = stdout; + } + return CMD_SUCCESS; +} + DEFUN(find, find_cmd, "find COMMAND...", @@ -2736,6 +2786,8 @@ static void vtysh_install_default(enum node_type node) { install_element(node, &config_list_cmd); install_element(node, &find_cmd); + install_element(node, &vtysh_output_file_cmd); + install_element(node, &no_vtysh_output_file_cmd); } /* Making connection to protocol daemon. */ @@ -2964,6 +3016,12 @@ static const struct cmd_variable_handler vtysh_var_handler[] = { .completions = vtysh_autocomplete}, {.completions = NULL}}; +void vtysh_uninit() +{ + if (outputfile != stdout) + fclose(outputfile); +} + void vtysh_init_vty(void) { /* Make vty structure. */ @@ -2971,6 +3029,9 @@ void vtysh_init_vty(void) vty->type = VTY_SHELL; vty->node = VIEW_NODE; + /* set default output */ + outputfile = stdout; + /* Initialize commands. */ cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index c584d7a905..ab13182094 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -63,6 +63,7 @@ extern char frr_config[]; extern char vtydir[]; void vtysh_init_vty(void); +void vtysh_uninit(void); void vtysh_init_cmd(void); extern int vtysh_connect_all(const char *optional_daemon_name); void vtysh_readline_init(void); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 57042f8e62..a4985c423c 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -644,6 +644,8 @@ int main(int argc, char **argv, char **env) while (vtysh_rl_gets()) vtysh_execute(line_read); + vtysh_uninit(); + history_truncate_file(history_file, 1000); printf("\n"); |
