diff options
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_ */ @@ -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) { @@ -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); |
