summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--README12
-rw-r--r--bgpd/bgp_advertise.c6
-rw-r--r--bgpd/bgp_io.c71
-rw-r--r--bgpd/bgp_io.h19
-rw-r--r--bgpd/bgp_route.c4
-rw-r--r--bgpd/bgp_vty.c17
-rw-r--r--bgpd/bgpd.c43
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--lib/frr_pthread.c1
-rw-r--r--lib/frr_pthread.h3
-rw-r--r--ospfd/ospf_abr.c67
-rw-r--r--ospfd/ospf_apiserver.c33
-rw-r--r--ospfd/ospf_ase.c7
-rw-r--r--ospfd/ospf_ia.c4
-rw-r--r--ospfd/ospf_lsa.c33
-rw-r--r--ospfd/ospf_nsm.c18
-rw-r--r--ospfd/ospf_vty.c4
-rw-r--r--ospfd/ospfd.c25
-rwxr-xr-xtools/frr-reload.py9
-rw-r--r--vtysh/vtysh.c165
-rw-r--r--vtysh/vtysh.h1
-rw-r--r--vtysh/vtysh_main.c2
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
diff --git a/README b/README
index bbad60087b..af14795a6a 100644
--- a/README
+++ b/README
@@ -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 *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, seqnum);
if (mask & Power2[OSPF_NETWORK_LSA])
LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
- apiserver_sync_callback(lsa, (void *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, seqnum);
if (mask & Power2[OSPF_SUMMARY_LSA])
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
- apiserver_sync_callback(lsa, (void *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, seqnum);
if (mask & Power2[OSPF_ASBR_SUMMARY_LSA])
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
- apiserver_sync_callback(lsa, (void *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, seqnum);
if (mask & Power2[OSPF_OPAQUE_LINK_LSA])
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
- apiserver_sync_callback(lsa, (void *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, seqnum);
if (mask & Power2[OSPF_OPAQUE_AREA_LSA])
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
- apiserver_sync_callback(lsa, (void *)&param, seqnum);
+ apiserver_sync_callback(
+ lsa, (void *)&param, 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 *)&param, seqnum);
+ apiserver_sync_callback(lsa, (void *)&param,
+ 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 *)&param, seqnum);
+ apiserver_sync_callback(lsa, (void *)&param,
+ 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 *)&param, 0);
+ apiserver_flush_opaque_type_callback(
+ lsa, (void *)&param, 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 *)&param, 0);
+ apiserver_flush_opaque_type_callback(
+ lsa, (void *)&param, 0);
break;
case OSPF_OPAQUE_AS_LSA:
LSDB_LOOP(OPAQUE_LINK_LSDB(ospf), rn, lsa)
- apiserver_flush_opaque_type_callback(lsa, (void *)&param, 0);
+ apiserver_flush_opaque_type_callback(lsa,
+ (void *)&param, 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");