summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in3
-rw-r--r--bgpd/bgp_advertise.c2
-rw-r--r--bgpd/bgp_advertise.h11
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_route.c2
-rw-r--r--bgpd/bgp_table.c2
-rw-r--r--bgpd/bgp_table.h3
-rw-r--r--bgpd/bgp_updgrp_adv.c53
-rw-r--r--bgpd/bgp_vty.c2
-rwxr-xr-xconfigure.ac5
-rw-r--r--debianpkg/README.Debian2
-rw-r--r--debianpkg/backports/ubuntu12.04/debian/control56
l---------debianpkg/backports/ubuntu12.04/debian/frr.install1
l---------debianpkg/backports/ubuntu12.04/debian/frr.postinst1
l---------debianpkg/backports/ubuntu12.04/debian/frr.postrm1
-rwxr-xr-xdebianpkg/backports/ubuntu12.04/debian/rules162
-rw-r--r--debianpkg/backports/ubuntu12.04/debian/source/format1
-rw-r--r--debianpkg/backports/ubuntu12.04/exclude0
-rw-r--r--debianpkg/backports/ubuntu12.04/versionext1
-rw-r--r--debianpkg/backports/ubuntu14.04/debian/frr.install1
-rw-r--r--debianpkg/backports/ubuntu14.04/debian/frr.postinst38
-rw-r--r--debianpkg/backports/ubuntu14.04/debian/frr.postrm14
-rwxr-xr-xdebianpkg/backports/ubuntu14.04/debian/rules2
-rwxr-xr-xdebianpkg/rules2
-rw-r--r--debianpkg/subdir.am10
-rw-r--r--doc/developer/building-frr-for-alpine.rst1
-rw-r--r--doc/developer/building-frr-for-ubuntu1204.rst1
-rw-r--r--doc/developer/building-frr-for-ubuntu1404.rst1
-rw-r--r--doc/developer/building-frr-for-ubuntu1604.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst2
-rw-r--r--doc/user/rpki.rst8
-rw-r--r--doc/user/setup.rst2
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/northbound.c5
-rw-r--r--lib/northbound.h3
-rw-r--r--lib/northbound_cli.c121
-rw-r--r--lib/northbound_cli.h4
-rw-r--r--lib/vty.c8
-rw-r--r--lib/vty.h4
-rw-r--r--redhat/daemons2
-rwxr-xr-xredhat/frr.init42
-rw-r--r--redhat/frr.spec.in3
-rw-r--r--staticd/static_vty.c8
-rw-r--r--tests/bgpd/test_peer_attr.c4
-rw-r--r--tests/helpers/c/main.c2
-rw-r--r--tests/lib/cli/common_cli.c3
-rw-r--r--tests/lib/cli/test_cli.refout.in2
-rw-r--r--tests/lib/cli/test_commands.c2
-rw-r--r--tests/lib/northbound/test_oper_data.c2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py13
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py9
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py12
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py6
-rw-r--r--tests/topotests/lib/bgprib.py11
-rw-r--r--tests/topotests/lib/topotest.py1
-rw-r--r--tools/.gitignore3
-rw-r--r--tools/etc/default/frr10
-rw-r--r--tools/etc/frr/daemons44
-rw-r--r--tools/etc/frr/daemons.conf34
-rwxr-xr-xtools/frr.in60
-rw-r--r--tools/frr.service7
-rw-r--r--tools/frrcommon.sh.in317
-rw-r--r--tools/frrinit.sh.in90
-rw-r--r--tools/subdir.am4
-rw-r--r--tools/watchfrr.sh.in33
-rw-r--r--vtysh/vtysh.c59
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--vtysh/vtysh_main.c2
-rw-r--r--watchfrr/watchfrr.c77
-rw-r--r--watchfrr/watchfrr.h4
-rw-r--r--watchfrr/watchfrr_vty.c11
-rw-r--r--zebra/zebra_vty.c7
75 files changed, 916 insertions, 517 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 42896c21a5..969b85f524 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
-source="$pkgname-$pkgver.tar.gz docker-start daemons daemons.conf"
+source="$pkgname-$pkgver.tar.gz docker-start daemons"
builddir="$srcdir"/$pkgname-$pkgver
@@ -62,7 +62,6 @@ package() {
install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
- install -Dm644 "$srcdir"/daemons.conf "$pkgdir"$_sysconfdir
install -d "$pkgdir"/etc/init.d
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
}
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 5b2cb57921..208a2947ef 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -154,7 +154,7 @@ int bgp_adj_out_lookup(struct peer *peer, struct bgp_node *rn,
safi_t safi;
int addpath_capable;
- for (adj = rn->adj_out; adj; adj = adj->next)
+ RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out)
SUBGRP_FOREACH_PEER (adj->subgroup, paf)
if (paf->peer == peer) {
afi = SUBGRP_AFI(adj->subgroup);
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index 1912aec1bf..9aa5a0eaff 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -67,9 +67,8 @@ struct bgp_advertise {
/* BGP adjacency out. */
struct bgp_adj_out {
- /* Lined list pointer. */
- struct bgp_adj_out *next;
- struct bgp_adj_out *prev;
+ /* RB Tree of adjacency entries */
+ RB_ENTRY(bgp_adj_out) adj_entry;
/* Advertised subgroup. */
struct update_subgroup *subgroup;
@@ -89,6 +88,10 @@ struct bgp_adj_out {
struct bgp_advertise *adv;
};
+RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
+RB_PROTOTYPE(bgp_adj_out_rb, bgp_adj_out, adj_entry,
+ bgp_adj_out_compare);
+
/* BGP adjacency in. */
struct bgp_adj_in {
/* Linked list pointer. */
@@ -134,8 +137,6 @@ struct bgp_synchronize {
#define BGP_ADJ_IN_ADD(N, A) BGP_PATH_INFO_ADD(N, A, adj_in)
#define BGP_ADJ_IN_DEL(N, A) BGP_PATH_INFO_DEL(N, A, adj_in)
-#define BGP_ADJ_OUT_ADD(N, A) BGP_PATH_INFO_ADD(N, A, adj_out)
-#define BGP_ADJ_OUT_DEL(N, A) BGP_PATH_INFO_DEL(N, A, adj_out)
#define BGP_ADV_FIFO_ADD(F, N) \
do { \
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index baf2c1e029..d4204126e1 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -578,7 +578,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
return bpi;
}
- new = info_make(bpi_ultimate->type, BGP_ROUTE_IMPORTED, 0,
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
bgp->peer_self, new_attr, bn);
if (nexthop_self_flag)
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 74e4276c06..8cefb3ff39 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -10560,7 +10560,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
output_count++;
}
} else if (type == bgp_show_adj_route_advertised) {
- for (adj = rn->adj_out; adj; adj = adj->next)
+ RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out)
SUBGRP_FOREACH_PEER (adj->subgroup, paf) {
if (paf->peer != peer || !adj->attr)
continue;
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 728eeaa3a9..0321412263 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -67,6 +67,8 @@ static struct route_node *bgp_node_create(route_table_delegate_t *delegate,
{
struct bgp_node *node;
node = XCALLOC(MTYPE_BGP_NODE, sizeof(struct bgp_node));
+
+ RB_INIT(bgp_adj_out_rb, &node->adj_out);
return bgp_node_to_rnode(node);
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index c267b4fe8a..4795ab741c 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -26,6 +26,7 @@
#include "queue.h"
#include "linklist.h"
#include "bgpd.h"
+#include "bgp_advertise.h"
struct bgp_table {
/* table belongs to this instance */
@@ -52,7 +53,7 @@ struct bgp_node {
*/
ROUTE_NODE_FIELDS
- struct bgp_adj_out *adj_out;
+ struct bgp_adj_out_rb adj_out;
struct bgp_adj_in *adj_in;
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 7196bbbf12..cefbf72b58 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -55,12 +55,24 @@
/********************
* PRIVATE FUNCTIONS
********************/
+static int bgp_adj_out_compare(const struct bgp_adj_out *o1,
+ const struct bgp_adj_out *o2)
+{
+ if (o1->subgroup < o2->subgroup)
+ return -1;
+
+ if (o1->subgroup > o2->subgroup)
+ return 1;
+
+ return 0;
+}
+RB_GENERATE(bgp_adj_out_rb, bgp_adj_out, adj_entry, bgp_adj_out_compare);
static inline struct bgp_adj_out *adj_lookup(struct bgp_node *rn,
struct update_subgroup *subgrp,
uint32_t addpath_tx_id)
{
- struct bgp_adj_out *adj;
+ struct bgp_adj_out *adj, lookup;
struct peer *peer;
afi_t afi;
safi_t safi;
@@ -76,19 +88,16 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_node *rn,
/* update-groups that do not support addpath will pass 0 for
* addpath_tx_id so do not both matching against it */
- for (adj = rn->adj_out; adj; adj = adj->next) {
- if (adj->subgroup == subgrp) {
- if (addpath_capable) {
- if (adj->addpath_tx_id == addpath_tx_id) {
- break;
- }
- } else {
- break;
- }
- }
+ lookup.subgroup = subgrp;
+ adj = RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup);
+ if (adj) {
+ if (addpath_capable) {
+ if (adj->addpath_tx_id == addpath_tx_id)
+ return adj;
+ } else
+ return adj;
}
-
- return adj;
+ return NULL;
}
static void adj_free(struct bgp_adj_out *adj)
@@ -110,8 +119,7 @@ static void subgrp_withdraw_stale_addpath(struct updwalk_context *ctx,
/* Look through all of the paths we have advertised for this rn and send
* a withdraw for the ones that are no longer present */
- for (adj = ctx->rn->adj_out; adj; adj = adj_next) {
- adj_next = adj->next;
+ RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->rn->adj_out, adj_next) {
if (adj->subgroup == subgrp) {
for (pi = ctx->rn->info; pi; pi = pi->next) {
@@ -204,10 +212,9 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
/* Find the addpath_tx_id of the path we
* had advertised and
* send a withdraw */
- for (adj = ctx->rn->adj_out; adj;
- adj = adj_next) {
- adj_next = adj->next;
-
+ RB_FOREACH_SAFE (adj, bgp_adj_out_rb,
+ &ctx->rn->adj_out,
+ adj_next) {
if (adj->subgroup == subgrp) {
subgroup_process_announce_selected(
subgrp, NULL,
@@ -243,7 +250,7 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
output_count = 0;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
- for (adj = rn->adj_out; adj; adj = adj->next)
+ RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out)
if (adj->subgroup == subgrp) {
if (header1) {
vty_out(vty,
@@ -394,7 +401,7 @@ struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp,
adj = XCALLOC(MTYPE_BGP_ADJ_OUT, sizeof(struct bgp_adj_out));
adj->subgroup = subgrp;
if (rn) {
- BGP_ADJ_OUT_ADD(rn, adj);
+ RB_INSERT(bgp_adj_out_rb, &rn->adj_out, adj);
bgp_lock_node(rn);
adj->rn = rn;
}
@@ -551,7 +558,7 @@ void bgp_adj_out_unset_subgroup(struct bgp_node *rn,
subgroup_trigger_write(subgrp);
} else {
/* Remove myself from adjacency. */
- BGP_ADJ_OUT_DEL(rn, adj);
+ RB_REMOVE(bgp_adj_out_rb, &rn->adj_out, adj);
/* Free allocated information. */
adj_free(adj);
@@ -572,7 +579,7 @@ void bgp_adj_out_remove_subgroup(struct bgp_node *rn, struct bgp_adj_out *adj,
if (adj->adv)
bgp_advertise_clean_subgroup(subgrp, adj);
- BGP_ADJ_OUT_DEL(rn, adj);
+ RB_REMOVE(bgp_adj_out_rb, &rn->adj_out, adj);
adj_free(adj);
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 06caebe567..f83b146175 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9722,7 +9722,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_string_add(
json_nxt,
print_store,
- "received");
+ "recieved"); /* misspelled for compatibility */
}
}
json_object_object_add(
diff --git a/configure.ac b/configure.ac
index 09d57ab0f2..0d75f7d319 100755
--- a/configure.ac
+++ b/configure.ac
@@ -13,7 +13,7 @@ AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
AC_SUBST([PACKAGE_FULLNAME])
-CONFIG_ARGS="$ac_configure_args"
+CONFIG_ARGS="`echo $ac_configure_args | sed -e \"s% '[[A-Z]]*FLAGS=[[^']]\+'%%g\"`"
AC_SUBST([CONFIG_ARGS])
AC_CONFIG_SRCDIR([lib/zebra.h])
@@ -2180,6 +2180,9 @@ AC_CONFIG_FILES([
AC_CONFIG_FILES([vtysh/extract.pl], [chmod +x vtysh/extract.pl])
AC_CONFIG_FILES([tools/frr], [chmod +x tools/frr])
+AC_CONFIG_FILES([tools/watchfrr.sh], [chmod +x tools/watchfrr.sh])
+AC_CONFIG_FILES([tools/frrinit.sh], [chmod +x tools/frrinit.sh])
+AC_CONFIG_FILES([tools/frrcommon.sh])
AC_CONFIG_COMMANDS([lib/route_types.h], [
dst="${ac_abs_top_builddir}/lib/route_types.h"
diff --git a/debianpkg/README.Debian b/debianpkg/README.Debian
index 1b04803366..cd7be5e801 100644
--- a/debianpkg/README.Debian
+++ b/debianpkg/README.Debian
@@ -83,7 +83,7 @@ into the kernel.
=====================================================================
If this message occurs the receive buffer should be increased by adding the
-following to /etc/sysctl.conf and "--nl-bufsize" to /etc/frr/daemons.conf.
+following to /etc/sysctl.conf and "--nl-bufsize" to /etc/frr/daemons.
> net.core.rmem_default = 262144
> net.core.rmem_max = 262144
See message #4525 from 2005-05-09 in the quagga-users mailing list.
diff --git a/debianpkg/backports/ubuntu12.04/debian/control b/debianpkg/backports/ubuntu12.04/debian/control
deleted file mode 100644
index 9bae348840..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/control
+++ /dev/null
@@ -1,56 +0,0 @@
-Source: frr
-Section: net
-Priority: optional
-Maintainer: Nobody <nobody@frrouting.org>
-Uploaders: Nobody <nobody@frrouting.org>
-XSBC-Original-Maintainer: <maintainers@frrouting.org>
-Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson0, libjson0-dev, pkg-config, python (>= 2.7), python-ipaddr
-Standards-Version: 3.9.6
-Homepage: http://www.frrouting.org/
-XS-Testsuite: autopkgtest
-
-Package: frr
-Architecture: any
-Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), ${misc:Depends}
-Pre-Depends: adduser
-Conflicts: zebra, zebra-pj, quagga
-Replaces: zebra, zebra-pj
-Suggests: snmpd
-Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga
- FRR is free software which manages TCP/IP based routing protocols.
- It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng,
- PIM and LDP as well as the IPv6 versions of these.
- .
- FRR is a fork of Quagga with an open community model. The main git
- lives on https://github.com/frrouting/frr.git
-
-Package: frr-dbg
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version})
-Priority: extra
-Section: debug
-Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols)
- This package provides debugging symbols for all binary packages built
- from frr source package. It's highly recommended to have this package
- installed before reporting any FRR crashes to either FRR developers or
- Debian package maintainers.
-
-Package: frr-doc
-Section: net
-Architecture: all
-Depends: ${misc:Depends}
-Suggests: frr
-Description: documentation files for FRR
- This package includes info files for frr, a free software which manages
- TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3,
- IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these.
-
-Package: frr-pythontools
-Section: net
-Architecture: all
-Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddr
-Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools)
- This package includes info files for frr, a free software which manages
- TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3,
- IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these.
-
diff --git a/debianpkg/backports/ubuntu12.04/debian/frr.install b/debianpkg/backports/ubuntu12.04/debian/frr.install
deleted file mode 120000
index 83ecca5958..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/frr.install
+++ /dev/null
@@ -1 +0,0 @@
-../../ubuntu14.04/debian/frr.install \ No newline at end of file
diff --git a/debianpkg/backports/ubuntu12.04/debian/frr.postinst b/debianpkg/backports/ubuntu12.04/debian/frr.postinst
deleted file mode 120000
index eb98053c7b..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/frr.postinst
+++ /dev/null
@@ -1 +0,0 @@
-../../ubuntu14.04/debian/frr.postinst \ No newline at end of file
diff --git a/debianpkg/backports/ubuntu12.04/debian/frr.postrm b/debianpkg/backports/ubuntu12.04/debian/frr.postrm
deleted file mode 120000
index 4f4380872f..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/frr.postrm
+++ /dev/null
@@ -1 +0,0 @@
-../../ubuntu14.04/debian/frr.postrm \ No newline at end of file
diff --git a/debianpkg/backports/ubuntu12.04/debian/rules b/debianpkg/backports/ubuntu12.04/debian/rules
deleted file mode 100755
index 7495db89cb..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/rules
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/make -f
-
-# FRRouting Configuration options
-######################################
-#
-# WANT_xxxx --> Set to 1 for enable, 0 for disable
-# The following are the defaults. They can be overridden by setting a
-# env variable to a different value
-
-WANT_LDP ?= 1
-WANT_PIM ?= 1
-WANT_OSPFAPI ?= 1
-WANT_BGP_VNC ?= 1
-WANT_CUMULUS_MODE ?= 0
-WANT_MULTIPATH ?= 1
-WANT_SNMP ?= 0
-
-# NOTES:
-#
-# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
-# Please be aware that 0 is NOT disabled, but treated as unlimited
-
-MULTIPATH ?= 256
-
-# Set the following to the value required (or leave alone for the default below)
-# WANT_FRR_USER is used for the username and groupname of the FRR user account
-
-WANT_FRR_USER ?= frr
-WANT_FRR_VTY_GROUP ?= frrvty
-
-# Don't build PDF docs by default
-GENERATE_PDF ?= 0
-
-#
-####################################
-
-export DH_VERBOSE=1
-export DEB_BUILD_MAINT_OPTIONS = hardening=+all
-export DH_OPTIONS=-v
-
-ifeq ($(WANT_SNMP), 1)
- USE_SNMP=--enable-snmp
- $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience")
-else
- USE_SNMP=--disable-snmp
- $(warning "DEBIAN: SNMP disabled, see README.Debian")
-endif
-
-ifeq ($(WANT_LDP), 1)
- USE_LDP=--enable-ldpd
-else
- USE_LDP=--disable-ldpd
-endif
-
-ifeq ($(WANT_PIM), 1)
- USE_PIM=--enable-pimd
-else
- USE_PIM=--disable-pimd
-endif
-
-ifeq ($(WANT_OSPFAPI), 1)
- USE_OSPFAPI=--enable-ospfapi=yes
-else
- USE_OSPFAPI=--enable-ospfapi=no
-endif
-
-ifeq ($(WANT_BGP_VNC), 1)
- USE_BGP_VNC=--enable-bgp-vnc=yes
-else
- USE_BGP_VNC=--enable-bgp-vnc=no
-endif
-
-USE_FRR_USER=--enable-user=$(WANT_FRR_USER)
-USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER)
-USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
-
-ifeq ($(WANT_MULTIPATH), 1)
- USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
-else
- USE_MULTIPATH=--disable-multipath
-endif
-
-ifeq ($(WANT_CUMULUS_MODE), 1)
- USE_CUMULUS=--enable-cumulus=yes
-else
- USE_CUMULUS=--enable-cumulus=no
-endif
-
-ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
- DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-endif
-
-ifdef DEBIAN_JOBS
-MAKEFLAGS += -j$(DEBIAN_JOBS)
-endif
-
-%:
- dh $@ --with=autoreconf --parallel --dbg-package=frr-dbg --list-missing
-
-override_dh_auto_configure:
- # Frr needs /proc to check some BSD vs Linux specific stuff.
- # Else it fails with an obscure error message pointing out that
- # IPCTL_FORWARDING is an undefined symbol which is not very helpful.
- @if ! [ -d /proc/1 ]; then \
- echo "./configure needs a mounted /proc"; \
- exit 1; \
- fi
-
- if ! [ -e config.status ]; then \
- dh_auto_configure -- \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- $(USE_SNMP) \
- $(USE_OSPFAPI) \
- $(USE_MULTIPATH) \
- $(USE_LDP) \
- --enable-fpm \
- $(USE_FRR_USER) $(USE_FRR_GROUP) \
- $(USE_FRR_VTY_GROUP) \
- --enable-configfile-mask=0640 \
- --enable-logfile-mask=0640 \
- --with-libpam \
- --enable-systemd=no \
- --enable-poll=yes \
- $(USE_CUMULUS) \
- $(USE_PIM) \
- --disable-bfdd \
- --enable-dependency-tracking \
- $(USE_BGP_VNC) \
- $(shell dpkg-buildflags --export=configure); \
- fi
-
-override_dh_auto_build:
-ifeq ($(GENERATE_PDF), 1)
- dh_auto_build -- -C doc pdf
-endif
- rm -vf doc/user/_build/texinfo/frr.info
- dh_auto_build -- -C doc info
-
-override_dh_auto_test:
-
-override_dh_auto_install:
- dh_auto_install
-
- # installed in frr-pythontools
- rm debian/tmp/usr/lib/frr/frr-reload.py
-
- # cleaning up the info dir
- rm -f debian/tmp/usr/share/info/dir*
-
- # install config files
- mkdir -p debian/tmp/etc/frr/
- perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
-
- # leftover from previously shipping SMUX client OID MIB
- mkdir -p debian/tmp/usr/share/snmp/mibs
-
- # cleaning .la files
- sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
- sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/modules/*.la
diff --git a/debianpkg/backports/ubuntu12.04/debian/source/format b/debianpkg/backports/ubuntu12.04/debian/source/format
deleted file mode 100644
index 163aaf8d82..0000000000
--- a/debianpkg/backports/ubuntu12.04/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debianpkg/backports/ubuntu12.04/exclude b/debianpkg/backports/ubuntu12.04/exclude
deleted file mode 100644
index e69de29bb2..0000000000
--- a/debianpkg/backports/ubuntu12.04/exclude
+++ /dev/null
diff --git a/debianpkg/backports/ubuntu12.04/versionext b/debianpkg/backports/ubuntu12.04/versionext
deleted file mode 100644
index 159e2e4160..0000000000
--- a/debianpkg/backports/ubuntu12.04/versionext
+++ /dev/null
@@ -1 +0,0 @@
--1~ubuntu12.04+1
diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.install b/debianpkg/backports/ubuntu14.04/debian/frr.install
index 199d264f1a..7fb81c44a0 100644
--- a/debianpkg/backports/ubuntu14.04/debian/frr.install
+++ b/debianpkg/backports/ubuntu14.04/debian/frr.install
@@ -3,7 +3,6 @@ usr/bin/vtysh
usr/bin/mtracebis
usr/include/frr/
usr/lib/
-tools/frr etc/init.d/
usr/share/doc/frr/
usr/share/snmp/mibs/
usr/share/yang/
diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.postinst b/debianpkg/backports/ubuntu14.04/debian/frr.postinst
deleted file mode 100644
index 5a14e510cd..0000000000
--- a/debianpkg/backports/ubuntu14.04/debian/frr.postinst
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash -e
-
-######################
-PASSWDFILE=/etc/passwd
-GROUPFILE=/etc/group
-
-frruid=`egrep "^frr:" $PASSWDFILE | awk -F ":" '{ print $3 }'`
-frrgid=`egrep "^frr:" $GROUPFILE | awk -F ":" '{ print $3 }'`
-frrvtygid=`egrep "^frrvty:" $GROUPFILE | awk -F ":" '{ print $3 }'`
-
-[ -n ${frruid} ] || (echo "No uid for frr in ${PASSWDFILE}" && /bin/false)
-[ -n ${frrgid} ] || (echo "No gid for frr in ${GROUPFILE}" && /bin/false)
-[ -n ${frrVTYgid} ] || (echo "No gid for frrvty in ${GROUPFILE}" && /bin/false)
-
-chown -R ${frruid}:${frrgid} /etc/frr
-touch /etc/frr/vtysh.conf
-chgrp ${frrvtygid} /etc/frr/vtysh*
-chmod 644 /etc/frr/*
-
-ENVIRONMENTFILE=/etc/environment
-if ! egrep --quiet '^VTYSH_PAGER=' ${ENVIRONMENTFILE}; then
- echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE}
-fi
-##################################################
-
-if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
-${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"}
-
-# This is most likely due to the answer "no" to the "really stop the server"
-# question in the prerm script.
-if [ "$1" = "abort-upgrade" ]; then
- exit 0
-fi
-
-update-rc.d frr defaults > /dev/null
-
-#DEBHELPER#
-
diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.postrm b/debianpkg/backports/ubuntu14.04/debian/frr.postrm
deleted file mode 100644
index 48c23321f7..0000000000
--- a/debianpkg/backports/ubuntu14.04/debian/frr.postrm
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash -e
-
-if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
-${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"}
-# set -u not because of debhelper
-
-update-rc.d -f frr remove >> /dev/null
-
-if [ "$1" = "purge" ]; then
- rm -rf /etc/frr /var/run/frr /var/log/frr
- userdel frr >/dev/null 2>&1 || true
-fi
-
-#DEBHELPER#
diff --git a/debianpkg/backports/ubuntu14.04/debian/rules b/debianpkg/backports/ubuntu14.04/debian/rules
index 291233c147..21b442d85a 100755
--- a/debianpkg/backports/ubuntu14.04/debian/rules
+++ b/debianpkg/backports/ubuntu14.04/debian/rules
@@ -178,6 +178,8 @@ override_dh_auto_test:
override_dh_auto_install:
dh_auto_install
+ cp tools/frrinit.sh debian/frr.init
+
# installed in frr-pythontools
rm debian/tmp/usr/lib/frr/frr-reload.py
diff --git a/debianpkg/rules b/debianpkg/rules
index 7cdb8fbaf7..12d6c3545c 100755
--- a/debianpkg/rules
+++ b/debianpkg/rules
@@ -171,7 +171,7 @@ override_dh_systemd_enable:
# backports
SRCPKG = frr
-KNOWN_BACKPORTS = debian8 debian9 ubuntu12.04 ubuntu14.04 ubuntu16.04 ubuntu17.10 ubuntu18.04
+KNOWN_BACKPORTS = debian8 debian9 ubuntu14.04 ubuntu16.04 ubuntu17.10 ubuntu18.04
DEBIAN_VERSION := $(shell dh_testdir && \
dpkg-parsechangelog -c1 < debian/changelog | \
sed -rn 's/^Version: ?//p')
diff --git a/debianpkg/subdir.am b/debianpkg/subdir.am
index b6251962b7..af17e4642a 100644
--- a/debianpkg/subdir.am
+++ b/debianpkg/subdir.am
@@ -23,18 +23,8 @@ EXTRA_DIST += \
debianpkg/backports/debian9/debian/source/format \
debianpkg/backports/debian9/exclude \
debianpkg/backports/debian9/versionext \
- debianpkg/backports/ubuntu12.04/debian/control \
- debianpkg/backports/ubuntu12.04/debian/frr.install \
- debianpkg/backports/ubuntu12.04/debian/frr.postinst \
- debianpkg/backports/ubuntu12.04/debian/frr.postrm \
- debianpkg/backports/ubuntu12.04/debian/rules \
- debianpkg/backports/ubuntu12.04/debian/source/format \
- debianpkg/backports/ubuntu12.04/exclude \
- debianpkg/backports/ubuntu12.04/versionext \
debianpkg/backports/ubuntu14.04/debian/control \
debianpkg/backports/ubuntu14.04/debian/frr.install \
- debianpkg/backports/ubuntu14.04/debian/frr.postinst \
- debianpkg/backports/ubuntu14.04/debian/frr.postrm \
debianpkg/backports/ubuntu14.04/debian/rules \
debianpkg/backports/ubuntu14.04/debian/source/format \
debianpkg/backports/ubuntu14.04/exclude \
diff --git a/doc/developer/building-frr-for-alpine.rst b/doc/developer/building-frr-for-alpine.rst
index d303784d4e..f88fc7bfdc 100644
--- a/doc/developer/building-frr-for-alpine.rst
+++ b/doc/developer/building-frr-for-alpine.rst
@@ -85,7 +85,6 @@ startup. To configure by hand:
docker exec -it frr /bin/sh
vi /etc/frr/daemons
- vi /etc/frr/daemons.conf
cp /etc/frr/zebra.conf.sample /etc/frr/zebra.conf
vi /etc/frr/zebra.conf
/etc/init.d/frr start
diff --git a/doc/developer/building-frr-for-ubuntu1204.rst b/doc/developer/building-frr-for-ubuntu1204.rst
index 9b2394f018..a2d58e2258 100644
--- a/doc/developer/building-frr-for-ubuntu1204.rst
+++ b/doc/developer/building-frr-for-ubuntu1204.rst
@@ -158,7 +158,6 @@ Install the init.d service
sudo install -m 755 tools/frr /etc/init.d/frr
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
Enable daemons
diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst
index 81ca970469..7952cd682a 100644
--- a/doc/developer/building-frr-for-ubuntu1404.rst
+++ b/doc/developer/building-frr-for-ubuntu1404.rst
@@ -112,7 +112,6 @@ Install the init.d service
sudo install -m 755 tools/frr /etc/init.d/frr
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
Enable daemons
diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst
index 9830b24dfc..f5329fef2c 100644
--- a/doc/developer/building-frr-for-ubuntu1604.rst
+++ b/doc/developer/building-frr-for-ubuntu1604.rst
@@ -139,9 +139,7 @@ Install the systemd service (if rebooted from last step, change directory back t
::
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/default/frr /etc/default/frr
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst
index e69ded8f73..110bc6a0ee 100644
--- a/doc/developer/building-frr-for-ubuntu1804.rst
+++ b/doc/developer/building-frr-for-ubuntu1804.rst
@@ -203,9 +203,7 @@ Install the systemd service
::
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/default/frr /etc/default/frr
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst
index f48ff2e6ba..295a26fda9 100644
--- a/doc/user/rpki.rst
+++ b/doc/user/rpki.rst
@@ -67,17 +67,17 @@ Enabling RPKI
to configure at least one reachable cache server. See section
:ref:`configuring-rpki-rtr-cache-servers` for configuring a cache server.
-.. index:: RPKI and daemons.conf
+.. index:: RPKI and daemons
When first installing FRR with RPKI support from the pre-packaged binaries.
Remember to add ``-M rpki`` to the variable ``bgpd_options`` in
-:file:`/etc/frr/daemons.conf` , like so::
+:file:`/etc/frr/daemons` , like so::
- bgpd_options=" --daemon -A 127.0.0.1 -M rpki"
+ bgpd_options=" -A 127.0.0.1 -M rpki"
instead of the default setting::
- bgpd_options=" --daemon -A 127.0.0.1"
+ bgpd_options=" -A 127.0.0.1"
Otherwise you will encounter an error when trying to enter RPKI
configuration mode due to the ``rpki`` module not being loaded when the BGP
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index 8a76a61e78..3a09c50309 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -41,7 +41,7 @@ Daemons Configuration File
--------------------------
There is another file that controls the default options passed to daemons when
starting FRR as a service. This file is located in your configuration
-directory, usually at :file:`/etc/frr/daemons.conf`.
+directory, usually at :file:`/etc/frr/daemons`.
This file has several parts. Here is an example:
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 6ebe24eef7..9119b04992 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -653,7 +653,7 @@ struct thread_master *frr_init(void)
lib_error_init();
yang_init();
- nb_init(di->yang_modules, di->n_yang_modules);
+ nb_init(master, di->yang_modules, di->n_yang_modules);
return master;
}
diff --git a/lib/northbound.c b/lib/northbound.c
index 490b3abe57..8503f87d60 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -1539,7 +1539,8 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
}
}
-void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules)
+void nb_init(struct thread_master *tm,
+ const struct frr_yang_module_info *modules[], size_t nmodules)
{
unsigned int errors = 0;
@@ -1574,7 +1575,7 @@ void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules)
running_config = nb_config_new(NULL);
/* Initialize the northbound CLI. */
- nb_cli_init();
+ nb_cli_init(tm);
}
void nb_terminate(void)
diff --git a/lib/northbound.h b/lib/northbound.h
index e26a2f8617..c8e8d75701 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -20,6 +20,7 @@
#ifndef _FRR_NORTHBOUND_H_
#define _FRR_NORTHBOUND_H_
+#include "thread.h"
#include "hook.h"
#include "linklist.h"
#include "openbsd-tree.h"
@@ -825,7 +826,7 @@ extern const char *nb_client_name(enum nb_client client);
* nmodules
* Size of the modules array.
*/
-extern void nb_init(const struct frr_yang_module_info *modules[],
+extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info *modules[],
size_t nmodules);
/*
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 2cacc6b1dc..d685a4e7c2 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -36,6 +36,7 @@
int debug_northbound;
struct nb_config *vty_shared_candidate_config;
+static struct thread_master *master;
static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx)
{
@@ -213,16 +214,80 @@ int nb_cli_rpc(const char *xpath, struct list *input, struct list *output)
}
}
-static int nb_cli_commit(struct vty *vty, bool force, char *comment)
+void nb_cli_confirmed_commit_clean(struct vty *vty)
+{
+ THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
+ nb_config_free(vty->confirmed_commit_rollback);
+ vty->confirmed_commit_rollback = NULL;
+}
+
+int nb_cli_confirmed_commit_rollback(struct vty *vty)
+{
+ uint32_t transaction_id;
+ int ret;
+
+ /* Perform the rollback. */
+ ret = nb_candidate_commit(
+ vty->confirmed_commit_rollback, NB_CLIENT_CLI, true,
+ "Rollback to previous configuration - confirmed commit has timed out",
+ &transaction_id);
+ if (ret == NB_OK)
+ vty_out(vty,
+ "Rollback performed successfully (Transaction ID #%u).\n",
+ transaction_id);
+ else
+ vty_out(vty, "Failed to rollback to previous configuration.\n");
+
+ return ret;
+}
+
+static int nb_cli_confirmed_commit_timeout(struct thread *thread)
+{
+ struct vty *vty = THREAD_ARG(thread);
+
+ /* XXX: broadcast this message to all logged-in users? */
+ vty_out(vty,
+ "\nConfirmed commit has timed out, rolling back to previous configuration.\n\n");
+
+ nb_cli_confirmed_commit_rollback(vty);
+ nb_cli_confirmed_commit_clean(vty);
+
+ return 0;
+}
+
+static int nb_cli_commit(struct vty *vty, bool force,
+ unsigned int confirmed_timeout, char *comment)
{
uint32_t transaction_id;
int ret;
+ /* Check if there's a pending confirmed commit. */
+ if (vty->t_confirmed_commit_timeout) {
+ if (confirmed_timeout) {
+ /* Reset timeout if "commit confirmed" is used again. */
+ vty_out(vty,
+ "%% Resetting confirmed-commit timeout to %u minute(s)\n\n",
+ confirmed_timeout);
+
+ THREAD_TIMER_OFF(vty->t_confirmed_commit_timeout);
+ thread_add_timer(master,
+ nb_cli_confirmed_commit_timeout, vty,
+ confirmed_timeout * 60,
+ &vty->t_confirmed_commit_timeout);
+ } else {
+ /* Accept commit confirmation. */
+ vty_out(vty, "%% Commit complete.\n\n");
+ nb_cli_confirmed_commit_clean(vty);
+ }
+ return CMD_SUCCESS;
+ }
+
if (vty_exclusive_lock != NULL && vty_exclusive_lock != vty) {
vty_out(vty, "%% Configuration is locked by another VTY.\n\n");
return CMD_WARNING;
}
+ /* "force" parameter. */
if (!force && nb_candidate_needs_update(vty->candidate_config)) {
vty_out(vty,
"%% Candidate configuration needs to be updated before commit.\n\n");
@@ -231,6 +296,16 @@ static int nb_cli_commit(struct vty *vty, bool force, char *comment)
return CMD_WARNING;
}
+ /* "confirm" parameter. */
+ if (confirmed_timeout) {
+ vty->confirmed_commit_rollback = nb_config_dup(running_config);
+
+ vty->t_confirmed_commit_timeout = NULL;
+ thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
+ confirmed_timeout * 60,
+ &vty->t_confirmed_commit_timeout);
+ }
+
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, true,
comment, &transaction_id);
@@ -534,18 +609,22 @@ DEFUN (config_private,
DEFPY (config_commit,
config_commit_cmd,
- "commit [force$force]",
+ "commit [{force$force|confirmed (1-60)}]",
"Commit changes into the running configuration\n"
- "Force commit even if the candidate is outdated\n")
+ "Force commit even if the candidate is outdated\n"
+ "Rollback this commit unless there is a confirming commit\n"
+ "Timeout in minutes for the commit to be confirmed\n")
{
- return nb_cli_commit(vty, !!force, NULL);
+ return nb_cli_commit(vty, !!force, confirmed, NULL);
}
DEFPY (config_commit_comment,
config_commit_comment_cmd,
- "commit [force$force] comment LINE...",
+ "commit [{force$force|confirmed (1-60)}] comment LINE...",
"Commit changes into the running configuration\n"
"Force commit even if the candidate is outdated\n"
+ "Rollback this commit unless there is a confirming commit\n"
+ "Timeout in minutes for the commit to be confirmed\n"
"Assign a comment to this commit\n"
"Comment for this commit (Max 80 characters)\n")
{
@@ -555,7 +634,7 @@ DEFPY (config_commit_comment,
argv_find(argv, argc, "LINE", &idx);
comment = argv_concat(argv, argc, idx);
- ret = nb_cli_commit(vty, !!force, comment);
+ ret = nb_cli_commit(vty, !!force, confirmed, comment);
XFREE(MTYPE_TMP, comment);
return ret;
@@ -754,6 +833,30 @@ DEFPY (show_config_candidate,
return CMD_SUCCESS;
}
+DEFPY (show_config_candidate_section,
+ show_config_candidate_section_cmd,
+ "show",
+ SHOW_STR)
+{
+ struct lyd_node *dnode;
+
+ /* Top-level configuration node, display everything. */
+ if (vty->xpath_index == 0)
+ return nb_cli_show_config(vty, vty->candidate_config,
+ NB_CFG_FMT_CMDS, NULL, false);
+
+ /* Display only the current section of the candidate configuration. */
+ dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (!dnode)
+ /* Shouldn't happen. */
+ return CMD_WARNING;
+
+ nb_cli_show_dnode_cmds(vty, dnode, 0);
+ vty_out(vty, "!\n");
+
+ return CMD_SUCCESS;
+}
+
DEFPY (show_config_compare,
show_config_compare_cmd,
"show configuration compare\
@@ -1468,6 +1571,8 @@ static struct cmd_node nb_debug_node = {NORTHBOUND_DEBUG_NODE, "", 1};
void nb_cli_install_default(int node)
{
+ install_element(node, &show_config_candidate_section_cmd);
+
if (frr_get_cli_mode() != FRR_CLI_TRANSACTIONAL)
return;
@@ -1517,8 +1622,10 @@ static const struct cmd_variable_handler yang_var_handlers[] = {
.completions = yang_translator_autocomplete},
{.completions = NULL}};
-void nb_cli_init(void)
+void nb_cli_init(struct thread_master *tm)
{
+ master = tm;
+
/* Initialize the shared candidate configuration. */
vty_shared_candidate_config = nb_config_new(NULL);
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index febcbd86f1..362a4bc325 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -105,8 +105,10 @@ extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
/* Prototypes of internal functions. */
+extern void nb_cli_confirmed_commit_clean(struct vty *vty);
+extern int nb_cli_confirmed_commit_rollback(struct vty *vty);
extern void nb_cli_install_default(int node);
-extern void nb_cli_init(void);
+extern void nb_cli_init(struct thread_master *tm);
extern void nb_cli_terminate(void);
#endif /* _FRR_NORTHBOUND_CLI_H_ */
diff --git a/lib/vty.c b/lib/vty.c
index 9908ada7f0..085cbac742 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2714,6 +2714,14 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
void vty_config_exit(struct vty *vty)
{
+ /* Check if there's a pending confirmed commit. */
+ if (vty->t_confirmed_commit_timeout) {
+ vty_out(vty,
+ "WARNING: exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n");
+ nb_cli_confirmed_commit_rollback(vty);
+ nb_cli_confirmed_commit_clean(vty);
+ }
+
vty_config_exclusive_unlock(vty);
if (vty->candidate_config) {
diff --git a/lib/vty.h b/lib/vty.h
index ae6c4bae96..ad4dc273b9 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -126,6 +126,10 @@ struct vty {
/* Base candidate configuration. */
struct nb_config *candidate_config_base;
+ /* Confirmed-commit timeout and rollback configuration. */
+ struct thread *t_confirmed_commit_timeout;
+ struct nb_config *confirmed_commit_rollback;
+
/* qobj object ID (replacement for "index") */
uint64_t qobj_index;
diff --git a/redhat/daemons b/redhat/daemons
index c301a1c23a..7f3ff36df9 100644
--- a/redhat/daemons
+++ b/redhat/daemons
@@ -35,7 +35,7 @@
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
watchfrr_enable=yes
-watchfrr_options=("-b_" "-r/usr/lib/frr/frr_restart_%s" "-s/usr/lib/frr/frr_start_%s" "-k/usr/lib/frr/frr_stop_%s")
+watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'"
#
zebra=no
bgpd=no
diff --git a/redhat/frr.init b/redhat/frr.init
index 47a92eed32..b59656adcd 100755
--- a/redhat/frr.init
+++ b/redhat/frr.init
@@ -107,22 +107,28 @@ check_daemon()
# The Frr daemons creates the pidfile when starting.
start()
{
+ local dmn inst
+ dmn="$1"
+ inst="$2"
+
ulimit -n $MAX_FDS > /dev/null 2> /dev/null
- if [ "$1" = "watchfrr" ]; then
+ if [ "$dmn" = "watchfrr" ]; then
# We may need to restart watchfrr if new daemons are added and/or
# removed
- if started "$1" ; then
+ if started "$dmn" ; then
stop watchfrr
else
# Echo only once. watchfrr is printed in the stop above
- echo -n " $1"
+ echo -n " $dmn"
fi
if [ -e /var/run/frr/watchfrr.started ] ; then
rm /var/run/frr/watchfrr.started
fi
- daemon --pidfile=`pidfile $1` "$D_PATH/$1" -d "${watchfrr_options[@]}"
+ # redhat /etc/init.d/functions daemon() re-expands args :(
+ # eval "set - $watchfrr_options"
+ daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options"
RETVAL=$?
[ $RETVAL -ne 0 ] && break
for i in `seq 1 10`;
@@ -135,25 +141,25 @@ start()
fi
done
RETVAL=1
- elif [ -n "$2" ]; then
- echo -n " $1-$2"
- if ! check_daemon $1 $2 ; then
+ elif [ -n "$inst" ]; then
+ echo -n " $dmn-$inst"
+ if ! check_daemon $dmn $inst ; then
echo -n " (binary does not exist)"
return;
fi
- daemon --pidfile=`pidfile $1-$2` "$D_PATH/$1" -d `eval echo "$""$1""_options"` -n "$2"
+ daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst"
RETVAL=$?
else
- echo -n " $1 "
- if ! check_daemon $1; then
+ echo -n " $dmn "
+ if ! check_daemon $dmn; then
echo " (binary does not exist)"
return;
fi
- daemon --pidfile=`pidfile $1` "$D_PATH/$1" -d `eval echo "$""$1""_options"`
+ daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"`
RETVAL=$?
fi
echo
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$1
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn
return $RETVAL
}
@@ -223,11 +229,9 @@ start_watchfrr()
fi
# Check variable type
- if ! declare -p watchfrr_options | grep -q '^declare \-a'; then
- echo
- echo "ERROR: The variable watchfrr_options from /etc/frr/daemons must be a BASH array!"
- echo "ERROR: Please convert config file and restart!"
- exit 1
+ if declare -p watchfrr_options | grep -q '^declare \-a'; then
+ # old array support
+ watchfrr_options="${watchfrr_options[@]}"
fi
# Which daemons have been started?
@@ -241,13 +245,13 @@ start_watchfrr()
eval "inst_disable=\${${daemon_name}_${inst}}"
if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
if check_daemon $daemon_name $inst; then
- watchfrr_options+=("${daemon_name}-${inst}")
+ watchfrr_options="$watchfrr_options ${daemon_name}-${inst}"
fi
fi
done
else
if check_daemon $daemon_name; then
- watchfrr_options+=($daemon_name)
+ watchfrr_options="$watchfrr_options $daemon_name"
fi
fi
found_one=1
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index d2da06faa6..7a6344aa4c 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -637,6 +637,9 @@ fi
%config(noreplace) %{_sysconfdir}/pam.d/frr
%config(noreplace) %{_sysconfdir}/logrotate.d/frr
%{_sbindir}/frr-reload
+%{_sbindir}/frrcommon.sh
+%{_sbindir}/frrinit.sh
+%{_sbindir}/watchfrr.sh
%files contrib
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 59d4ae924b..ae0026cc97 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -1211,7 +1211,7 @@ DEFPY(ipv6_route_address_interface,
{
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
- const char *flag;
+ const char *flag = NULL;
if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
@@ -1280,7 +1280,7 @@ DEFPY(ipv6_route_address_interface_vrf,
VTY_DECLVAR_CONTEXT(vrf, vrf);
struct static_vrf *svrf = vrf->info;
struct static_vrf *nh_svrf;
- const char *flag;
+ const char *flag = NULL;
if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
@@ -1341,7 +1341,7 @@ DEFPY(ipv6_route,
{
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
- const char *flag;
+ const char *flag = NULL;
if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) {
vty_out(vty,
@@ -1407,7 +1407,7 @@ DEFPY(ipv6_route_vrf,
VTY_DECLVAR_CONTEXT(vrf, vrf);
struct static_vrf *svrf = vrf->info;
struct static_vrf *nh_svrf;
- const char *flag;
+ const char *flag = NULL;
if (table_str && !vrf_is_mapped_on_netns(vrf)) {
vty_out(vty,
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index 2fbc686e1e..78016dc9ce 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -1384,10 +1384,10 @@ static void bgp_startup(void)
LOG_DAEMON);
zprivs_preinit(&bgpd_privs);
zprivs_init(&bgpd_privs);
- yang_init();
- nb_init(NULL, 0);
master = thread_master_create(NULL);
+ yang_init();
+ nb_init(master, NULL, 0);
bgp_master_init(master);
bgp_option_set(BGP_OPT_NO_LISTEN);
vrf_init(NULL, NULL, NULL, NULL, NULL);
diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c
index 9e34a7c255..768cf296ad 100644
--- a/tests/helpers/c/main.c
+++ b/tests/helpers/c/main.c
@@ -156,7 +156,7 @@ int main(int argc, char **argv)
vty_init(master);
memory_init();
yang_init();
- nb_init(NULL, 0);
+ nb_init(master, NULL, 0);
/* OSPF vty inits. */
test_vty_init();
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index 04f1e3253d..393b588745 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -80,11 +80,12 @@ int main(int argc, char **argv)
/* Library inits. */
cmd_init(1);
cmd_hostname_set("test");
+ cmd_domainname_set("test.domain");
vty_init(master);
memory_init();
yang_init();
- nb_init(NULL, 0);
+ nb_init(master, NULL, 0);
test_init(argc, argv);
diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in
index af8f9ce56a..8f9959cc47 100644
--- a/tests/lib/cli/test_cli.refout.in
+++ b/tests/lib/cli/test_cli.refout.in
@@ -311,6 +311,7 @@ frr version @PACKAGE_VERSION@
frr defaults @DFLT_NAME@
!
hostname test
+domainname test.domain
!
!
!
@@ -327,6 +328,7 @@ frr version @PACKAGE_VERSION@
frr defaults @DFLT_NAME@
!
hostname foohost
+domainname test.domain
!
!
!
diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c
index 74816ece8c..ba46bdcea9 100644
--- a/tests/lib/cli/test_commands.c
+++ b/tests/lib/cli/test_commands.c
@@ -143,7 +143,7 @@ static void test_init(void)
cmd_init(1);
yang_init();
- nb_init(NULL, 0);
+ nb_init(master, NULL, 0);
install_node(&bgp_node, NULL);
install_node(&rip_node, NULL);
diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c
index a9a89ee491..7c5713d8f9 100644
--- a/tests/lib/northbound/test_oper_data.c
+++ b/tests/lib/northbound/test_oper_data.c
@@ -449,7 +449,7 @@ int main(int argc, char **argv)
vty_init(master);
memory_init();
yang_init();
- nb_init(modules, array_size(modules));
+ nb_init(master, modules, array_size(modules));
/* Create artificial data. */
create_data(num_vrfs, num_interfaces, num_routes);
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
index 274eceaf0f..cb08db5314 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
@@ -7,7 +7,7 @@ log monitor notifications
log commands
log file bgpd.log
-router bgp 5228
+router bgp 5228 vrf ce4-cust2
bgp router-id 99.0.0.4
neighbor 192.168.2.1 remote-as 5228
neighbor 192.168.2.1 update-source 192.168.2.2
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
index bfd8ba8435..e55c9e779a 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
@@ -2,7 +2,7 @@ log file zebra.log
!
hostname ce4
!
-interface lo
+interface ce4-cust2
ip address 99.0.0.4/32
!
interface ce4-eth0
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 596701cee2..31e23faede 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -196,7 +196,18 @@ def ltemplatePreRouterStartHook():
for intf in intfs:
cc.doCmd(tgen, rtr, 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf))
logger.info('setup {0} vrf {0}-cust2, {0}-eth5. enabled mpls input.'.format(rtr))
- if cc.getOutput() != 3:
+ #put ce4-eth0 into a VRF (no default instance!)
+ rtrs = ['ce4']
+ cmds = ['ip link add {0}-cust2 type vrf table 20',
+ 'ip ru add oif {0}-cust2 table 20',
+ 'ip ru add iif {0}-cust2 table 20',
+ 'ip link set dev {0}-cust2 up',
+ 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)]
+ for rtr in rtrs:
+ for cmd in cmds:
+ cc.doCmd(tgen, rtr, cmd.format(rtr))
+ cc.doCmd(tgen, rtr, 'ip link set dev {0}-eth0 master {0}-cust2'.format(rtr))
+ if cc.getOutput() != 4:
InitSuccess = False
logger.info('Unexpected output seen ({} times, tests will be skipped'.format(cc.getOutput()))
else:
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
index 1dfd22f6bd..28ecfeec5a 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
@@ -2,7 +2,7 @@ from lutil import luCommand
luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
-luCommand('ce4','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
+luCommand('ce4','vtysh -c "show bgp vrf all summary"',' 00:0','wait','Adjacencies up',180)
luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
index 174666a075..9827a9e2c1 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
@@ -31,13 +31,14 @@ if ret != False and found != None:
luCommand('ce1', 'ping 99.0.0.4 -I 99.0.0.1 -c 1',
' 0. packet loss','wait','CE->CE (loopback) ping - l3vpn+zebra case')
- luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1',
- ' 0. packet loss','wait','CE->CE (loopback) ping - l3vpn+zebra case')
+ #skip due to VRF weirdness
+ #luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1',
+ # ' 0. packet loss','wait','CE->CE (loopback) ping - l3vpn+zebra case')
luCommand('ce1', 'ping 99.0.0.4 -I 99.0.0.1 -c 1',
' 0. packet loss','wait','CE->CE (loopback) ping')
- luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1',
- ' 0. packet loss','wait','CE->CE (loopback) ping')
+ #luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1',
+ # ' 0. packet loss','wait','CE->CE (loopback) ping')
luCommand('r3', 'ip -M route show', '103', 'pass', 'MPLS->VRF route installed')
luCommand('ce2', 'ping 99.0.0.3 -I 99.0.0.2 -c 1',
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 6239f77a82..778d504040 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -1,4 +1,12 @@
from lutil import luCommand
+
+rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4']
+for rtr in rtrs:
+ luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','')
+ found = luLast()
+ luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0))
+ luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp')
+
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP,LOWER_UP','pass','VRF cust1 up')
@@ -11,4 +19,6 @@ rtrs = ['ce1', 'ce2', 'ce3']
for rtr in rtrs:
luCommand(rtr, 'ip route show','192.168...0/24 dev ce.-eth0','pass','CE interface route')
luCommand(rtr,'ping 192.168.1.1 -c 1',' 0. packet loss','wait','CE->PE ping')
-luCommand('ce4','ping 192.168.2.1 -c 1',' 0. packet loss','wait','CE4->PE4 ping')
+luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up')
+luCommand('ce4', 'ip route show vrf ce4-cust2','192.168...0/24 dev ce.-eth0','pass','CE interface route')
+luCommand('ce4','ping 192.168.2.1 -c 1 -I ce4-cust2',' 0. packet loss','wait','CE4->PE4 ping')
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
index 7b2387bd0b..e47ea5f2cd 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
@@ -37,7 +37,7 @@ want = [
{'p':'5.4.3.0/24', 'n':'99.0.0.4'},
{'p':'99.0.0.4/32', 'n':'0.0.0.0'},
]
-bgpribRequireUnicastRoutes('ce4','ipv4','','Cust 4 routes in ce1',want)
+bgpribRequireUnicastRoutes('ce4','ipv4','ce4-cust2','Cust 4 routes in ce1',want)
########################################################################
@@ -307,12 +307,12 @@ want = [
]
bgpribRequireUnicastRoutes('ce3','ipv4','','Cust 1 routes from remote',want)
-luCommand('ce4','vtysh -c "show bgp ipv4 uni"','10 routes and 10','wait','Local and remote routes', 10)
+luCommand('ce4','vtysh -c "show bgp vrf ce4-cust2 ipv4 uni"','10 routes and 10','wait','Local and remote routes', 10)
want = [
{'p':'5.1.0.0/24', 'n':'192.168.2.1'},
{'p':'5.1.1.0/24', 'n':'192.168.2.1'},
{'p':'5.1.2.0/24', 'n':'192.168.2.1'},
{'p':'5.1.3.0/24', 'n':'192.168.2.1'},
]
-bgpribRequireUnicastRoutes('ce4','ipv4','','Cust 2 routes from remote',want)
+bgpribRequireUnicastRoutes('ce4','ipv4','ce4-cust2','Cust 2 routes from remote',want)
diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py
index 8ec1511e10..5a81036643 100644
--- a/tests/topotests/lib/bgprib.py
+++ b/tests/topotests/lib/bgprib.py
@@ -123,7 +123,16 @@ class BgpRib:
return
luResult(target, True, title, logstr)
rib = json.loads(ret)
- table = rib['routes']
+ try:
+ table = rib['routes']
+ # KeyError: 'routes' probably means missing/bad VRF
+ except KeyError as err:
+ if vrf != '':
+ errstr = '-script ERROR: check if wrong vrf (%s)' % (vrf)
+ else:
+ errstr = '-script ERROR: check if vrf missing'
+ luResult(target, False, title + errstr, logstr)
+ return
for want in wantroutes:
if not self.routes_include_wanted(table,want,debug):
luResult(target, False, title, logstr)
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index f25b066288..e9b8d34ec3 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -863,7 +863,6 @@ class Router(Node):
))
self.waitOutput()
logger.debug('{}: {} staticd started'.format(self, self.routertype))
- sleep(1, '{}: waiting for staticd to start'.format(self.name))
# Fix Link-Local Addresses
# Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this
self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done')
diff --git a/tools/.gitignore b/tools/.gitignore
index c23322c4c6..85dae7fd36 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -3,3 +3,6 @@
/gen_yang_deviations
/permutations
/ssd
+/watchfrr.sh
+/frrinit.sh
+/frrcommon.sh
diff --git a/tools/etc/default/frr b/tools/etc/default/frr
deleted file mode 100644
index 693fa63390..0000000000
--- a/tools/etc/default/frr
+++ /dev/null
@@ -1,10 +0,0 @@
-MAX_INSTANCES=5
-MAX_FDS=1024
-ZEBRA_OPTIONS="-s 16777216 -A 127.0.0.1"
-BGPD_OPTIONS="-A 127.0.0.1"
-OSPFD_OPTIONS="-A 127.0.0.1"
-OSPF6D_OPTIONS="-A ::1"
-RIPD_OPTIONS="-A 127.0.0.1"
-RIPNGD_OPTIONS="-A ::1"
-ISISD_OPTIONS="-A 127.0.0.1"
-EIGRP_OPTIONS="-A 127.0.0.1"
diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons
index 1514082e90..2d56fe1b98 100644
--- a/tools/etc/frr/daemons
+++ b/tools/etc/frr/daemons
@@ -1,11 +1,5 @@
# This file tells the frr package which daemons to start.
#
-# Entries are in the format: <daemon>=(yes|no|priority)
-# 0, "no" = disabled
-# 1, "yes" = highest priority
-# 2 .. 10 = lower priorities
-# Read /usr/share/doc/frr/README.Debian for details.
-#
# Sample configurations for these daemons can be found in
# /usr/share/doc/frr/examples/.
#
@@ -18,10 +12,8 @@
# When using "vtysh" such a config file is also needed. It should be owned by
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
-# The watchfrr daemon is always started. Per default in monitoring-only but
-# that can be changed via /etc/frr/daemons.conf.
+# The watchfrr and zebra daemons are always started.
#
-zebra=no
bgpd=no
ospfd=no
ospf6d=no
@@ -37,3 +29,37 @@ sharpd=no
pbrd=no
bfdd=no
fabricd=no
+
+#
+# If this option is set the /etc/init.d/frr script automatically loads
+# the config via "vtysh -b" when the servers are started.
+# Check /etc/pam.d/frr if you intend to use "vtysh"!
+#
+vtysh_enable=yes
+zebra_options=" -A 127.0.0.1 -s 90000000"
+bgpd_options=" -A 127.0.0.1"
+ospfd_options=" -A 127.0.0.1"
+ospf6d_options=" -A ::1"
+ripd_options=" -A 127.0.0.1"
+ripngd_options=" -A ::1"
+isisd_options=" -A 127.0.0.1"
+pimd_options=" -A 127.0.0.1"
+ldpd_options=" -A 127.0.0.1"
+nhrpd_options=" -A 127.0.0.1"
+eigrpd_options=" -A 127.0.0.1"
+babeld_options=" -A 127.0.0.1"
+sharpd_options=" -A 127.0.0.1"
+pbrd_options=" -A 127.0.0.1"
+staticd_options="-A 127.0.0.1"
+bfdd_options=" -A 127.0.0.1"
+fabricd_options="-A 127.0.0.1"
+
+# The list of daemons to watch is automatically generated by the init script.
+watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'"
+
+# 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.
diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf
index 94221301eb..70b96a9800 100644
--- a/tools/etc/frr/daemons.conf
+++ b/tools/etc/frr/daemons.conf
@@ -1,33 +1 @@
-#
-# If this option is set the /etc/init.d/frr script automatically loads
-# the config via "vtysh -b" when the servers are started.
-# Check /etc/pam.d/frr if you intend to use "vtysh"!
-#
-vtysh_enable=yes
-zebra_options=" -s 90000000 --daemon -A 127.0.0.1"
-bgpd_options=" --daemon -A 127.0.0.1"
-ospfd_options=" --daemon -A 127.0.0.1"
-ospf6d_options=" --daemon -A ::1"
-ripd_options=" --daemon -A 127.0.0.1"
-ripngd_options=" --daemon -A ::1"
-isisd_options=" --daemon -A 127.0.0.1"
-pimd_options=" --daemon -A 127.0.0.1"
-ldpd_options=" --daemon -A 127.0.0.1"
-nhrpd_options=" --daemon -A 127.0.0.1"
-eigrpd_options=" --daemon -A 127.0.0.1"
-babeld_options=" --daemon -A 127.0.0.1"
-sharpd_options=" --daemon -A 127.0.0.1"
-pbrd_options=" --daemon -A 127.0.0.1"
-staticd_options=" --daemon -A 127.0.0.1"
-bfdd_options=" --daemon -A 127.0.0.1"
-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/lib/frr/frrbBrestartbB%s -s /usr/lib/frr/frrbBstartbB%s -k /usr/lib/frr/frrbBstopbB%s -b bB)
-
-# 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
+# this file is deprecated, please use "daemons" instead.
diff --git a/tools/frr.in b/tools/frr.in
index ec383bc5a0..a443191fd0 100755
--- a/tools/frr.in
+++ b/tools/frr.in
@@ -115,41 +115,45 @@ check_daemon()
# The Frr daemons creates the pidfile when starting.
start()
{
- ulimit -n $MAX_FDS
- if [ "$1" = "watchfrr" ]; then
+ local dmn inst
+ dmn="$1"
+ inst="$2"
+
+ ulimit -n $MAX_FDS > /dev/null 2> /dev/null
+ if [ "$dmn" = "watchfrr" ]; then
# We may need to restart watchfrr if new daemons are added and/or
# removed
- if started "$1" ; then
+ if started "$dmn" ; then
stop watchfrr
else
# Echo only once. watchfrr is printed in the stop above
- echo -n " $1"
+ echo -n " $dmn"
fi
-
+ eval "set - $watchfrr_options"
${SSD} \
--start \
- --pidfile=`pidfile $1` \
- --exec "$D_PATH/$1" \
+ --pidfile=`pidfile $dmn` \
+ --exec "$D_PATH/$dmn" \
-- \
- "${watchfrr_options[@]}"
+ "$@"
- elif [ -n "$2" ]; then
- echo -n " $1-$2"
- if ! check_daemon $1 $2 ; then
+ elif [ -n "$inst" ]; then
+ echo -n " $dmn-$inst"
+ if ! check_daemon $dmn $inst ; then
echo -n " (binary does not exist)"
return;
fi
${SSD} \
--start \
- --pidfile=`pidfile $1-$2` \
- --exec "$D_PATH/$1" \
+ --pidfile=`pidfile $dmn-$inst` \
+ --exec "$D_PATH/$dmn" \
-- \
- `eval echo "$""$1""_options"` -n "$2"
+ `eval echo "$""$dmn""_options"` -n "$inst"
else
- if ! check_daemon $1; then
+ if ! check_daemon $dmn; then
echo -n " (binary does not exist)"
return;
fi
@@ -157,22 +161,22 @@ start()
if [ "$valgrind_enable" = "yes" ]; then
${SSD} \
--start \
- --pidfile=`pidfile $1` \
+ --pidfile=`pidfile $dmn` \
--exec "$valgrind" \
- -- --trace-children=no --leak-check=full --log-file=/var/log/frr/$1-valgrind.log $D_PATH/$1 \
- `eval echo "$""$1""_options"`
+ -- --trace-children=no --leak-check=full --log-file=/var/log/frr/$dmn-valgrind.log $D_PATH/$dmn \
+ `eval echo "$""$dmn""_options"`
else
${SSD} \
--start \
- --pidfile=`pidfile $1` \
- --exec "$D_PATH/$1" \
+ --pidfile=`pidfile $dmn` \
+ --exec "$D_PATH/$dmn" \
-- \
- `eval echo "$""$1""_options"`
+ `eval echo "$""$dmn""_options"`
fi
fi
# Start the staticd automatically
- if [ "$1" = "zebra" ]; then
+ if [ "$dmn" = "zebra" ]; then
echo -n "starting staticd since zebra is running"
if ! check_daemon staticd ; then
echo -n " (binary does not exist)"
@@ -269,11 +273,9 @@ start_watchfrr()
fi
# Check variable type
- if ! declare -p watchfrr_options | grep -q '^declare \-a'; then
- echo
- echo "ERROR: The variable watchfrr_options from /etc/frr/debian.cnf must be a BASH array!"
- echo "ERROR: Please convert config file and restart!"
- exit 1
+ if declare -p watchfrr_options | grep -q '^declare \-a'; then
+ # old array support
+ watchfrr_options="${watchfrr_options[@]}"
fi
# Which daemons have been started?
@@ -287,13 +289,13 @@ start_watchfrr()
eval "inst_disable=\${${daemon_name}_${inst}}"
if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
if check_daemon $daemon_name $inst; then
- watchfrr_options+=("${daemon_name}-${inst}")
+ watchfrr_options="$watchfrr_options ${daemon_name}-${inst}"
fi
fi
done
else
if check_daemon $daemon_name; then
- watchfrr_options+=($daemon_name)
+ watchfrr_options="$watchfrr_options $daemon_name"
fi
fi
found_one=1
diff --git a/tools/frr.service b/tools/frr.service
index 5f44274ec3..03112bd7cd 100644
--- a/tools/frr.service
+++ b/tools/frr.service
@@ -5,7 +5,6 @@ OnFailure=heartbeat-failed@%n.service
[Service]
Nice=-5
-EnvironmentFile=/etc/default/frr
Type=forking
NotifyAccess=all
StartLimitInterval=3m
@@ -15,8 +14,8 @@ WatchdogSec=60s
RestartSec=5
Restart=on-abnormal
LimitNOFILE=1024
-ExecStart=/usr/lib/frr/frr start
-ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr-reload
+ExecStart=/usr/lib/frr/frrinit.sh start
+ExecStop=/usr/lib/frr/frrinit.sh stop
+ExecReload=/usr/lib/frr/frrinit.sh reload
[Install]
WantedBy=network-online.target
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
new file mode 100644
index 0000000000..7278e3f9df
--- /dev/null
+++ b/tools/frrcommon.sh.in
@@ -0,0 +1,317 @@
+#!/bin/sh
+#
+# This is a "library" of sorts for use by the other FRR shell scripts. It
+# has most of the daemon start/stop logic, but expects the following shell
+# functions/commands to be provided by the "calling" script:
+#
+# log_success_msg
+# log_warning_msg
+# log_failure_msg
+#
+# (coincidentally, these are LSB standard functions.)
+#
+# Sourcing this file in a shell script will load FRR config variables but
+# not perform any action. Note there is an "exit 1" if the main config
+# file does not exist.
+#
+# This script should be installed in @CFG_SBIN@/frrcommon.sh
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+D_PATH="@CFG_SBIN@" # /usr/lib/frr
+C_PATH="@CFG_SYSCONF@" # /etc/frr
+V_PATH="@CFG_STATE@" # /var/run/frr
+VTYSH="@vtysh_bin@" # /usr/bin/vtysh
+FRR_USER="@enable_user@" # frr
+FRR_GROUP="@enable_group@" # frr
+FRR_VTY_GROUP="@enable_vty_group@" # frrvty
+
+# ORDER MATTERS FOR $DAEMONS!
+# - keep zebra first
+# - watchfrr does NOT belong in this list
+
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd"
+RELOAD_SCRIPT="$D_PATH/frr-reload.py"
+
+#
+# general helpers
+#
+
+debug() {
+ [ -n "$watchfrr_debug" ] || return 0
+
+ printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
+ # this is to show how arguments are split regarding whitespace & co.
+ # (e.g. for use with `debug "message" "$@"`)
+ while [ $# -gt 0 ]; do
+ printf ' "%s"' "$1" >&2
+ shift
+ done
+ printf '\n' >&2
+}
+
+chownfrr() {
+ [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
+ [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
+}
+
+vtysh_b () {
+ [ "$1" = "watchfrr" ] && return 0
+ [ -r "$C_PATH/frr.conf" ] || return 0
+ if [ -n "$1" ]; then
+ "$VTYSH" -b -n -d "$1"
+ else
+ "$VTYSH" -b -n
+ fi
+}
+
+daemon_inst() {
+ # note this sets global variables ($dmninst, $daemon, $inst)
+ dmninst="$1"
+ daemon="${dmninst%:*}"
+ inst=""
+ [ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}"
+}
+
+daemon_list() {
+ # note $1 and $2 specify names for global variables to be set
+ local enabled disabled evar dvar
+ enabled=""
+ disabled=""
+ evar="$1"
+ dvar="$2"
+
+ for daemon in $DAEMONS; do
+ eval cfg=\$$daemon
+ eval inst=\$${daemon}_instances
+ [ "$daemon" = zebra ] && cfg=yes
+ if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
+ debug "$daemon enabled"
+ enabled="$enabled $daemon"
+ if [ -n "$inst" ]; then
+ debug "$daemon multi-instance $inst"
+ for i in $inst; do
+ enabled="$enabled $daemon:$inst"
+ done
+ fi
+ else
+ debug "$daemon disabled"
+ disabled="$disabled $daemon"
+ fi
+ done
+
+ enabled="${enabled# }"
+ disabled="${disabled# }"
+ [ -z "$evar" ] && echo "$enabled"
+ [ -n "$evar" ] && eval $evar="\"$enabled\""
+ [ -n "$dvar" ] && eval $dvar="\"$disabled\""
+}
+
+#
+# individual daemon management
+#
+
+daemon_prep() {
+ local daemon inst cfg
+ daemon="$1"
+ inst="$2"
+ [ "$daemon" = "watchfrr" ] && return 0
+ [ -x "$D_PATH/$daemon" ] || {
+ log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n"
+ return 1
+ }
+ [ -r "$C_PATH/frr.conf" ] && return 0
+
+ cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
+ if [ ! -r "$cfg" ]; then
+ touch "$cfg"
+ chownfrr "$cfg"
+ fi
+ return 0
+}
+
+daemon_start() {
+ local dmninst daemon inst args instopt wrap bin
+ daemon_inst "$1"
+
+ ulimit -n $MAX_FDS > /dev/null 2> /dev/null
+ daemon_prep "$daemon" "$inst" || return 1
+
+ eval wrap="\$${daemon}_wrap"
+ bin="$D_PATH/$daemon"
+ instopt="${inst:+-n $inst}"
+ eval args="\$${daemon}_options"
+
+ if eval "$all_wrap $wrap $bin -d $instopt $args"; then
+ log_success_msg "Started $dmninst"
+ vtysh_b "$daemon"
+ else
+ log_failure_msg "Failed to start $dmninst!"
+ fi
+}
+
+daemon_stop() {
+ local dmninst daemon inst pidfile vtyfile pid cnt fail
+ daemon_inst "$1"
+
+ pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
+ vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
+
+ [ -r "$pidfile" ] || fail="pid file not found"
+ [ -z "$fail" ] && pid="`cat \"$pidfile\"`"
+ [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
+ [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
+
+ if [ -n "$fail" ]; then
+ log_failure_msg "Cannot stop $dmninst: $fail"
+ return 1
+ fi
+
+ debug "kill -2 $pid"
+ kill -2 "$pid"
+ cnt=1200
+ while kill -0 "$pid" 2>/dev/null; do
+ sleep .1
+ [ $(( cnt -= 1 )) -gt 0 ] || break
+ done
+ if kill -0 "$pid" 2>/dev/null; then
+ log_failure_msg "Failed to stop $dmninst, pid $pid still running"
+ still_running=1
+ return 1
+ else
+ log_success_msg "Stopped $dmninst"
+ rm -f "$pidfile"
+ return 0
+ fi
+}
+
+daemon_status() {
+ local dmninst daemon inst pidfile pid fail
+ daemon_inst "$1"
+
+ pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
+
+ [ -r "$pidfile" ] || return 3
+ pid="`cat \"$pidfile\"`"
+ [ -z "$pid" ] && return 1
+ kill -0 "$pid" 2>/dev/null || return 1
+ return 0
+}
+
+print_status() {
+ daemon_status "$1"
+ rv=$?
+ if [ "$rv" -eq 0 ]; then
+ log_success_msg "Status of $1: running"
+ else
+ log_failure_msg "Status of $1: FAILED"
+ fi
+ return $rv
+}
+
+#
+# all-daemon commands
+#
+
+all_start() {
+ daemon_list daemons
+ for dmninst in $daemons; do
+ daemon_start "$dmninst"
+ done
+}
+
+all_stop() {
+ local pids reversed
+
+ daemon_list daemons disabled
+ [ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
+
+ reversed=""
+ for dmninst in $daemons; do
+ reversed="$dmninst $reversed"
+ done
+
+ for dmninst in $reversed; do
+ daemon_stop "$dmninst" &
+ pids="$pids $!"
+ done
+ for pid in $pids; do
+ wait $pid
+ done
+}
+
+all_status() {
+ local fail
+
+ daemon_list daemons
+ fail=0
+ for dmninst in $daemons; do
+ print_status "$dmninst" || fail=1
+ done
+ return $fail
+}
+
+#
+# config sourcing
+#
+
+load_old_config() {
+ oldcfg="$1"
+ [ -r "$oldcfg" ] || return 0
+ [ -s "$oldcfg" ] || return 0
+ grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
+
+ log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
+
+ # save off settings from daemons for the OR below
+ for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
+
+ . "$oldcfg"
+
+ # OR together the daemon enabling options between config files
+ for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
+}
+
+[ -r "$C_PATH/daemons" ] || {
+ log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n"
+ exit 1
+}
+. "$C_PATH/daemons"
+
+load_old_config "$C_PATH/daemons.conf"
+load_old_config "/etc/default/frr"
+load_old_config "/etc/sysconfig/frr"
+
+#
+# other defaults and dispatch
+#
+
+frrcommon_main() {
+ local cmd
+
+ debug "frrcommon_main" "$@"
+
+ cmd="$1"
+ shift
+
+ if [ "$1" = "all" -o -z "$1" ]; then
+ case "$cmd" in
+ start) all_start;;
+ stop) all_stop;;
+ restart)
+ all_stop
+ all_start
+ ;;
+ *) $cmd "$@";;
+ esac
+ else
+ case "$cmd" in
+ start) daemon_start "$@";;
+ stop) daemon_stop "$@";;
+ restart)
+ daemon_stop "$@"
+ daemon_start "$@"
+ ;;
+ *) $cmd "$@";;
+ esac
+ fi
+}
diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in
new file mode 100644
index 0000000000..3dddf5bd44
--- /dev/null
+++ b/tools/frrinit.sh.in
@@ -0,0 +1,90 @@
+#!/bin/sh
+#
+### BEGIN INIT INFO
+# Provides: frr
+# Required-Start: $local_fs $network $remote_fs $syslog
+# Required-Stop: $local_fs $network $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: start and stop the FRR routing suite
+# Description: FRR is a routing suite for IP routing protocols like
+# BGP, OSPF, RIP and others. This script contols the main
+# "watchfrr" daemon.
+### END INIT INFO
+#
+# This is the main init script for FRR. It mostly wraps frrcommon.sh which
+# provides the actual functions to start/stop/restart things.
+#
+
+if [ -r "/lib/lsb/init-functions" ]; then
+ . /lib/lsb/init-functions
+else
+ log_success_msg() {
+ echo "$@"
+ }
+ log_warning_msg() {
+ echo "$@" >&2
+ }
+ log_failure_msg() {
+ echo "$@" >&2
+ }
+fi
+
+self="`dirname $0`"
+if [ -r "$self/frrcommon.sh" ]; then
+ . "$self/frrcommon.sh"
+else
+ . "@CFG_SBIN@/frrcommon.sh"
+fi
+
+case "$1" in
+start)
+ daemon_list daemons
+ watchfrr_options="$watchfrr_options $daemons"
+ daemon_start watchfrr
+ ;;
+stop)
+ daemon_stop watchfrr
+ all_stop --reallyall
+ exit ${still_running:-0}
+ ;;
+
+restart|force-reload)
+ daemon_stop watchfrr
+ all_stop --reallyall
+
+ daemon_list daemons
+ watchfrr_options="$watchfrr_options $daemons"
+ daemon_start watchfrr
+ ;;
+
+status)
+ fail=0
+ print_status watchfrr || fail=1
+ all_status || fail=1
+ exit $fail
+ ;;
+
+reload)
+ if [ ! -x "$RELOAD_SCRIPT" ]; then
+ log_failure_msg "The frr-pythontools package is required for reload functionality."
+ exit 1
+ fi
+
+ # restart watchfrr to pick up added daemons.
+ # NB: This will NOT cause the other daemons to be restarted.
+ daemon_list daemons
+ watchfrr_options="$watchfrr_options $daemons"
+ daemon_stop watchfrr && \
+ daemon_start watchfrr
+
+ NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
+ [ ! -r $NEW_CONFIG_FILE ] && log_failure_msg "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
+ "$RELOAD_SCRIPT" --reload "$NEW_CONFIG_FILE"
+ exit $?
+ ;;
+
+*)
+ log_failure_msg "Unknown command: $1" >&2
+ exit 1
+esac
diff --git a/tools/subdir.am b/tools/subdir.am
index 2e68dfee09..ff41fe2c63 100644
--- a/tools/subdir.am
+++ b/tools/subdir.am
@@ -13,6 +13,10 @@ sbin_SCRIPTS += \
tools/frr-reload \
tools/frr-reload.py \
tools/frr \
+ \
+ tools/frrcommon.sh \
+ tools/frrinit.sh \
+ tools/watchfrr.sh \
# end
tools_permutations_SOURCES = tools/permutations.c
diff --git a/tools/watchfrr.sh.in b/tools/watchfrr.sh.in
new file mode 100644
index 0000000000..3051d91044
--- /dev/null
+++ b/tools/watchfrr.sh.in
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# This is NOT the init script! This is the watchfrr start/stop/restart
+# command handler, passed to watchfrr with the -s/-r/-k commands. It is used
+# internally by watchfrr to start the protocol daemons with the appropriate
+# options.
+#
+# This script should be installed in @CFG_SBIN@/watchfrr.sh
+
+log_success_msg() {
+ :
+}
+
+log_warning_msg() {
+ echo "$@" >&2
+ [ -x /usr/bin/logger ] && echo "$@" \
+ | /usr/bin/logger -t watchfrr.sh -p daemon.warn
+}
+
+log_failure_msg() {
+ echo "$@" >&2
+ [ -x /usr/bin/logger ] && echo "$@" \
+ | /usr/bin/logger -t watchfrr.sh -p daemon.err
+}
+
+self="`dirname $0`"
+if [ -r "$self/frrcommon.sh" ]; then
+ . "$self/frrcommon.sh"
+else
+ . "@CFG_SBIN@/frrcommon.sh"
+fi
+
+frrcommon_main "$@"
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index f57a4d9ddf..2327f2b46d 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -104,7 +104,7 @@ static int vty_close_pager(struct vty *vty)
return 0;
}
-void vtysh_pager_init(void)
+static void vtysh_pager_envdef(void)
{
char *pager_defined;
@@ -2881,52 +2881,58 @@ DEFUN (vtysh_copy_running_config,
return vtysh_write_memory(self, vty, argc, argv);
}
+DEFUN (vtysh_terminal_paginate,
+ vtysh_terminal_paginate_cmd,
+ "[no] terminal paginate",
+ NO_STR
+ "Set terminal line parameters\n"
+ "Use pager for output scrolling\n")
+{
+ free(vtysh_pager_name);
+ vtysh_pager_name = NULL;
+
+ if (strcmp(argv[0]->text, "no"))
+ vtysh_pager_envdef();
+ return CMD_SUCCESS;
+}
+
DEFUN (vtysh_terminal_length,
vtysh_terminal_length_cmd,
- "terminal length (0-512)",
+ "[no] terminal length (0-4294967295)",
+ NO_STR
"Set terminal line parameters\n"
"Set number of lines on a screen\n"
- "Number of lines on screen (0 for no pausing)\n")
+ "Number of lines on screen (0 for no pausing, nonzero to use pager)\n")
{
int idx_number = 2;
- int lines;
- char *endptr = NULL;
- char default_pager[10];
+ unsigned long lines;
- lines = strtol(argv[idx_number]->arg, &endptr, 10);
- if (lines < 0 || lines > 512 || *endptr != '\0') {
- vty_out(vty, "length is malformed\n");
- return CMD_WARNING;
- }
+ free(vtysh_pager_name);
+ vtysh_pager_name = NULL;
- if (vtysh_pager_name) {
- free(vtysh_pager_name);
- vtysh_pager_name = NULL;
+ if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) {
+ /* "terminal no length" = use VTYSH_PAGER */
+ vtysh_pager_envdef();
+ return CMD_SUCCESS;
}
+ lines = strtoul(argv[idx_number]->arg, NULL, 10);
if (lines != 0) {
- snprintf(default_pager, 10, "more -%i", lines);
- vtysh_pager_name = strdup(default_pager);
+ 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();
}
return CMD_SUCCESS;
}
-DEFUN (vtysh_terminal_no_length,
+ALIAS_DEPRECATED(vtysh_terminal_length,
vtysh_terminal_no_length_cmd,
"terminal no length",
"Set terminal line parameters\n"
NO_STR
"Set number of lines on a screen\n")
-{
- if (vtysh_pager_name) {
- free(vtysh_pager_name);
- vtysh_pager_name = NULL;
- }
-
- vtysh_pager_init();
- return CMD_SUCCESS;
-}
DEFUN (vtysh_show_daemons,
vtysh_show_daemons_cmd,
@@ -3805,6 +3811,7 @@ void vtysh_init_vty(void)
/* "write memory" command. */
install_element(ENABLE_NODE, &vtysh_write_memory_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);
install_element(VIEW_NODE, &vtysh_show_daemons_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 430b117c50..eb69a20b83 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -98,8 +98,6 @@ void vtysh_config_dump(void);
void vtysh_config_init(void);
-void vtysh_pager_init(void);
-
void suid_on(void);
void suid_off(void);
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 777eed7b5d..2e4510a45a 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -675,8 +675,6 @@ int main(int argc, char **argv, char **env)
exit(0);
}
- vtysh_pager_init();
-
vtysh_readline_init();
vty_hello(vty);
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index e32bf3359b..e28da6db8c 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -65,6 +65,7 @@ static bool watch_only = false;
typedef enum {
PHASE_NONE = 0,
+ PHASE_INIT,
PHASE_STOPS_PENDING,
PHASE_WAITING_DOWN,
PHASE_ZEBRA_RESTART_PENDING,
@@ -72,7 +73,8 @@ typedef enum {
} restart_phase_t;
static const char *phase_str[] = {
- "None",
+ "Idle",
+ "Startup",
"Stop jobs running",
"Waiting for other daemons to come down",
"Zebra restart job running",
@@ -112,7 +114,7 @@ static struct global_state {
int numpids;
int numdown; /* # of daemons that are not UP or UNRESPONSIVE */
} gs = {
- .phase = PHASE_NONE,
+ .phase = PHASE_INIT,
.vtydir = frr_vtydir,
.period = 1000 * DEFAULT_PERIOD,
.timeout = DEFAULT_TIMEOUT,
@@ -177,6 +179,7 @@ static int try_connect(struct daemon *dmn);
static int wakeup_send_echo(struct thread *t_wakeup);
static void try_restart(struct daemon *dmn);
static void phase_check(void);
+static void restart_done(struct daemon *dmn);
static const char *progname;
static void printhelp(FILE *target)
@@ -333,6 +336,7 @@ static void sigchild(void)
const char *name;
const char *what;
struct restart_info *restart;
+ struct daemon *dmn;
switch (child = waitpid(-1, &status, WNOHANG)) {
case -1:
@@ -378,9 +382,18 @@ static void sigchild(void)
zlog_warn(
"%s %s process %d exited with non-zero status %d",
what, name, (int)child, WEXITSTATUS(status));
- else
+ else {
zlog_debug("%s %s process %d exited normally", what,
name, (int)child);
+
+ if (restart && restart != &gs.restart) {
+ dmn = container_of(restart, struct daemon,
+ restart);
+ restart_done(dmn);
+ } else if (restart)
+ for (dmn = gs.daemons; dmn; dmn = dmn->next)
+ restart_done(dmn);
+ }
} else
flog_err_sys(
EC_LIB_SYSTEM_CALL,
@@ -494,15 +507,27 @@ static int wakeup_init(struct thread *t_wakeup)
dmn->t_wakeup = NULL;
if (try_connect(dmn) < 0) {
- SET_WAKEUP_DOWN(dmn);
flog_err(EC_WATCHFRR_CONNECTION,
"%s state -> down : initial connection attempt failed",
dmn->name);
dmn->state = DAEMON_DOWN;
}
+ phase_check();
return 0;
}
+static void restart_done(struct daemon *dmn)
+{
+ if (dmn->state != DAEMON_DOWN) {
+ zlog_warn("wtf?");
+ return;
+ }
+ if (dmn->t_wakeup)
+ THREAD_OFF(dmn->t_wakeup);
+ if (try_connect(dmn) < 0)
+ SET_WAKEUP_DOWN(dmn);
+}
+
static void daemon_down(struct daemon *dmn, const char *why)
{
if (IS_UP(dmn) || (dmn->state == DAEMON_INIT))
@@ -773,9 +798,25 @@ static void set_phase(restart_phase_t new_phase)
static void phase_check(void)
{
+ struct daemon *dmn;
+
switch (gs.phase) {
case PHASE_NONE:
break;
+
+ case PHASE_INIT:
+ for (dmn = gs.daemons; dmn; dmn = dmn->next)
+ if (dmn->state == DAEMON_INIT)
+ return;
+
+ /* startup complete, everything out of INIT */
+ gs.phase = PHASE_NONE;
+ for (dmn = gs.daemons; dmn; dmn = dmn->next)
+ if (dmn->state == DAEMON_DOWN) {
+ SET_WAKEUP_DOWN(dmn);
+ try_restart(dmn);
+ }
+ break;
case PHASE_STOPS_PENDING:
if (gs.numpids)
break;
@@ -929,6 +970,31 @@ bool check_all_up(void)
return true;
}
+void watchfrr_status(struct vty *vty)
+{
+ struct daemon *dmn;
+ struct timeval delay;
+
+ vty_out(vty, "watchfrr global phase: %s\n", phase_str[gs.phase]);
+ if (gs.restart.pid)
+ vty_out(vty, " global restart running, pid %ld\n",
+ (long)gs.restart.pid);
+
+ for (dmn = gs.daemons; dmn; dmn = dmn->next) {
+ vty_out(vty, " %-20s %s\n", dmn->name, state_str[dmn->state]);
+ if (dmn->restart.pid)
+ vty_out(vty, " restart running, pid %ld\n",
+ (long)dmn->restart.pid);
+ else if (dmn->state == DAEMON_DOWN &&
+ time_elapsed(&delay, &dmn->restart.time)->tv_sec
+ < dmn->restart.interval)
+ vty_out(vty, " restarting in %ld seconds"
+ " (%lds backoff interval)\n",
+ dmn->restart.interval - delay.tv_sec,
+ dmn->restart.interval);
+ }
+}
+
static void sigint(void)
{
zlog_notice("Terminating on signal");
@@ -980,8 +1046,7 @@ static void watchfrr_init(int argc, char **argv)
gs.numdown++;
dmn->fd = -1;
dmn->t_wakeup = NULL;
- thread_add_timer_msec(master, wakeup_init, dmn,
- 100 + (random() % 900),
+ thread_add_timer_msec(master, wakeup_init, dmn, 0,
&dmn->t_wakeup);
dmn->restart.interval = gs.min_restart_interval;
*add = dmn;
diff --git a/watchfrr/watchfrr.h b/watchfrr/watchfrr.h
index ee16846a1d..c5f54769bd 100644
--- a/watchfrr/watchfrr.h
+++ b/watchfrr/watchfrr.h
@@ -29,6 +29,10 @@ extern void watchfrr_vty_init(void);
extern pid_t integrated_write_pid;
extern void integrated_write_sigchld(int status);
+
+struct vty;
+extern void watchfrr_status(struct vty *vty);
+
/*
* Check if all daemons we are monitoring are in the DAEMON_UP state.
*
diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c
index 1bfc41f255..9b844d67f2 100644
--- a/watchfrr/watchfrr_vty.c
+++ b/watchfrr/watchfrr_vty.c
@@ -124,6 +124,16 @@ DEFUN_NOSH (show_debugging_watchfrr,
return CMD_SUCCESS;
}
+DEFUN (show_watchfrr,
+ show_watchfrr_cmd,
+ "show watchfrr",
+ SHOW_STR
+ WATCHFRR_STR)
+{
+ watchfrr_status(vty);
+ return CMD_SUCCESS;
+}
+
void integrated_write_sigchld(int status)
{
uint8_t reply[4] = {0, 0, 0, CMD_WARNING};
@@ -159,4 +169,5 @@ void watchfrr_vty_init(void)
install_element(ENABLE_NODE, &config_write_integrated_cmd);
install_element(ENABLE_NODE, &show_debugging_watchfrr_cmd);
install_element(CONFIG_NODE, &show_debugging_watchfrr_cmd);
+ install_element(VIEW_NODE, &show_watchfrr_cmd);
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 7052fab01c..e6cc802d08 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -732,15 +732,14 @@ static void vty_show_ip_route_detail_json(struct vty *vty,
char buf[BUFSIZ];
json = json_object_new_object();
+ json_prefix = json_object_new_array();
RNODE_FOREACH_RE (rn, re) {
- json_prefix = json_object_new_array();
vty_show_ip_route(vty, rn, re, json_prefix);
- prefix2str(&rn->p, buf, sizeof buf);
- json_object_object_add(json, buf, json_prefix);
- json_prefix = NULL;
}
+ prefix2str(&rn->p, buf, sizeof(buf));
+ json_object_object_add(json, buf, json_prefix);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);