diff --git a/.gitignore b/.gitignore index 3ad6b1de1c..7ed1255d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ GPATH *.la *.lo compile_commands.json +.dirstamp diff --git a/Makefile.am b/Makefile.am index 7cfe4a97e3..494fcd4d56 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ noinst_LIBRARIES = lib_LTLIBRARIES = module_LTLIBRARIES = pkginclude_HEADERS = +nodist_pkginclude_HEADERS = dist_examples_DATA = include lib/subdir.am @@ -29,16 +30,27 @@ include zebra/subdir.am include qpb/subdir.am include fpm/subdir.am +include ripd/subdir.am +include ripngd/subdir.am +include ospfd/subdir.am +include ospf6d/subdir.am +include ospfclient/subdir.am +include isisd/subdir.am +include nhrpd/subdir.am +include ldpd/subdir.am +include babeld/subdir.am +include eigrpd/subdir.am + SUBDIRS = . @LIBRFP@ @RFPTEST@ \ - @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \ - @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ @BABELD@ \ - @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ \ + @BGPD@ \ + @PIMD@ \ + @WATCHFRR@ @VTYSH@ @DOC@ \ @SOLARIS@ tests tools -DIST_SUBDIRS = . bgpd ripd ripngd ospfd ospf6d ldpd \ - isisd watchfrr vtysh ospfclient doc tests \ - solaris pimd nhrpd eigrpd bgpd/rfp-example/librfp \ - bgpd/rfp-example/rfptest tools babeld \ +DIST_SUBDIRS = . bgpd \ + watchfrr vtysh doc tests \ + solaris pimd bgpd/rfp-example/librfp \ + bgpd/rfp-example/rfptest tools \ # end if PKGSRC diff --git a/babeld/.gitignore b/babeld/.gitignore index 8384763a65..fbdb90f677 100644 --- a/babeld/.gitignore +++ b/babeld/.gitignore @@ -2,6 +2,7 @@ !*.c !*.h !LICENCE -!Makefile.am +!Makefile +!subdir.am !babeld.conf.sample -!.gitignore \ No newline at end of file +!.gitignore diff --git a/babeld/Makefile b/babeld/Makefile new file mode 100644 index 0000000000..ae125e6e4d --- /dev/null +++ b/babeld/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. babeld/babeld +%: ALWAYS + @$(MAKE) -s -C .. babeld/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/babeld/Makefile.am b/babeld/Makefile.am deleted file mode 100644 index 39f748e7fa..0000000000 --- a/babeld/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PILDFLAGS) - -noinst_LIBRARIES = libbabel.a -sbin_PROGRAMS = babeld - -libbabel_a_SOURCES = \ - babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ - route.c xroute.c message.c resend.c babel_interface.c babeld.c \ - babel_filter.c babel_memory.c - -noinst_HEADERS = \ - babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ - route.h xroute.h message.h resend.h babel_interface.h babeld.h \ - babel_filter.h babel_main.h babel_memory.h - -babeld_SOURCES = \ - babel_main.c $(libbabel_a_SOURCES) - -babeld_LDADD = ../lib/libfrr.la @LIBCAP@ - -examplesdir = $(exampledir) -dist_examples_DATA = babeld.conf.sample diff --git a/babeld/subdir.am b/babeld/subdir.am new file mode 100644 index 0000000000..c44cb275c2 --- /dev/null +++ b/babeld/subdir.am @@ -0,0 +1,47 @@ +# +# babeld +# + +if BABELD +noinst_LIBRARIES += babeld/libbabel.a +sbin_PROGRAMS += babeld/babeld +dist_examples_DATA += babeld/babeld.conf.sample +endif + +babeld_libbabel_a_SOURCES = \ + babeld/babel_filter.c \ + babeld/babel_interface.c \ + babeld/babel_memory.c \ + babeld/babel_zebra.c \ + babeld/babeld.c \ + babeld/kernel.c \ + babeld/message.c \ + babeld/neighbour.c \ + babeld/net.c \ + babeld/resend.c \ + babeld/route.c \ + babeld/source.c \ + babeld/util.c \ + babeld/xroute.c \ + # end + +noinst_HEADERS += \ + babeld/babel_filter.h \ + babeld/babel_interface.h \ + babeld/babel_main.h \ + babeld/babel_memory.h \ + babeld/babel_zebra.h \ + babeld/babeld.h \ + babeld/kernel.h \ + babeld/message.h \ + babeld/neighbour.h \ + babeld/net.h \ + babeld/resend.h \ + babeld/route.h \ + babeld/source.h \ + babeld/util.h \ + babeld/xroute.h \ + # end + +babeld_babeld_SOURCES = babeld/babel_main.c +babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la @LIBCAP@ diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index bd3ae27c05..36ffb0e9c5 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -543,8 +543,6 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, reuse_time = 0; /* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 if (reuse_time == 0) { if (use_json) json_object_int_add(json, "reuseTimerMsecs", 0); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2fa10dc6cd..d30def0f07 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6110,11 +6110,6 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, u_char use_json, uptime1 -= uptime2; tm = gmtime(&uptime1); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 -#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 - if (uptime1 < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/bgpd/rfapi/.gitignore b/bgpd/rfapi/.gitignore deleted file mode 100644 index 0638d7514b..0000000000 --- a/bgpd/rfapi/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.dirstamp diff --git a/configure.ac b/configure.ac index 1343d31336..d501c4449b 100755 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ AC_PREREQ(2.60) AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" +AC_SUBST(PACKAGE_URL) PACKAGE_FULLNAME="FRRouting" AC_SUBST(PACKAGE_FULLNAME) @@ -1019,6 +1020,13 @@ fi LIBS="$TMPLIBS" AC_SUBST(LIBM) +AC_CHECK_FUNCS([ppoll], [ + AC_DEFINE([HAVE_PPOLL], 1, [have Linux/BSD ppoll()]) +]) +AC_CHECK_FUNCS([pollts], [ + AC_DEFINE([HAVE_POLLTS], 1, [have NetBSD pollts()]) +]) + dnl --------------- dnl other functions dnl --------------- @@ -1057,8 +1065,11 @@ case "$host_os" in if test $ac_cv_header_net_bpf_h = no; then if test $ac_cv_header_sys_dlpi_h = no; then AC_MSG_RESULT(none) + if test "${enable_isisd}" = yes; then + AC_MSG_FAILURE([IS-IS support requested but no packet backend found]) + fi AC_MSG_WARN([*** IS-IS support will not be built ***]) - ISISD="" + enable_isisd="no" else AC_MSG_RESULT(DLPI) fi @@ -1241,27 +1252,13 @@ else fi AM_CONDITIONAL(BGPD, test "x$BGPD" = "xbgpd") -if test "${enable_ripd}" = "no";then - RIPD="" -else - RIPD="ripd" -fi -AM_CONDITIONAL(RIPD, test "x$RIPD" = "xripd") +AM_CONDITIONAL(RIPD, test "${enable_ripd}" != "no") +AM_CONDITIONAL(OSPFD, test "${enable_ospfd}" != "no") +AM_CONDITIONAL(LDPD, test "${enable_ldpd}" != "no") -if test "${enable_ospfd}" = "no";then - OSPFD="" -else - OSPFD="ospfd" -fi -AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") - -if test "${enable_ldpd}" = "no";then - LDPD="" -else - LDPD="ldpd" +AS_IF([test "${enable_ldpd}" != "no"], [ AC_DEFINE(HAVE_LDPD, 1, ldpd) -fi -AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd") +]) NHRPD="" case "$host_os" in @@ -1278,12 +1275,7 @@ case "$host_os" in esac AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd") -if test "${enable_eigrpd}" = "no";then - EIGRPD="" -else - EIGRPD="eigrpd" -fi -AM_CONDITIONAL(EIGRPD, test "x$EIGRPD" = "xeigrpd") +AM_CONDITIONAL(EIGRPD, test "${enable_eigrpd}" != "no") if test "${enable_watchfrr}" = "no";then WATCHFRR="" @@ -1302,30 +1294,10 @@ if test "${enable_ospfapi}" != "no";then fi AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") - -case "${enable_ripngd}" in - "no" ) RIPNGD="";; - * ) RIPNGD="ripngd";; -esac -AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd") - -case "${enable_babeld}" in - "no" ) BABELD="";; - * ) BABELD="babeld";; -esac -AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld") - -case "${enable_ospf6d}" in - "no" ) OSPF6D="";; - * ) OSPF6D="ospf6d";; -esac -AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") - -case "${enable_isisd}" in - "no" ) ISISD="";; - * ) ISISD="isisd";; -esac -AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") +AM_CONDITIONAL(RIPNGD, test "${enable_ripngd}" != "no") +AM_CONDITIONAL(BABELD, test "${enable_babeld}" != "no") +AM_CONDITIONAL(OSPF6D, test "${enable_ospf6d}" != "no") +AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no") case "${enable_pimd}" in "no" ) PIMD="";; @@ -1364,23 +1336,13 @@ AC_SUBST(DOC) AC_SUBST(RFPTEST) AC_SUBST(LIBRFP) AC_SUBST(RFPINC) -AC_SUBST(BABELD) AC_SUBST(BGPD) -AC_SUBST(RIPD) -AC_SUBST(RIPNGD) -AC_SUBST(OSPFD) -AC_SUBST(OSPF6D) -AC_SUBST(LDPD) -AC_SUBST(NHRPD) -AC_SUBST(EIGRPD) AC_SUBST(WATCHFRR) AC_SUBST(ISISD) AC_SUBST(PIMD) AC_SUBST(SOLARIS) AC_SUBST(VTYSH) AC_SUBST(CURSES) -AC_SUBST(OSPFCLIENT) -AC_SUBST(OSPFAPI) AC_CHECK_LIB(crypt, crypt, [], [AC_CHECK_LIB(crypto, DES_crypt)]) AC_CHECK_LIB(resolv, res_init) @@ -1824,15 +1786,12 @@ AC_CACHE_VAL(ac_cv_htonl_works, ) AC_MSG_RESULT($ac_cv_htonl_works) -AC_CONFIG_FILES([Makefile ripd/Makefile - ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile - ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile - doc/Makefile ospfclient/Makefile tests/Makefile +AC_CONFIG_FILES([Makefile + bgpd/Makefile watchfrr/Makefile + vtysh/Makefile + doc/Makefile tests/Makefile bgpd/rfp-example/rfptest/Makefile bgpd/rfp-example/librfp/Makefile - babeld/Makefile pimd/Makefile - eigrpd/Makefile - nhrpd/Makefile tools/Makefile redhat/frr.spec snapcraft/snapcraft.yaml @@ -1863,6 +1822,34 @@ AC_CONFIG_FILES([solaris/Makefile]) AC_CONFIG_FILES([vtysh/extract.pl],[chmod +x vtysh/extract.pl]) +AC_CONFIG_COMMANDS([lib/route_types.h], [ + dst="${ac_abs_top_builddir}/lib/route_types.h" + ${PERL} "${ac_abs_top_srcdir}/lib/route_types.pl" \ + < "${ac_abs_top_srcdir}/lib/route_types.txt" \ + > "${dst}.tmp" + test -f "${dst}" \ + && diff "${dst}.tmp" "${dst}" >/dev/null 2>/dev/null \ + && rm "${dst}.tmp" \ + || mv "${dst}.tmp" "${dst}" +], [ + PERL="$PERL" +]) + +AS_IF([test "x$with_pkg_git_version" = "xyes"], [ + AC_CONFIG_COMMANDS([lib/gitversion.h], [ + dst="${ac_abs_top_builddir}/lib/gitversion.h" + ${PERL} "${ac_abs_top_srcdir}/lib/gitversion.pl" \ + "${ac_abs_top_srcdir}" \ + > "${dst}.tmp" + test -f "${dst}" \ + && diff "${dst}.tmp" "${dst}" >/dev/null 2>/dev/null \ + && rm "${dst}.tmp" \ + || mv "${dst}.tmp" "${dst}" + ], [ + PERL="$PERL" + ]) +]) + ## Hack, but working solution to avoid rebuilding of frr.info. ## It's already in CVS until texinfo 4.7 is more common. AC_OUTPUT diff --git a/debian/frr.logrotate b/debian/frr.logrotate index 0dd68fb257..9a1fa2149b 100644 --- a/debian/frr.logrotate +++ b/debian/frr.logrotate @@ -7,11 +7,21 @@ create 640 frr frrvty postrotate - for i in zebra bgpd ripd ospfd ripngd ospf6d isisd pimd; do - if [ -e /var/run/frr/$i.pid ] ; then - kill -USR1 `cat /var/run/frr/$i.pid` - fi - - done + pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null) + if [ -n "$pid" ] + then # using syslog + kill -HUP $pid + fi + # in case using file logging; if switching back and forth + # between file and syslog, rsyslogd might still have file + # open, as well as the daemons, so always signal the daemons. + # It's safe, a NOP if (only) syslog is being used. + for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd \ + pimd ripd ripngd zebra ; do + if [ -e /var/run/frr/$i.pid ] ; then + pids="$pids $(cat /var/run/frr/$i.pid)" + fi + done + [ -n "$pids" ] && kill -USR1 $pids endscript } diff --git a/doc/Makefile.am b/doc/Makefile.am index b2bdf91cd4..9016df7372 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -45,17 +45,19 @@ figures_txt = $(figures_names_parts:%=fig%.txt) # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. -# Built from defines.texi.in -BUILT_SOURCES = defines.texi - info_TEXINFOS = frr.texi # Have to manually specify the frr.pdf rule in order to allow # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... -frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) - $(TEXI2PDF) -o "$@" $< || true +frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) defines.texi + $(TEXI2PDF) -o "$@" $< + +# don't ask me why the info file is in srcdir +$(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi +frr.dvi: $(frr_TEXINFOS) defines.texi +frr.html: $(frr_TEXINFOS) defines.texi frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \ vnc.texi \ @@ -65,7 +67,7 @@ frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \ eigrpd.texi \ ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ - snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ + snmp.texi vtysh.texi routeserver.texi $(figures_png) \ snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt) .png.eps: diff --git a/doc/basic.texi b/doc/basic.texi index 05d72bc80f..6e43210bb8 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -450,7 +450,7 @@ Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. -Hello, this is @value{PACKAGE_NAME} (version @value{VERSION}) +Hello, this is @value{PACKAGE_NAME} (version @value{PACKAGE_VERSION}) @value{COPYRIGHT_STR} User Access Verification diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 8e0da12949..d6b07a270f 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -698,8 +698,11 @@ This command is deprecated and may be removed in a future release. Its use should be avoided. @end deffn -@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {} -@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {} +@c for some reason, using [all] here triggers a bug in texinfo... +@deffn {BGP} {neighbor @var{peer} next-hop-self} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} +@deffnx {BGP} {neighbor @var{peer} next-hop-self all} {} +@deffnx {BGP} {no neighbor @var{peer} next-hop-self all} {} This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword @code{all} is specified the modifiation is done diff --git a/doc/defines.texi.in b/doc/defines.texi.in index 0fadba964a..b2af89e40a 100644 --- a/doc/defines.texi.in +++ b/doc/defines.texi.in @@ -5,6 +5,8 @@ @set PACKAGE_NAME @PACKAGE_NAME@ @set PACKAGE_TARNAME @PACKAGE_TARNAME@ @set PACKAGE_STRING @PACKAGE_STRING@ +@set PACKAGE_URL @PACKAGE_URL@ +@set PACKAGE_VERSION @PACKAGE_VERSION@ @set AUTHORS Kunihiro Ishiguro, et al. @set COPYRIGHT_YEAR 1999-2005 @set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS} diff --git a/doc/frr.texi b/doc/frr.texi index b08bb6fd04..d268b4b981 100644 --- a/doc/frr.texi +++ b/doc/frr.texi @@ -7,13 +7,9 @@ @setfilename frr.info @c Set variables - sourced from defines.texi @include defines.texi -@settitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}} +@settitle @uref{@value{PACKAGE_URL},,@value{PACKAGE_NAME}} @c %**end of header -@c automake will automatically generate version.texi -@c and set EDITION, VERSION, UPDATED and UPDATED-MONTH -@include version.texi - @copying @value{COPYRIGHT_STR} @quotation @@ -44,21 +40,18 @@ approved by Kunihiro Ishiguro. @c @smallbook @ifinfo -This file documents the Frr Software Routing Suite which manages common -TCP/IP routing protocols. +This file documents the @uref{@value{PACKAGE_URL},,Frr Software Routing Suite} +which manages common TCP/IP routing protocols. -This is Edition @value{EDITION}, last updated @value{UPDATED} of -@cite{The Frr Manual}, for @uref{http://www.frrouting.org/,,@value{PACKAGE_NAME}} -Version @value{VERSION}. +This document was generated for version @value{PACKAGE_VERSION}. @insertcopying @end ifinfo @titlepage -@title @uref{http://www.frrouting.org,,Frr} +@title @uref{@value{PACKAGE_URL},,Frr} @subtitle A routing software package for TCP/IP networks -@subtitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}} @value{VERSION} -@subtitle @value{UPDATED-MONTH} +@subtitle @uref{@value{PACKAGE_URL},,@value{PACKAGE_NAME}} @value{PACKAGE_VERSION} @author @value{AUTHORS} @page @@ -72,9 +65,9 @@ Version @value{VERSION}. @node Top @top Frr -- With Virtual Network Control -@uref{http://www.frrouting.org,,Frr} is an advanced routing software package +@uref{@value{PACKAGE_URL},,Frr} is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual -for @value{PACKAGE_STRING}. @uref{http://www.frrouting.org,,Frr} is a fork of +for @value{PACKAGE_STRING}. @uref{@value{PACKAGE_URL},,Frr} is a fork of @uref{http://www.quagga.net,,Quagga}. @insertcopying diff --git a/doc/overview.texi b/doc/overview.texi index 7ecf3d95c3..c988e219b7 100644 --- a/doc/overview.texi +++ b/doc/overview.texi @@ -2,7 +2,7 @@ @chapter Overview @cindex Overview - @uref{http://www.frrouting.org,,Frr} is a routing software package that + @uref{@value{PACKAGE_URL},,Frr} is a routing software package that provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported RFCs}). Frr also supports special BGP Route Reflector and Route Server @@ -275,12 +275,12 @@ November 1995.} The official Frr web-site is located at: -@uref{http://www.frrouting.org/} +@uref{@value{PACKAGE_URL}} and contains further information, as well as links to additional resources. -@uref{http://www.frrouting.org/,Frr} is a fork of Quagga, whose +@uref{@value{PACKAGE_URL},Frr} is a fork of Quagga, whose web-site is located at: @uref{http://www.quagga.net/}. @@ -296,12 +296,12 @@ web-site is located at: There is a mailing list for discussions about Frr. If you have any comments or suggestions to Frr, please subscribe to: -@uref{http://lists.nox.tf/listinfo/frr-users}. +@uref{https://lists.frrouting.org/listinfo/frog}. -The @uref{http://www.frrouting.org/,,Frr} site has further information on +The @uref{@value{PACKAGE_URL},,Frr} site has further information on the available mailing lists, see: - @uref{http://lists.nox.tf/lists.php} + @uref{https://lists.frrouting.org/} @node Bug Reports @section Bug Reports diff --git a/doc/watchfrr.8.in b/doc/watchfrr.8.in index 82098e1b0d..782ac7b46e 100644 --- a/doc/watchfrr.8.in +++ b/doc/watchfrr.8.in @@ -20,59 +20,6 @@ daemon's VTY UNIX stream socket, and send echo commands to ensure the daemon responds. When the daemon crashes, EOF is received from the socket, so that watchfrr can react immediately. .PP -This program can run in one of the following 5 modes: -.TP -.B Mode 0: monitor -In this mode, the program serves as a monitor and reports status changes. -.IP -Example usage: watchfrr \-d zebra ospfd bgpd -.TP -.B Mode 1: global restart -In this mode, whenever a daemon hangs or crashes, the given command is used -to restart all watched daemons. -.IP -Example usage: watchfrr \-dz \e -.br --R '/sbin/service zebra restart; /sbin/service ospfd restart' \e -.br -zebra ospfd -.TP -.B Mode 2: individual daemon restart -In this mode, whenever a single daemon hangs or crashes, the given command -is used to restart this daemon only. -.IP -Example usage: watchfrr \-dz \-r '/sbin/service %s restart' \e -.br -zebra ospfd bgpd -.TP -.B Mode 3: phased zebra restart -In this mode, whenever a single daemon hangs or crashes, the given command -is used to restart this daemon only. The only exception is the zebra -daemon; in this case, the following steps are taken: (1) all other daemons -are stopped, (2) zebra is restarted, and (3) other daemons are started -again. -.IP -Example usage: watchfrr \-adz \-r '/sbin/service %s restart' \e -.br -\-s '/sbin/service %s start' \e -.br -\-k '/sbin/service %s stop' zebra ospfd bgpd -.TP -.B Mode 4: phased global restart for any failure -In this mode, whenever a single daemon hangs or crashes, the following -steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, -and (3) other daemons are started again. -.IP -Example usage: watchfrr \-Adz \-r '/sbin/service %s restart' \e -.br -\-s '/sbin/service %s start' \e -.br -\-k '/sbin/service %s stop' zebra ospfd bgpd -.PP -Important: It is believed that mode 2 (individual daemon restart) is not -safe, and mode 3 (phased zebra restart) may not be safe with certain -routing daemons. -.PP In order to avoid restarting the daemons in quick succession, you can supply the .B \-m @@ -87,6 +34,36 @@ the restart delay is set to the value of otherwise the interval is doubled (but capped at the value of .BR \-M ). .SH OPTIONS +The following 3 options specify scripts that +.B watchfrr +uses to perform start/stop/restart actions. These options are mandatory +unless the +.B --dry +option is used: +.TP +.BI \-s " command" "\fR, \fB\-\-start\-command " command +Supply a Bourne shell +.I command +to start a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BI \-k " command" "\fR, \fB\-\-kill\-command " command +Supply a Bourne shell +.I command +to stop a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.TP +.BI \-r " command" "\fR, \fB\-\-restart " command +Supply a Bourne shell +.I command +to restart a single daemon. The command string should contain the '%s' +placeholder to be substituted with the daemon name. +.PP +Other options: +.TP +.BI \-\-dry +Run watchfrr in "dry-run" mode, only monitoring the specified daemons but not +performing any start/stop/restart actions. .TP .BR \-d ", " \-\-daemon Run in daemon mode. When supplied, error messages are sent to Syslog @@ -97,10 +74,6 @@ Set the VTY socket .I directory (the default value is "/var/run/frr"). .TP -.BR \-e ", " \-\-no\-echo -Do not ping the daemons to test whether they respond. This option is -necessary if one or more daemons do not support the echo command. -.TP .BI \-l " level" "\fR, \fB\-\-loglevel " level Set the logging .I level @@ -131,68 +104,6 @@ Set the restart (kill) timeout in seconds (the default value is "20"). If any background jobs are still running after this period has elapsed, they will be killed. .TP -.BI \-r " command" "\fR, \fB\-\-restart " command -Supply a Bourne shell -.I command -to restart a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.IP -Note that -.B \-r -and -.B \-R -options are not compatible. -.TP -.BI \-s " command" "\fR, \fB\-\-start\-command " command -Supply a Bourne shell -.I command -to start a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.TP -.BI \-k " command" "\fR, \fB\-\-kill\-command " command -Supply a Bourne shell -.I command -to stop a single daemon. The command string should contain the '%s' -placeholder to be substituted with the daemon name. -.TP -.BR \-R ", " \-\-restart\-all -When one or more daemons are shut down, try to restart them using the -Bourne shell command supplied on the command line. -.IP -Note that -.B \-r -and -.B \-R -options are not compatible. -.TP -.BR \-z ", " \-\-unresponsive\-restart -When a daemon is in an unresponsive state, treat it as being shut down for -the restart purposes. -.TP -.BR \-a ", " \-\-all\-restart -When zebra hangs or crashes, restart all daemons taking the following -steps: (1) stop all other daemons, (2) restart zebra, and (3) start other -daemons again. -.IP -Note that this option also requires -.BR \-r , -.BR \-s , -and -.B \-k -options to be specified. -.TP -.BR \-A ", " \-\-always\-all\-restart -When any daemon (i.e., not just zebra) hangs or crashes, restart all -daemons taking the following steps: (1) stop all other daemons, (2) restart -zebra, and (3) start other daemons again. -.IP -Note that this option also requires -.BR \-r , -.BR \-s , -and -.B \-k -options to be specified. -.TP .BI \-p " filename" "\fR, \fB\-\-pid\-file " filename Set the process identifier .I filename @@ -204,9 +115,8 @@ When the supplied is found in any of the command line option arguments (i.e., .BR \-r , .BR \-s , -.BR \-k , or -.BR \-R ), +.BR \-k ), replace it with a space. .IP This is an ugly hack to circumvent problems with passing the command line @@ -217,6 +127,20 @@ Display the version information and exit. .TP .BR \-h ", " \-\-help Display the usage information and exit. +.SH PREVIOUS OPTIONS +Prior versions of \fBwatchfrr\fR supported some additional options that no +longer exist: +.IP +.BR \-a ,\ \-A ,\ \-e ,\ \-R ,\ \-z +.PP +The \fB-a\fR, \fB-A\fR and \fB-R\fR options were used to select alternate +monitoring modes that offered different patterns of restarting daemons. The +"correct" mode (phased restart) is now the default. The \fB-e\fR and \fB-z\fR +options used to disable some monitoring aspects, watchfrr now always has all +monitoring features enabled. +.PP +Removing these options should result in correct operation, if it does not +please file a bug report. .SH SEE ALSO .BR zebra (8), .BR bgpd (8), diff --git a/eigrpd/.gitignore b/eigrpd/.gitignore index cd46e50c6c..5b72399e72 100644 --- a/eigrpd/.gitignore +++ b/eigrpd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o *.a diff --git a/eigrpd/Makefile b/eigrpd/Makefile new file mode 100644 index 0000000000..b6d60764e9 --- /dev/null +++ b/eigrpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. eigrpd/eigrpd +%: ALWAYS + @$(MAKE) -s -C .. eigrpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/eigrpd/Makefile.am b/eigrpd/Makefile.am deleted file mode 100644 index 9ee792e552..0000000000 --- a/eigrpd/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = libeigrp.a -sbin_PROGRAMS = eigrpd - -libeigrp_a_SOURCES = \ - eigrpd.c eigrp_zebra.c \ - eigrp_interface.c eigrp_neighbor.c \ - eigrp_dump.c eigrp_vty.c \ - eigrp_network.c eigrp_packet.c \ - eigrp_topology.c eigrp_fsm.c \ - eigrp_hello.c eigrp_update.c \ - eigrp_query.c eigrp_reply.c \ - eigrp_snmp.c eigrp_siaquery.c \ - eigrp_siareply.c eigrp_filter.c \ - eigrp_memory.c - - -eigrpdheaderdir = $(pkgincludedir)/eigrpd - -eigrpdheader_HEADERS = \ - eigrp_topology.h eigrp_dump.h eigrpd.h - -noinst_HEADERS = \ - eigrp_const.h eigrp_structs.h \ - eigrp_macros.h eigrp_interface.h \ - eigrp_neighbor.h eigrp_network.h \ - eigrp_packet.h eigrp_memory.h \ - eigrp_zebra.h eigrp_vty.h \ - eigrp_snmp.h eigrp_filter.h \ - eigrp_fsm.h - -eigrpd_SOURCES = eigrp_main.c $(libeigrp_a_SOURCES) - -eigrpd_LDADD = ../lib/libfrr.la @LIBCAP@ - -EXTRA_DIST = EIGRP-MIB.txt - -examplesdir = $(exampledir) -dist_examples_DATA = eigrpd.conf.sample diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 15a8a71cf3..db5e38d422 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -616,5 +616,6 @@ void eigrp_debug_init() install_element(CONFIG_NODE, &show_debugging_eigrp_cmd); install_element(CONFIG_NODE, &debug_eigrp_packets_all_cmd); install_element(CONFIG_NODE, &no_debug_eigrp_packets_all_cmd); + install_element(CONFIG_NODE, &debug_eigrp_transmit_cmd); install_element(CONFIG_NODE, &no_debug_eigrp_transmit_cmd); } diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am new file mode 100644 index 0000000000..2c6b1e321b --- /dev/null +++ b/eigrpd/subdir.am @@ -0,0 +1,59 @@ +# +# eigrpd +# + +if EIGRPD +noinst_LIBRARIES += eigrpd/libeigrp.a +sbin_PROGRAMS += eigrpd/eigrpd +dist_examples_DATA += eigrpd/eigrpd.conf.sample +endif + +eigrpd_libeigrp_a_SOURCES = \ + eigrpd/eigrp_dump.c \ + eigrpd/eigrp_filter.c \ + eigrpd/eigrp_fsm.c \ + eigrpd/eigrp_hello.c \ + eigrpd/eigrp_interface.c \ + eigrpd/eigrp_memory.c \ + eigrpd/eigrp_neighbor.c \ + eigrpd/eigrp_network.c \ + eigrpd/eigrp_packet.c \ + eigrpd/eigrp_query.c \ + eigrpd/eigrp_reply.c \ + eigrpd/eigrp_siaquery.c \ + eigrpd/eigrp_siareply.c \ + eigrpd/eigrp_snmp.c \ + eigrpd/eigrp_topology.c \ + eigrpd/eigrp_update.c \ + eigrpd/eigrp_vty.c \ + eigrpd/eigrp_zebra.c \ + eigrpd/eigrpd.c \ + # end + +eigrpdheaderdir = $(pkgincludedir)/eigrpd +eigrpdheader_HEADERS = \ + eigrpd/eigrp_dump.h \ + eigrpd/eigrp_topology.h \ + eigrpd/eigrpd.h \ + # end + +noinst_HEADERS += \ + eigrpd/eigrp_const.h \ + eigrpd/eigrp_filter.h \ + eigrpd/eigrp_fsm.h \ + eigrpd/eigrp_interface.h \ + eigrpd/eigrp_macros.h \ + eigrpd/eigrp_memory.h \ + eigrpd/eigrp_neighbor.h \ + eigrpd/eigrp_network.h \ + eigrpd/eigrp_packet.h \ + eigrpd/eigrp_snmp.h \ + eigrpd/eigrp_structs.h \ + eigrpd/eigrp_vty.h \ + eigrpd/eigrp_zebra.h \ + # end + +eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c +eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la @LIBCAP@ + +EXTRA_DIST += eigrpd/EIGRP-MIB.txt diff --git a/fpm/subdir.am b/fpm/subdir.am index f81a84222c..795535596b 100644 --- a/fpm/subdir.am +++ b/fpm/subdir.am @@ -13,7 +13,6 @@ fpm_libfrrfpm_pb_la_SOURCES = \ if HAVE_PROTOBUF nodist_fpm_libfrrfpm_pb_la_SOURCES = fpm/fpm.pb-c.c -BUILT_SOURCES += fpm/fpm.pb-c.c CLEANFILES += \ fpm/fpm.pb-c.c \ fpm/fpm.pb-c.h \ diff --git a/isisd/.gitignore b/isisd/.gitignore index 5e8028c2a6..a882bbf675 100644 --- a/isisd/.gitignore +++ b/isisd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o isisd diff --git a/isisd/Makefile b/isisd/Makefile new file mode 100644 index 0000000000..db3b70eead --- /dev/null +++ b/isisd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. isisd/isisd +%: ALWAYS + @$(MAKE) -s -C .. isisd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/isisd/Makefile.am b/isisd/Makefile.am deleted file mode 100644 index dc3d3683a1..0000000000 --- a/isisd/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 -LIBS = @LIBS@ - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = libisis.a -sbin_PROGRAMS = isisd - -libisis_a_SOURCES = \ - isis_memory.c \ - isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ - isisd.c isis_misc.c isis_zebra.c isis_dr.c \ - isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ - isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ - isis_vty.c isis_mt.c \ - isis_tlvs.c - - -noinst_HEADERS = \ - isis_memory.h \ - isisd.h isis_pdu.h isis_adjacency.h isis_constants.h \ - isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ - isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ - iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ - isis_route.h isis_routemap.h isis_te.h isis_mt.h \ - isis_tlvs.h - -isisd_SOURCES = \ - isis_main.c $(libisis_a_SOURCES) \ - isis_bpf.c isis_dlpi.c isis_pfpacket.c - -isisd_LDADD = ../lib/libfrr.la @LIBCAP@ - -examplesdir = $(exampledir) -dist_examples_DATA = isisd.conf.sample diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index c872774da8..e8888a5f5b 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -609,8 +609,6 @@ void vty_out_timestr(struct vty *vty, time_t uptime) difftime -= uptime; tm = gmtime(&difftime); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 if (difftime < ONE_DAY_SECOND) vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/isisd/subdir.am b/isisd/subdir.am new file mode 100644 index 0000000000..6e49d4ec80 --- /dev/null +++ b/isisd/subdir.am @@ -0,0 +1,71 @@ +# +# isisd +# + +if ISISD +noinst_LIBRARIES += isisd/libisis.a +sbin_PROGRAMS += isisd/isisd +dist_examples_DATA += isisd/isisd.conf.sample +endif + +isisd_libisis_a_SOURCES = \ + isisd/dict.c \ + isisd/isis_adjacency.c \ + isisd/isis_circuit.c \ + isisd/isis_csm.c \ + isisd/isis_dr.c \ + isisd/isis_dynhn.c \ + isisd/isis_events.c \ + isisd/isis_flags.c \ + isisd/isis_lsp.c \ + isisd/isis_memory.c \ + isisd/isis_misc.c \ + isisd/isis_mt.c \ + isisd/isis_pdu.c \ + isisd/isis_redist.c \ + isisd/isis_route.c \ + isisd/isis_routemap.c \ + isisd/isis_spf.c \ + isisd/isis_te.c \ + isisd/isis_tlvs.c \ + isisd/isis_vty.c \ + isisd/isis_zebra.c \ + isisd/isisd.c \ + isisd/iso_checksum.c \ + # end + +noinst_HEADERS += \ + isisd/dict.h \ + isisd/isis_adjacency.h \ + isisd/isis_circuit.h \ + isisd/isis_common.h \ + isisd/isis_constants.h \ + isisd/isis_csm.h \ + isisd/isis_dr.h \ + isisd/isis_dynhn.h \ + isisd/isis_events.h \ + isisd/isis_flags.h \ + isisd/isis_lsp.h \ + isisd/isis_memory.h \ + isisd/isis_misc.h \ + isisd/isis_mt.h \ + isisd/isis_network.h \ + isisd/isis_pdu.h \ + isisd/isis_redist.h \ + isisd/isis_route.h \ + isisd/isis_routemap.h \ + isisd/isis_spf.h \ + isisd/isis_te.h \ + isisd/isis_tlvs.h \ + isisd/isis_zebra.h \ + isisd/isisd.h \ + isisd/iso_checksum.h \ + # end + +isisd_isisd_LDADD = isisd/libisis.a lib/libfrr.la @LIBCAP@ +isisd_isisd_SOURCES = \ + isisd/isis_bpf.c \ + isisd/isis_dlpi.c \ + isisd/isis_main.c \ + isisd/isis_pfpacket.c \ + # end diff --git a/ldpd/.gitignore b/ldpd/.gitignore index f52b227cb1..eee96c636f 100644 --- a/ldpd/.gitignore +++ b/ldpd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o ldpd diff --git a/ldpd/Makefile b/ldpd/Makefile new file mode 100644 index 0000000000..464e02cf51 --- /dev/null +++ b/ldpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ldpd/ldpd +%: ALWAYS + @$(MAKE) -s -C .. ldpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am deleted file mode 100644 index de9b07ed4c..0000000000 --- a/ldpd/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -include ../common.am - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = libldp.a -sbin_PROGRAMS = ldpd - -libldp_a_SOURCES = \ - accept.c address.c adjacency.c control.c hello.c init.c interface.c \ - keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \ - ldpe.c log.c logmsg.c neighbor.c notification.c packet.c pfkey.c \ - socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \ - ldp_debug.c ldp_zebra.c - -ldp_vty_cmds.o: ldp_vty_cmds_clippy.c - -noinst_HEADERS = \ - control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h - -ldpd_SOURCES = ldpd.c -ldpd_LDADD = libldp.a ../lib/libfrr.la @LIBCAP@ - -examplesdir = $(exampledir) -dist_examples_DATA = ldpd.conf.sample diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index f15461d3d2..9bad503b9c 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -235,6 +235,7 @@ void l2vpn_pw_init(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_reset(pw); @@ -242,16 +243,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw) lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0, (void *)pw); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw)); } void l2vpn_pw_exit(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_fec(pw, &fec); lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw)); } static void @@ -269,7 +277,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw) { pw->remote_group = 0; pw->remote_mtu = 0; - pw->remote_status = 0; + pw->local_status = PW_FORWARDING; + pw->remote_status = PW_NOT_FORWARDING; if (pw->flags & F_PW_CWORD_CONF) pw->flags |= F_PW_CWORD; @@ -475,6 +484,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) } } +int +l2vpn_pw_status_update(struct zapi_pw_status *zpw) +{ + struct l2vpn *l2vpn; + struct l2vpn_pw *pw = NULL; + struct lde_nbr *ln; + struct fec fec; + uint32_t local_status; + + RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) { + pw = l2vpn_pw_find(l2vpn, zpw->ifname); + if (pw) + break; + } + if (!pw) { + log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname); + return (1); + } + + if (zpw->status == PW_STATUS_UP) + local_status = PW_FORWARDING; + else + local_status = PW_NOT_FORWARDING; + + /* local status didn't change */ + if (pw->local_status == local_status) + return (0); + pw->local_status = local_status; + + /* notify remote peer about the status update */ + ln = lde_nbr_find_by_lsrid(pw->lsr_id); + if (ln == NULL) + return (0); + l2vpn_pw_fec(pw, &fec); + if (pw->flags & F_PW_STATUSTLV) + l2vpn_send_pw_status(ln, local_status, &fec); + else { + struct fec_node *fn; + fn = (struct fec_node *)fec_find(&ft, &fec); + if (fn) { + if (pw->local_status == PW_FORWARDING) + lde_send_labelmapping(ln, fn, 1); + else + lde_send_labelwithdraw(ln, fn, NULL, NULL); + } + } + + return (0); +} + void l2vpn_pw_ctl(pid_t pid) { @@ -491,7 +550,9 @@ l2vpn_pw_ctl(pid_t pid) sizeof(pwctl.ifname)); pwctl.pwid = pw->pwid; pwctl.lsr_id = pw->lsr_id; - pwctl.status = pw->flags & F_PW_STATUS_UP; + if (pw->local_status == PW_FORWARDING && + pw->remote_status == PW_FORWARDING) + pwctl.status = 1; lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, pid, &pwctl, sizeof(pwctl)); diff --git a/ldpd/lde.c b/ldpd/lde.c index 11fcbfa46d..4460b424d2 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -165,6 +165,7 @@ lde_init(struct ldpd_init *init) /* drop privileges */ lde_privs.user = init->user; lde_privs.group = init->group; + zprivs_preinit(&lde_privs); zprivs_init(&lde_privs); /* start the LIB garbage collector */ @@ -474,6 +475,15 @@ lde_dispatch_parent(struct thread *thread) } } break; + case IMSG_PW_UPDATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct zapi_pw_status)) + fatalx("PW_UPDATE imsg with wrong len"); + + if (l2vpn_pw_status_update(imsg.data) != 0) + log_warnx("%s: error updating PW status", + __func__); + break; case IMSG_NETWORK_ADD: case IMSG_NETWORK_UPDATE: if (imsg.hdr.len != IMSG_HEADER_SIZE + @@ -714,8 +724,8 @@ lde_update_label(struct fec_node *fn) void lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) { - struct kroute kr; - struct kpw kpw; + struct kroute kr; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -753,19 +763,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) return; pw = (struct l2vpn_pw *) fn->data; - pw->flags |= F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw)); break; } } @@ -774,7 +775,7 @@ void lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) { struct kroute kr; - struct kpw kpw; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -808,21 +809,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; - if (!(pw->flags & F_PW_STATUS_UP)) - return; - pw->flags &= ~F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw)); break; } } @@ -903,8 +893,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw) { - if (!fec_find(&ln->sent_map_pending, &fn->fec)) + if (!fec_find(&ln->sent_map_pending, &fn->fec)) { + debug_evt("%s: FEC %s: scheduling to send label " + "mapping later (waiting for pending label release)", + __func__, log_fec(&fn->fec)); lde_map_pending_add(ln, fn); + } return; } @@ -950,8 +944,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) map.flags |= F_MAP_PW_CWORD; if (pw->flags & F_PW_STATUSTLV) { map.flags |= F_MAP_PW_STATUS; - /* VPLS are always up */ - map.pw_status = PW_FORWARDING; + map.pw_status = pw->local_status; } break; } diff --git a/ldpd/lde.h b/ldpd/lde.h index 1cce483832..43f1d36481 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); void l2vpn_recv_pw_status_wcard(struct lde_nbr *, struct notify_msg *); +int l2vpn_pw_status_update(struct zapi_pw_status *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index edf686537f..c56b7e33d0 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -396,8 +396,7 @@ lde_kernel_update(struct fec *fec) lde_gc_start_timer(); } else { fn->local_label = lde_update_label(fn); - if (fn->local_label != NO_LABEL && - RB_EMPTY(lde_map_head, &fn->upstream)) + if (fn->local_label != NO_LABEL) /* FEC.1: perform lsr label distribution procedure */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelmapping(ln, fn, 1); @@ -531,6 +530,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) pw->remote_mtu = map->fec.pwid.ifmtu; if (map->flags & F_MAP_PW_STATUS) pw->remote_status = map->pw_status; + else + pw->remote_status = PW_FORWARDING; fnh->remote_label = map->label; if (l2vpn_pw_ok(pw, fnh)) lde_send_change_klabel(fn, fnh); @@ -774,6 +775,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) pw = (struct l2vpn_pw *) fn->data; if (pw == NULL) continue; + pw->remote_status = PW_NOT_FORWARDING; break; default: break; @@ -802,6 +804,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; struct lde_map *me; + struct l2vpn_pw *pw; /* LWd.2: send label release */ lde_send_labelrelease(ln, NULL, map, map->label); @@ -825,6 +828,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) case FEC_TYPE_PWID: if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) continue; + pw = (struct l2vpn_pw *) fn->data; + if (pw) + pw->remote_status = PW_NOT_FORWARDING; break; default: break; diff --git a/ldpd/ldp.h b/ldpd/ldp.h index c2b64d20c6..cac3da7c55 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -285,9 +285,6 @@ struct address_list_tlv { #define MAP_TYPE_GENPWID 0x81 #define CONTROL_WORD_FLAG 0x8000 -#define PW_TYPE_ETHERNET_TAGGED 0x0004 -#define PW_TYPE_ETHERNET 0x0005 -#define PW_TYPE_WILDCARD 0x7FFF #define DEFAULT_PW_TYPE PW_TYPE_ETHERNET #define PW_TWCARD_RESERVED_BIT 0x8000 diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index efc6bd5279..ecc7db8f2e 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -52,6 +52,8 @@ static int ldp_interface_address_delete(int, struct zclient *, zebra_size_t, vrf_id_t); static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t, vrf_id_t); +static int ldp_zebra_read_pw_status_update(int, struct zclient *, + zebra_size_t, vrf_id_t); static void ldp_zebra_connected(struct zclient *); static struct zclient *zclient; @@ -92,6 +94,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) } } +void +pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) +{ + memset(zpw, 0, sizeof(*zpw)); + strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname)); + zpw->ifindex = pw->ifindex; + zpw->type = pw->l2vpn->pw_type; + zpw->af = pw->af; + zpw->nexthop.ipv6 = pw->addr.v6; + zpw->local_label = NO_LABEL; + zpw->remote_label = NO_LABEL; + if (pw->flags & F_PW_CWORD) + zpw->flags = F_PSEUDOWIRE_CWORD; + zpw->data.ldp.lsr_id = pw->lsr_id; + zpw->data.ldp.pwid = pw->pwid; + strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name, + sizeof(zpw->data.ldp.vpn_name)); +} + static int zebra_send_mpls_labels(int cmd, struct kroute *kr) { @@ -152,17 +173,40 @@ kr_delete(struct kroute *kr) } int -kmpw_set(struct kpw *kpw) +kmpw_add(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (add)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw)); } int -kmpw_unset(struct kpw *kpw) +kmpw_del(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (del)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw)); +} + +int +kmpw_set(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop), + zpw->local_label, zpw->remote_label); + + return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw)); +} + +int +kmpw_unset(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s (unset)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw)); } void @@ -464,6 +508,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, return (0); } +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +static int +ldp_zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct zapi_pw_status zpw; + + zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw); + + debug_zebra_in("pseudowire %s status %s", zpw.ifname, + (zpw.status == PW_STATUS_UP) ? "up" : "down"); + + main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw)); + + return (0); +} + static void ldp_zebra_connected(struct zclient *zclient) { @@ -494,6 +557,7 @@ ldp_zebra_init(struct thread_master *master) zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; + zclient->pw_status_update = ldp_zebra_read_pw_status_update; } void diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index abf584484e..80af2b14e5 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -578,21 +578,36 @@ main_dispatch_lde(struct thread *thread) if (kr_delete(imsg.data)) log_warnx("%s: error deleting route", __func__); break; - case IMSG_KPWLABEL_CHANGE: + case IMSG_KPW_ADD: + case IMSG_KPW_DELETE: + case IMSG_KPW_SET: + case IMSG_KPW_UNSET: if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) + sizeof(struct zapi_pw)) fatalx("invalid size of IMSG_KPWLABEL_CHANGE"); - if (kmpw_set(imsg.data)) - log_warnx("%s: error changing pseudowire", - __func__); - break; - case IMSG_KPWLABEL_DELETE: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) - fatalx("invalid size of IMSG_KPWLABEL_DELETE"); - if (kmpw_unset(imsg.data)) - log_warnx("%s: error unsetting pseudowire", - __func__); + + switch (imsg.hdr.type) { + case IMSG_KPW_ADD: + if (kmpw_add(imsg.data)) + log_warnx("%s: error adding " + "pseudowire", __func__); + break; + case IMSG_KPW_DELETE: + if (kmpw_del(imsg.data)) + log_warnx("%s: error deleting " + "pseudowire", __func__); + break; + case IMSG_KPW_SET: + if (kmpw_set(imsg.data)) + log_warnx("%s: error setting " + "pseudowire", __func__); + break; + case IMSG_KPW_UNSET: + if (kmpw_unset(imsg.data)) + log_warnx("%s: error unsetting " + "pseudowire", __func__); + break; + } break; case IMSG_ACL_CHECK: if (imsg.hdr.len != IMSG_HEADER_SIZE + diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 00d2627f11..31d0bc69b1 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -30,6 +30,8 @@ #include "prefix.h" #include "filter.h" #include "vty.h" +#include "pw.h" +#include "zclient.h" #include "ldp.h" @@ -44,7 +46,6 @@ #define LDPD_OPT_NOACTION 0x00000004 #define TCP_MD5_KEY_LEN 80 -#define L2VPN_NAME_LEN 32 #define RT_BUF_SIZE 16384 #define MAX_RTSOCK_BUF 128 * 1024 @@ -102,8 +103,10 @@ enum imsg_type { IMSG_CTL_LOG_VERBOSE, IMSG_KLABEL_CHANGE, IMSG_KLABEL_DELETE, - IMSG_KPWLABEL_CHANGE, - IMSG_KPWLABEL_DELETE, + IMSG_KPW_ADD, + IMSG_KPW_DELETE, + IMSG_KPW_SET, + IMSG_KPW_UNSET, IMSG_IFSTATUS, IMSG_NEWADDR, IMSG_DELADDR, @@ -147,7 +150,8 @@ enum imsg_type { IMSG_DEBUG_UPDATE, IMSG_LOG, IMSG_ACL_CHECK, - IMSG_INIT + IMSG_INIT, + IMSG_PW_UPDATE }; struct ldpd_init { @@ -407,6 +411,7 @@ struct l2vpn_pw { unsigned int ifindex; uint32_t remote_group; uint16_t remote_mtu; + uint32_t local_status; uint32_t remote_status; uint8_t flags; QOBJ_FIELDS @@ -418,8 +423,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw) #define F_PW_STATUSTLV 0x02 /* status tlv negotiated */ #define F_PW_CWORD_CONF 0x04 /* control word configured */ #define F_PW_CWORD 0x08 /* control word negotiated */ -#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */ -#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */ +#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */ struct l2vpn { RB_ENTRY(l2vpn) entry; @@ -542,16 +546,6 @@ struct kroute { uint16_t flags; }; -struct kpw { - unsigned short ifindex; - int pw_type; - int af; - union ldpd_addr nexthop; - uint32_t local_label; - uint32_t remote_label; - uint8_t flags; -}; - struct kaddr { char ifname[IF_NAMESIZE]; unsigned short ifindex; @@ -668,11 +662,14 @@ struct ldpd_conf *parse_config(char *); int cmdline_symset(char *); /* kroute.c */ +void pw2zpw(struct l2vpn_pw *, struct zapi_pw *); void kif_redistribute(const char *); int kr_change(struct kroute *); int kr_delete(struct kroute *); -int kmpw_set(struct kpw *); -int kmpw_unset(struct kpw *); +int kmpw_add(struct zapi_pw *); +int kmpw_del(struct zapi_pw *); +int kmpw_set(struct zapi_pw *); +int kmpw_unset(struct zapi_pw *); /* util.c */ uint8_t mask2prefixlen(in_addr_t); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index b2f9fdce55..1c0a8bdc84 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -142,6 +142,7 @@ ldpe_init(struct ldpd_init *init) /* drop privileges */ ldpe_privs.user = init->user; ldpe_privs.group = init->group; + zprivs_preinit(&ldpe_privs); zprivs_init(&ldpe_privs); /* listen on ldpd control socket */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index f8d4b5f5fd..39860a1859 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -289,6 +289,8 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, void nbr_del(struct nbr *nbr) { + struct adj *adj; + log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); @@ -314,6 +316,11 @@ nbr_del(struct nbr *nbr) mapping_list_clr(&nbr->release_list); mapping_list_clr(&nbr->abortreq_list); + while ((adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree)) != NULL) { + adj->nbr = NULL; + RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj); + } + if (nbr->peerid) RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr); RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr); diff --git a/ldpd/subdir.am b/ldpd/subdir.am new file mode 100644 index 0000000000..db71cee618 --- /dev/null +++ b/ldpd/subdir.am @@ -0,0 +1,55 @@ +# +# ldpd +# + +if LDPD +noinst_LIBRARIES += ldpd/libldp.a +sbin_PROGRAMS += ldpd/ldpd +dist_examples_DATA += ldpd/ldpd.conf.sample +endif + +ldpd_libldp_a_SOURCES = \ + ldpd/accept.c \ + ldpd/address.c \ + ldpd/adjacency.c \ + ldpd/control.c \ + ldpd/hello.c \ + ldpd/init.c \ + ldpd/interface.c \ + ldpd/keepalive.c \ + ldpd/l2vpn.c \ + ldpd/labelmapping.c \ + ldpd/lde.c \ + ldpd/lde_lib.c \ + ldpd/ldp_debug.c \ + ldpd/ldp_vty_cmds.c \ + ldpd/ldp_vty_conf.c \ + ldpd/ldp_vty_exec.c \ + ldpd/ldp_zebra.c \ + ldpd/ldpd.c \ + ldpd/ldpe.c \ + ldpd/log.c \ + ldpd/logmsg.c \ + ldpd/neighbor.c \ + ldpd/notification.c \ + ldpd/packet.c \ + ldpd/pfkey.c \ + ldpd/socket.c \ + ldpd/util.c \ + # end + +ldpd/ldp_vty_cmds.$(OBJEXT): ldpd/ldp_vty_cmds_clippy.c + +noinst_HEADERS += \ + ldpd/control.h \ + ldpd/lde.h \ + ldpd/ldp.h \ + ldpd/ldp_debug.h \ + ldpd/ldp_vty.h \ + ldpd/ldpd.h \ + ldpd/ldpe.h \ + ldpd/log.h \ + # end + +ldpd_ldpd_SOURCES = ldpd/ldpd.c +ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la @LIBCAP@ diff --git a/lib/command.c b/lib/command.c index f28a55ec6d..09ffa6ce56 100644 --- a/lib/command.c +++ b/lib/command.c @@ -110,6 +110,7 @@ const char *node_names[] = { "forwarding", // FORWARDING_NODE, "protocol", // PROTOCOL_NODE, "mpls", // MPLS_NODE, + "pw", // PW_NODE, "vty", // VTY_NODE, "link-params", // LINK_PARAMS_NODE, "bgp evpn vni", // BGP_EVPN_VNI_NODE, @@ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty) vty_config_unlock(vty); break; case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: @@ -1338,6 +1340,7 @@ DEFUN (config_end, break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: diff --git a/lib/command.h b/lib/command.h index 5184b53a9f..d0c9f0eaf9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -132,6 +132,7 @@ enum node_type { FORWARDING_NODE, /* IP forwarding node. */ PROTOCOL_NODE, /* protocol filtering node */ MPLS_NODE, /* MPLS config node */ + PW_NODE, /* Pseudowire config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ diff --git a/lib/gitversion.pl b/lib/gitversion.pl index 8ddd9ffa55..2718046d0b 100644 --- a/lib/gitversion.pl +++ b/lib/gitversion.pl @@ -4,7 +4,7 @@ use strict; my $dir = shift; chdir $dir || die "$dir: $!\n"; -my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; +my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index c236d2c7be..89b0993d1d 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -26,10 +26,11 @@ #include "command.h" #include "memory_vty.h" -static void vty_do_exit(void) +static void vty_do_exit(int isexit) { printf("\nend.\n"); - exit(0); + if (!isexit) + exit(0); } struct thread_master *master; diff --git a/lib/libfrr.c b/lib/libfrr.c index c901dcc229..e5573da900 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -21,8 +21,12 @@ #include #include +#include +#include + #include "libfrr.h" #include "getopt.h" +#include "privs.h" #include "vty.h" #include "command.h" #include "version.h" @@ -30,6 +34,7 @@ #include "zclient.h" #include "log_int.h" #include "module.h" +#include "network.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) @@ -93,12 +98,15 @@ static const struct option lo_cfg_pid_dry[] = { {"pid_file", required_argument, NULL, 'i'}, {"config_file", required_argument, NULL, 'f'}, {"dryrun", no_argument, NULL, 'C'}, + {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:C", + "f:i:Ct", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" - " -C, --dryrun Check configuration for validity and exit\n", + " -C, --dryrun Check configuration for validity and exit\n" + " -t, --terminal Open terminal session on stdio\n" + " -d -t Daemonize after terminal session ends\n", lo_cfg_pid_dry}; @@ -344,6 +352,11 @@ static int frr_opt(int opt) return 1; di->dryrun = 1; break; + case 't': + if (di->flags & FRR_NO_CFG_PID_DRY) + return 1; + di->terminal = 1; + break; case 'z': if (di->flags & FRR_NO_ZCLIENT) return 1; @@ -434,6 +447,49 @@ int frr_getopt(int argc, char *const argv[], int *longindex) return opt; } +static void frr_mkdir(const char *path, bool strip) +{ + char buf[256]; + mode_t prev; + int ret; + struct zprivs_ids_t ids; + + if (strip) { + char *slash = strrchr(path, '/'); + size_t plen; + if (!slash) + return; + plen = slash - path; + if (plen > sizeof(buf) - 1) + return; + memcpy(buf, path, plen); + buf[plen] = '\0'; + path = buf; + } + + /* o+rx (..5) is needed for the frrvty group to work properly; + * without it, users in the frrvty group can't access the vty sockets. + */ + prev = umask(0022); + ret = mkdir(path, 0755); + umask(prev); + + if (ret != 0) { + /* if EEXIST, return without touching the permissions, + * so user-set custom permissions are left in place + */ + if (errno == EEXIST) + return; + + zlog_warn("failed to mkdir \"%s\": %s", path, strerror(errno)); + return; + } + + zprivs_get_ids(&ids); + if (chown(path, ids.uid_normal, ids.gid_normal)) + zlog_warn("failed to chown \"%s\": %s", path, strerror(errno)); +} + static struct thread_master *master; struct thread_master *frr_init(void) { @@ -449,6 +505,8 @@ struct thread_master *frr_init(void) snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", di->logname, di->instance); + zprivs_preinit(di->privs); + openzlog(di->progname, di->logname, di->instance, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); #if defined(HAVE_CUMULUS) @@ -462,6 +520,16 @@ struct thread_master *frr_init(void) exit(1); } + /* don't mkdir these as root... */ + if (!(di->flags & FRR_NO_PRIVSEP)) { + if (!di->pid_file || !di->vty_path) + frr_mkdir(frr_vtydir, false); + if (di->pid_file) + frr_mkdir(di->pid_file, true); + if (di->vty_path) + frr_mkdir(di->vty_path, true); + } + frrmod_init(di->module); while (modules) { modules = (oc = modules)->next; @@ -488,6 +556,134 @@ struct thread_master *frr_init(void) return master; } +static int rcvd_signal = 0; + +static void rcv_signal(int signum) +{ + rcvd_signal = signum; + /* poll() is interrupted by the signal; handled below */ +} + +static void frr_daemon_wait(int fd) +{ + struct pollfd pfd[1]; + int ret; + pid_t exitpid; + int exitstat; + sigset_t sigs, prevsigs; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGTSTP); + sigaddset(&sigs, SIGQUIT); + sigaddset(&sigs, SIGINT); + sigprocmask(SIG_BLOCK, &sigs, &prevsigs); + + struct sigaction sa = { + .sa_handler = rcv_signal, .sa_flags = SA_RESETHAND, + }; + sigemptyset(&sa.sa_mask); + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + do { + char buf[1]; + ssize_t nrecv; + + pfd[0].fd = fd; + pfd[0].events = POLLIN; + + rcvd_signal = 0; + +#if defined(HAVE_PPOLL) + ret = ppoll(pfd, 1, NULL, &prevsigs); +#elif defined(HAVE_POLLTS) + ret = pollts(pfd, 1, NULL, &prevsigs); +#else + /* racy -- only used on FreeBSD 9 */ + sigset_t tmpsigs; + sigprocmask(SIG_SETMASK, &prevsigs, &tmpsigs); + ret = poll(pfd, 1, -1); + sigprocmask(SIG_SETMASK, &tmpsigs, NULL); +#endif + if (ret < 0 && errno != EINTR && errno != EAGAIN) { + perror("poll()"); + exit(1); + } + switch (rcvd_signal) { + case SIGTSTP: + send(fd, "S", 1, 0); + do { + nrecv = recv(fd, buf, sizeof(buf), 0); + } while (nrecv == -1 + && (errno == EINTR || errno == EAGAIN)); + + raise(SIGTSTP); + sigaction(SIGTSTP, &sa, NULL); + send(fd, "R", 1, 0); + break; + case SIGINT: + send(fd, "I", 1, 0); + break; + case SIGQUIT: + send(fd, "Q", 1, 0); + break; + } + } while (ret <= 0); + + exitpid = waitpid(-1, &exitstat, WNOHANG); + if (exitpid == 0) + /* child successfully went to main loop & closed socket */ + exit(0); + + /* child failed one way or another ... */ + if (WIFEXITED(exitstat)) + fprintf(stderr, "%s failed to start, exited %d\n", di->name, + WEXITSTATUS(exitstat)); + else if (WIFSIGNALED(exitstat)) + fprintf(stderr, "%s crashed in startup, signal %d\n", di->name, + WTERMSIG(exitstat)); + else + fprintf(stderr, "%s failed to start, unknown problem\n", + di->name); + exit(1); +} + +static int daemon_ctl_sock = -1; + +static void frr_daemonize(void) +{ + int fds[2]; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { + perror("socketpair() for daemon control"); + exit(1); + } + set_cloexec(fds[0]); + set_cloexec(fds[1]); + + pid = fork(); + if (pid < 0) { + perror("fork()"); + exit(1); + } + if (pid == 0) { + /* child */ + close(fds[0]); + if (setsid() < 0) { + perror("setsid()"); + exit(1); + } + + daemon_ctl_sock = fds[1]; + return; + } + + close(fds[1]); + frr_daemon_wait(fds[0]); +} + void frr_config_fork(void) { hook_call(frr_late_init, master); @@ -506,11 +702,8 @@ void frr_config_fork(void) if (di->dryrun) exit(0); - /* Daemonize. */ - if (di->daemon_mode && daemon(0, 0) < 0) { - zlog_err("Zebra daemon failed: %s", strerror(errno)); - exit(1); - } + if (di->daemon_mode || di->terminal) + frr_daemonize(); if (!di->pid_file) di->pid_file = pidfile_default; @@ -538,6 +731,67 @@ void frr_vty_serv(void) vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path); } +static void frr_terminal_close(int isexit) +{ + if (daemon_ctl_sock != -1) { + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + if (!di->daemon_mode || isexit) { + printf("\n%s exiting\n", di->name); + if (!isexit) + raise(SIGINT); + return; + } else { + printf("\n%s daemonizing\n", di->name); + fflush(stdout); + } + + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); +} + +static struct thread *daemon_ctl_thread = NULL; + +static int frr_daemon_ctl(struct thread *t) +{ + char buf[1]; + ssize_t nr; + + nr = recv(daemon_ctl_sock, buf, sizeof(buf), 0); + if (nr < 0 && (errno == EINTR || errno == EAGAIN)) + goto out; + if (nr <= 0) + return 0; + + switch (buf[0]) { + case 'S': /* SIGTSTP */ + vty_stdio_suspend(); + send(daemon_ctl_sock, "s", 1, 0); + break; + case 'R': /* SIGTCNT [implicit] */ + vty_stdio_resume(); + break; + case 'I': /* SIGINT */ + di->daemon_mode = false; + raise(SIGINT); + break; + case 'Q': /* SIGQUIT */ + di->daemon_mode = true; + vty_stdio_close(); + break; + } + +out: + thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock, + &daemon_ctl_thread); + return 0; +} + void frr_run(struct thread_master *master) { char instanceinfo[64] = ""; @@ -551,6 +805,28 @@ void frr_run(struct thread_master *master) zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION, instanceinfo, di->vty_port, di->startinfo); + if (di->terminal) { + vty_stdio(frr_terminal_close); + if (daemon_ctl_sock != -1) { + set_nonblocking(daemon_ctl_sock); + thread_add_read(master, frr_daemon_ctl, NULL, + daemon_ctl_sock, &daemon_ctl_thread); + } + } else { + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); + + if (daemon_ctl_sock != -1) + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + /* end fixed stderr startup logging */ + zlog_startup_stderr = false; + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); diff --git a/lib/libfrr.h b/lib/libfrr.h index 23516150ee..1710fc9a84 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -49,6 +49,7 @@ struct frr_daemon_info { char *vty_sock_path; bool dryrun; bool daemon_mode; + bool terminal; const char *config_file; const char *pid_file; const char *vty_path; diff --git a/lib/libospf.h b/lib/libospf.h index c9483a4c65..45aedb6a7d 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -34,7 +34,7 @@ /* Architectual Constants */ #ifdef DEBUG -#define OSPF_LS_REFRESH_TIME 60 +#define OSPF_LS_REFRESH_TIME 120 #else #define OSPF_LS_REFRESH_TIME 1800 #endif diff --git a/lib/log.c b/lib/log.c index 5adb06d28c..49351a0656 100644 --- a/lib/log.c +++ b/lib/log.c @@ -41,6 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; +bool zlog_startup_stderr = true; const char *zlog_priority[] = { "emergencies", "alerts", "critical", "errors", "warnings", @@ -172,6 +173,25 @@ static void time_print(FILE *fp, struct timestamp_control *ctl) } +static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, + const char *proto_str, int record_priority, + int priority, FILE *fp, const char *format, + va_list args) +{ + va_list ac; + + time_print(fp, tsctl); + if (record_priority) + fprintf(fp, "%s: ", zlog_priority[priority]); + + fprintf(fp, "%s", proto_str); + va_copy(ac, args); + vfprintf(fp, format, ac); + va_end(ac); + fprintf(fp, "\n"); + fflush(fp); +} + /* va_list version of zlog. */ void vzlog(int priority, const char *format, va_list args) { @@ -210,32 +230,21 @@ void vzlog(int priority, const char *format, va_list args) sprintf(proto_str, "%s: ", zl->protoname); /* File output. */ - if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) { - va_list ac; - time_print(zl->fp, &tsctl); - if (zl->record_priority) - fprintf(zl->fp, "%s: ", zlog_priority[priority]); - fprintf(zl->fp, "%s", proto_str); - va_copy(ac, args); - vfprintf(zl->fp, format, ac); - va_end(ac); - fprintf(zl->fp, "\n"); - fflush(zl->fp); - } + if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, zl->fp, format, args); - /* stdout output. */ - if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) { - va_list ac; - time_print(stdout, &tsctl); - if (zl->record_priority) - fprintf(stdout, "%s: ", zlog_priority[priority]); - fprintf(stdout, "%s", proto_str); - va_copy(ac, args); - vfprintf(stdout, format, ac); - va_end(ac); - fprintf(stdout, "\n"); - fflush(stdout); - } + /* fixed-config logging to stderr while we're stating up & haven't + * daemonized / reached mainloop yet + * + * note the "else" on stdout output -- we don't want to print the same + * message to both stderr and stdout. */ + if (zlog_startup_stderr && priority <= LOG_WARNING) + vzlog_file(zl, &tsctl, proto_str, 1, + priority, stderr, format, args); + else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, stdout, format, args); /* Terminal monitor. */ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) @@ -916,6 +925,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_MACIP_DEL), DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD), DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL), + DESC_ENTRY(ZEBRA_PW_ADD), + DESC_ENTRY(ZEBRA_PW_DELETE), + DESC_ENTRY(ZEBRA_PW_SET), + DESC_ENTRY(ZEBRA_PW_UNSET), + DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE), }; #undef DESC_ENTRY diff --git a/lib/log.h b/lib/log.h index d872ce56d6..07eb6d5bd5 100644 --- a/lib/log.h +++ b/lib/log.h @@ -24,6 +24,7 @@ #include #include +#include #include /* Here is some guidance on logging levels to use: @@ -54,6 +55,8 @@ typedef enum { } zlog_dest_t; #define ZLOG_NUM_DESTS (ZLOG_DEST_FILE+1) +extern bool zlog_startup_stderr; + /* Message structure. */ struct message { int key; diff --git a/lib/monotime.h b/lib/monotime.h index 7bd3386498..8e50c1874a 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -49,6 +49,10 @@ static inline time_t monotime(struct timeval *tvo) return ts.tv_sec; } +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 +#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 + /* the following two return microseconds, not time_t! * * also, they're negative forms of each other, but having both makes the diff --git a/lib/privs.c b/lib/privs.c index c971596117..eda3fb02d4 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -696,13 +696,10 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups, } #endif /* HAVE_GETGROUPLIST */ -void zprivs_init(struct zebra_privs_t *zprivs) +void zprivs_preinit(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; - gid_t groups[NGROUPS_MAX]; - int i, ngroups = 0; - int found = 0; if (!zprivs) { fprintf(stderr, "zprivs_init: called with NULL arg!\n"); @@ -751,6 +748,18 @@ void zprivs_init(struct zebra_privs_t *zprivs) zprivs_state.zgid = grentry->gr_gid; } +} + +void zprivs_init(struct zebra_privs_t *zprivs) +{ + gid_t groups[NGROUPS_MAX]; + int i, ngroups = 0; + int found = 0; + + /* NULL privs */ + if (!(zprivs->user || zprivs->group || zprivs->cap_num_p + || zprivs->cap_num_i)) + return; if (zprivs->user) { ngroups = sizeof(groups); diff --git a/lib/privs.h b/lib/privs.h index c18fe78add..7fe59328b2 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -74,6 +74,7 @@ struct zprivs_ids_t { }; /* initialise zebra privileges */ +extern void zprivs_preinit(struct zebra_privs_t *zprivs); extern void zprivs_init(struct zebra_privs_t *zprivs); /* drop all and terminate privileges */ extern void zprivs_terminate(struct zebra_privs_t *); diff --git a/lib/pw.h b/lib/pw.h new file mode 100644 index 0000000000..2cfaa47e5d --- /dev/null +++ b/lib/pw.h @@ -0,0 +1,52 @@ +/* Pseudowire definitions + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _FRR_PW_H +#define _FRR_PW_H + +/* L2VPN name length. */ +#define L2VPN_NAME_LEN 32 + +/* Pseudowire type - LDP and BGP use the same values. */ +#define PW_TYPE_ETHERNET_TAGGED 0x0004 /* RFC 4446 */ +#define PW_TYPE_ETHERNET 0x0005 /* RFC 4446 */ +#define PW_TYPE_WILDCARD 0x7FFF /* RFC 4863, RFC 6668 */ + +/* Pseudowire flags. */ +#define F_PSEUDOWIRE_CWORD 0x01 + +/* Pseudowire status. */ +#define PW_STATUS_DOWN 0 +#define PW_STATUS_UP 1 + +/* + * Protocol-specific information about the pseudowire. + */ +union pw_protocol_fields { + struct { + struct in_addr lsr_id; + uint32_t pwid; + char vpn_name[L2VPN_NAME_LEN]; + } ldp; + struct { + /* TODO */ + } bgp; +}; + +#endif /* _FRR_PW_H */ diff --git a/lib/subdir.am b/lib/subdir.am index 28a4ce5579..6a62cbb678 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -123,8 +123,8 @@ pkginclude_HEADERS += \ lib/prefix.h \ lib/privs.h \ lib/ptm_lib.h \ + lib/pw.h \ lib/qobj.h \ - lib/route_types.h \ lib/routemap.h \ lib/sbuf.h \ lib/sha256.h \ @@ -141,7 +141,6 @@ pkginclude_HEADERS += \ lib/termtable.h \ lib/thread.h \ lib/vector.h \ - lib/version.h \ lib/vlan.h \ lib/vrf.h \ lib/vrf_int.h \ @@ -154,6 +153,11 @@ pkginclude_HEADERS += \ lib/zebra.h \ # end +nodist_pkginclude_HEADERS += \ + lib/route_types.h \ + lib/version.h \ + # end + noinst_HEADERS += \ lib/clippy.h \ lib/log_int.h \ @@ -180,16 +184,22 @@ lib_libfrrsnmp_la_SOURCES = \ # CLI utilities # noinst_PROGRAMS += \ - lib/clippy \ lib/grammar_sandbox \ # end +if BUILD_CLIPPY +noinst_PROGRAMS += lib/clippy +else +$(HOSTTOOLS)lib/clippy: + @$(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/route_types.h lib/clippy +endif + lib_grammar_sandbox_SOURCES = \ lib/grammar_sandbox_main.c lib_grammar_sandbox_LDADD = \ lib/libfrr.la -lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib +lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE lib_clippy_CFLAGS = $(PYTHON_CFLAGS) lib_clippy_LDADD = $(PYTHON_LIBS) lib_clippy_SOURCES = \ @@ -210,6 +220,7 @@ lib_clippy_SOURCES = \ # EXTRA_DIST += \ lib/command_lex.h \ + lib/command_parse.h \ lib/gitversion.pl \ lib/queue.h \ lib/route_types.pl \ @@ -217,8 +228,6 @@ EXTRA_DIST += \ # end BUILT_SOURCES += \ - lib/command_lex.h \ - lib/command_parse.h \ lib/gitversion.h \ lib/route_types.h \ # end diff --git a/lib/thread.c b/lib/thread.c index fd36eaf388..4a5c61d036 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -340,9 +340,6 @@ static void cancelreq_del(void *cr) /* initializer, only ever called once */ static void initializer() { - if (!masters) - masters = list_new(); - pthread_key_create(&thread_current, NULL); } @@ -415,9 +412,12 @@ struct thread_master *thread_master_create(const char *name) rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct pollfd) * rv->handler.pfdsize); - /* add to list */ + /* add to list of threadmasters */ pthread_mutex_lock(&masters_mtx); { + if (!masters) + masters = list_new(); + listnode_add(masters, rv); } pthread_mutex_unlock(&masters_mtx); @@ -551,6 +551,10 @@ void thread_master_free(struct thread_master *m) pthread_mutex_lock(&masters_mtx); { listnode_delete(masters, m); + if (masters->count == 0) { + list_free (masters); + masters = NULL; + } } pthread_mutex_unlock(&masters_mtx); diff --git a/lib/vty.c b/lib/vty.c index e5bf2e6ced..59a8825357 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -684,6 +684,7 @@ static void vty_end_config(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -1094,6 +1095,7 @@ static void vty_stop_input(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -1661,24 +1663,82 @@ static struct vty *vty_create(int vty_sock, union sockunion *su) /* create vty for stdio */ static struct termios stdio_orig_termios; static struct vty *stdio_vty = NULL; -static void (*stdio_vty_atclose)(void); +static bool stdio_termios = false; +static void (*stdio_vty_atclose)(int isexit); -static void vty_stdio_reset(void) +static void vty_stdio_reset(int isexit) { if (stdio_vty) { - tcsetattr(0, TCSANOW, &stdio_orig_termios); + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; + stdio_vty = NULL; if (stdio_vty_atclose) - stdio_vty_atclose(); + stdio_vty_atclose(isexit); stdio_vty_atclose = NULL; } } -struct vty *vty_stdio(void (*atclose)()) +static void vty_stdio_atexit(void) +{ + vty_stdio_reset(1); +} + +void vty_stdio_suspend(void) +{ + if (!stdio_vty) + return; + + if (stdio_vty->t_write) + thread_cancel(stdio_vty->t_write); + if (stdio_vty->t_read) + thread_cancel(stdio_vty->t_read); + if (stdio_vty->t_timeout) + thread_cancel(stdio_vty->t_timeout); + + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; +} + +void vty_stdio_resume(void) +{ + if (!stdio_vty) + return; + + if (!tcgetattr(0, &stdio_orig_termios)) { + struct termios termios; + + termios = stdio_orig_termios; + termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR + | IGNCR | ICRNL | IXON); + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8; + tcsetattr(0, TCSANOW, &termios); + stdio_termios = true; + } + + vty_prompt(stdio_vty); + + /* Add read/write thread. */ + vty_event(VTY_WRITE, 1, stdio_vty); + vty_event(VTY_READ, 0, stdio_vty); +} + +void vty_stdio_close(void) +{ + if (!stdio_vty) + return; + vty_close(stdio_vty); +} + +struct vty *vty_stdio(void (*atclose)(int isexit)) { struct vty *vty; - struct termios termios; /* refuse creating two vtys on stdio */ if (stdio_vty) @@ -1696,23 +1756,7 @@ struct vty *vty_stdio(void (*atclose)()) vty->v_timeout = 0; strcpy(vty->address, "console"); - if (!tcgetattr(0, &stdio_orig_termios)) { - termios = stdio_orig_termios; - termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - termios.c_oflag &= ~OPOST; - termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - termios.c_cflag &= ~(CSIZE | PARENB); - termios.c_cflag |= CS8; - tcsetattr(0, TCSANOW, &termios); - } - - vty_prompt(vty); - - /* Add read/write thread. */ - vty_event(VTY_WRITE, 1, vty); - vty_event(VTY_READ, 0, vty); - + vty_stdio_resume(); return vty; } @@ -1811,7 +1855,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) ret = getaddrinfo(hostname, port_str, &req, &ainfo); if (ret != 0) { - fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(ret)); + zlog_err("getaddrinfo failed: %s", gai_strerror(ret)); exit(1); } @@ -2161,7 +2205,7 @@ void vty_close(struct vty *vty) XFREE(MTYPE_VTY, vty); if (was_stdio) - vty_stdio_reset(); + vty_stdio_reset(0); } /* When time out occur output message then close connection. */ @@ -2211,23 +2255,22 @@ static void vty_read_file(FILE *confp) if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) { const char *message = NULL; + char *nl; + switch (ret) { case CMD_ERR_AMBIGUOUS: - message = - "*** Error reading config: Ambiguous command."; + message = "Ambiguous command"; break; case CMD_ERR_NO_MATCH: - message = - "*** Error reading config: There is no such command."; + message = "No such command"; break; } - fprintf(stderr, "%s\n", message); - zlog_err("%s", message); - fprintf(stderr, - "*** Error occurred processing line %u, below:\n%s\n", - line_num, vty->error_buf); - zlog_err("*** Error occurred processing line %u, below:\n%s", - line_num, vty->error_buf); + + nl = strchr(vty->error_buf, '\n'); + if (nl) + *nl = '\0'; + zlog_err("ERROR: %s on config line %u: %s", + message, line_num, vty->error_buf); } vty_close(vty); @@ -2299,8 +2342,7 @@ void vty_read_config(const char *config_file, char *config_default_dir) if (config_file != NULL) { if (!IS_DIRECTORY_SEP(config_file[0])) { if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, - "Failure to determine Current Working Directory %d!\n", + zlog_err("Failure to determine Current Working Directory %d!", errno); exit(1); } @@ -2314,17 +2356,14 @@ void vty_read_config(const char *config_file, char *config_default_dir) confp = fopen(fullpath, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, fullpath, safe_strerror(errno)); confp = vty_use_backup_config(fullpath); if (confp) - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_file); exit(1); } @@ -2359,19 +2398,16 @@ void vty_read_config(const char *config_file, char *config_default_dir) #endif /* VTYSH */ confp = fopen(config_default_dir, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, config_default_dir, safe_strerror(errno)); confp = vty_use_backup_config(config_default_dir); if (confp) { - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); fullpath = config_default_dir; } else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_default_dir); goto tmp_free_and_out; } @@ -2881,12 +2917,12 @@ static void vty_save_cwd(void) * Hence not worrying about it too much. */ if (!chdir(SYSCONFDIR)) { - fprintf(stderr, "Failure to chdir to %s, errno: %d\n", + zlog_err("Failure to chdir to %s, errno: %d", SYSCONFDIR, errno); exit(-1); } if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, "Failure to getcwd, errno: %d\n", + zlog_err("Failure to getcwd, errno: %d", errno); exit(-1); } @@ -2926,7 +2962,7 @@ void vty_init(struct thread_master *master_thread) vty_master = master_thread; - atexit(vty_stdio_reset); + atexit(vty_stdio_atexit); /* Initilize server thread vector. */ Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE); diff --git a/lib/vty.h b/lib/vty.h index 0980f73afa..dcb8da225d 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -257,7 +257,7 @@ extern void vty_init_vtysh(void); extern void vty_terminate(void); extern void vty_reset(void); extern struct vty *vty_new(void); -extern struct vty *vty_stdio(void (*atclose)(void)); +extern struct vty *vty_stdio(void (*atclose)(int isexit)); extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); @@ -273,6 +273,11 @@ extern int vty_shell(struct vty *); extern int vty_shell_serv(struct vty *); extern void vty_hello(struct vty *); +/* ^Z / SIGTSTP handling */ +extern void vty_stdio_suspend(void); +extern void vty_stdio_resume(void); +extern void vty_stdio_close(void); + /* Send a fixed-size message to all vty terminal monitors; this should be an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); diff --git a/lib/zclient.c b/lib/zclient.c index 233d0359d5..24cb699196 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1778,6 +1778,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, return 0; } +int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) +{ + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, command, VRF_DEFAULT); + stream_write(s, pw->ifname, IF_NAMESIZE); + stream_putl(s, pw->ifindex); + + /* Put type */ + stream_putl(s, pw->type); + + /* Put nexthop */ + stream_putl(s, pw->af); + switch (pw->af) { + case AF_INET: + stream_put_in_addr(s, &pw->nexthop.ipv4); + break; + case AF_INET6: + stream_write(s, (u_char *)&pw->nexthop.ipv6, 16); + break; + default: + zlog_err("%s: unknown af", __func__); + return -1; + } + + /* Put labels */ + stream_putl(s, pw->local_label); + stream_putl(s, pw->remote_label); + + /* Put flags */ + stream_putc(s, pw->flags); + + /* Protocol specific fields */ + stream_write(s, &pw->data, sizeof(union pw_protocol_fields)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw) +{ + struct stream *s; + + memset(pw, 0, sizeof(struct zapi_pw_status)); + s = zclient->ibuf; + + /* Get data. */ + stream_get(pw->ifname, s, IF_NAMESIZE); + pw->ifindex = stream_getl(s); + pw->status = stream_getl(s); +} + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { @@ -2005,6 +2068,11 @@ static int zclient_read(struct thread *thread) (*zclient->local_macip_del)(command, zclient, length, vrf_id); break; + case ZEBRA_PW_STATUS_UPDATE: + if (zclient->pw_status_update) + (*zclient->pw_status_update)(command, zclient, length, + vrf_id); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index 2752acc281..5edb56f517 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -30,6 +30,12 @@ /* For vrf_bitmap_t. */ #include "vrf.h" +/* For union g_addr */ +#include "nexthop.h" + +/* For union pw_protocol_fields */ +#include "pw.h" + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 @@ -114,6 +120,11 @@ typedef enum { ZEBRA_MACIP_DEL, ZEBRA_REMOTE_MACIP_ADD, ZEBRA_REMOTE_MACIP_DEL, + ZEBRA_PW_ADD, + ZEBRA_PW_DELETE, + ZEBRA_PW_SET, + ZEBRA_PW_UNSET, + ZEBRA_PW_STATUS_UPDATE, } zebra_message_types_t; struct redist_proto { @@ -195,6 +206,7 @@ struct zclient { int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); + int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ @@ -274,6 +286,25 @@ struct zapi_ipv4 { vrf_id_t vrf_id; }; +struct zapi_pw { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + uint8_t protocol; +}; + +struct zapi_pw_status { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + uint32_t status; +}; + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); extern void zclient_init(struct zclient *, int, u_short); @@ -344,6 +375,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep, uint32_t *end); extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int zebra_send_pw(struct zclient *zclient, int command, + struct zapi_pw *pw); +extern void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw); + /* IPv6 prefix add and delete function prototype. */ struct zapi_ipv6 { diff --git a/nhrpd/.gitignore b/nhrpd/.gitignore index 3d4d56d589..3f47381278 100644 --- a/nhrpd/.gitignore +++ b/nhrpd/.gitignore @@ -1 +1,2 @@ +!Makefile nhrpd diff --git a/nhrpd/Makefile b/nhrpd/Makefile new file mode 100644 index 0000000000..62c9546020 --- /dev/null +++ b/nhrpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. nhrpd/nhrpd +%: ALWAYS + @$(MAKE) -s -C .. nhrpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/nhrpd/Makefile.am b/nhrpd/Makefile.am deleted file mode 100644 index 64d9e09bfb..0000000000 --- a/nhrpd/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DQUAGGA_NO_DEPRECATED_INTERFACES -DEFS = @DEFS@ @CARES_CFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(PICFLAGS) $(WERROR) -AM_LDFLAGS = $(PICLDFLAGS) - -sbin_PROGRAMS = nhrpd - -nhrpd_SOURCES = \ - zbuf.c \ - znl.c \ - resolver.c \ - linux.c \ - netlink_arp.c \ - netlink_gre.c \ - vici.c \ - reqid.c \ - nhrp_event.c \ - nhrp_packet.c \ - nhrp_interface.c \ - nhrp_vc.c \ - nhrp_peer.c \ - nhrp_cache.c \ - nhrp_nhs.c \ - nhrp_route.c \ - nhrp_shortcut.c \ - nhrp_vty.c \ - nhrp_main.c - -nhrpd_LDADD = ../lib/libfrr.la @LIBCAP@ @CARES_LIBS@ - -noinst_HEADERS = \ - debug.h \ - list.h \ - netlink.h \ - nhrp_protocol.h \ - nhrpd.h \ - os.h \ - vici.h \ - zbuf.h \ - znl.h \ - # end - -#dist_examples_DATA = nhrpd.conf.sample diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am new file mode 100644 index 0000000000..5b06946c89 --- /dev/null +++ b/nhrpd/subdir.am @@ -0,0 +1,43 @@ +# +# nhrpd +# + +if NHRPD +sbin_PROGRAMS += nhrpd/nhrpd +endif + +nhrpd_nhrpd_LDADD = lib/libfrr.la @LIBCAP@ @CARES_LIBS@ +nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) @CARES_CFLAGS@ +nhrpd_nhrpd_SOURCES = \ + nhrpd/linux.c \ + nhrpd/netlink_arp.c \ + nhrpd/netlink_gre.c \ + nhrpd/nhrp_cache.c \ + nhrpd/nhrp_event.c \ + nhrpd/nhrp_interface.c \ + nhrpd/nhrp_main.c \ + nhrpd/nhrp_nhs.c \ + nhrpd/nhrp_packet.c \ + nhrpd/nhrp_peer.c \ + nhrpd/nhrp_route.c \ + nhrpd/nhrp_shortcut.c \ + nhrpd/nhrp_vc.c \ + nhrpd/nhrp_vty.c \ + nhrpd/reqid.c \ + nhrpd/resolver.c \ + nhrpd/vici.c \ + nhrpd/zbuf.c \ + nhrpd/znl.c \ + # end + +noinst_HEADERS += \ + nhrpd/debug.h \ + nhrpd/list.h \ + nhrpd/netlink.h \ + nhrpd/nhrp_protocol.h \ + nhrpd/nhrpd.h \ + nhrpd/os.h \ + nhrpd/vici.h \ + nhrpd/zbuf.h \ + nhrpd/znl.h \ + # end diff --git a/ospf6d/.gitignore b/ospf6d/.gitignore index 3fef0b7804..744af2d5ce 100644 --- a/ospf6d/.gitignore +++ b/ospf6d/.gitignore @@ -1,5 +1,5 @@ +!Makefile Makefile.in -Makefile *.o *.patch ospf6d diff --git a/ospf6d/Makefile b/ospf6d/Makefile new file mode 100644 index 0000000000..97b37b8c60 --- /dev/null +++ b/ospf6d/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ospf6d/ospf6d +%: ALWAYS + @$(MAKE) -s -C .. ospf6d/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am deleted file mode 100644 index 75dd8ffe46..0000000000 --- a/ospf6d/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = libospf6.a -module_LTLIBRARIES = -sbin_PROGRAMS = ospf6d - -libospf6_a_SOURCES = \ - ospf6_memory.c \ - ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ - ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ - ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ - ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c \ - ospf6d.c ospf6_bfd.c - -noinst_HEADERS = \ - ospf6_memory.h \ - ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ - ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ - ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ - ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h \ - ospf6d.h ospf6_bfd.h - -ospf6d_SOURCES = \ - ospf6_main.c $(libospf6_a_SOURCES) - -ospf6d_LDADD = ../lib/libfrr.la @LIBCAP@ - -if SNMP -module_LTLIBRARIES += ospf6d_snmp.la -endif -ospf6d_snmp_la_SOURCES = ospf6_snmp.c -ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -ospf6d_snmp_la_LIBADD = ../lib/libfrrsnmp.la - -examplesdir = $(exampledir) -dist_examples_DATA = ospf6d.conf.sample diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 8764a549d2..418f858a32 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -83,8 +83,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb) zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb, lsdb->count, num); for (ALL_LSDB(lsdb, debug)) - zlog_debug("%p %p %s lsdb[%p]", debug->prev, debug->next, - debug->name, debug->lsdb); + zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb); zlog_debug("DUMP END"); assert(num == lsdb->count); diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am new file mode 100644 index 0000000000..76a64cd637 --- /dev/null +++ b/ospf6d/subdir.am @@ -0,0 +1,66 @@ +# +# ospf6d +# + +if OSPF6D +noinst_LIBRARIES += ospf6d/libospf6.a +sbin_PROGRAMS += ospf6d/ospf6d +dist_examples_DATA += ospf6d/ospf6d.conf.sample +if SNMP +module_LTLIBRARIES += ospf6d/ospf6d_snmp.la +endif +endif + +ospf6d_libospf6_a_SOURCES = \ + ospf6d/ospf6_abr.c \ + ospf6d/ospf6_area.c \ + ospf6d/ospf6_asbr.c \ + ospf6d/ospf6_bfd.c \ + ospf6d/ospf6_flood.c \ + ospf6d/ospf6_interface.c \ + ospf6d/ospf6_intra.c \ + ospf6d/ospf6_lsa.c \ + ospf6d/ospf6_lsdb.c \ + ospf6d/ospf6_memory.c \ + ospf6d/ospf6_message.c \ + ospf6d/ospf6_neighbor.c \ + ospf6d/ospf6_network.c \ + ospf6d/ospf6_proto.c \ + ospf6d/ospf6_route.c \ + ospf6d/ospf6_spf.c \ + ospf6d/ospf6_top.c \ + ospf6d/ospf6_zebra.c \ + ospf6d/ospf6d.c \ + # end + +noinst_HEADERS += \ + ospf6d/ospf6_abr.h \ + ospf6d/ospf6_area.h \ + ospf6d/ospf6_asbr.h \ + ospf6d/ospf6_bfd.h \ + ospf6d/ospf6_flood.h \ + ospf6d/ospf6_interface.h \ + ospf6d/ospf6_intra.h \ + ospf6d/ospf6_lsa.h \ + ospf6d/ospf6_lsdb.h \ + ospf6d/ospf6_memory.h \ + ospf6d/ospf6_message.h \ + ospf6d/ospf6_neighbor.h \ + ospf6d/ospf6_network.h \ + ospf6d/ospf6_proto.h \ + ospf6d/ospf6_route.h \ + ospf6d/ospf6_spf.h \ + ospf6d/ospf6_top.h \ + ospf6d/ospf6_zebra.h \ + ospf6d/ospf6d.h \ + # end + +ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la @LIBCAP@ +ospf6d_ospf6d_SOURCES = \ + ospf6d/ospf6_main.c \ + # end + +ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c +ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/ospfclient/.gitignore b/ospfclient/.gitignore index a6000f8021..1740b04fbc 100644 --- a/ospfclient/.gitignore +++ b/ospfclient/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o ospfclient diff --git a/ospfclient/Makefile b/ospfclient/Makefile new file mode 100644 index 0000000000..3da2a5b897 --- /dev/null +++ b/ospfclient/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ospfclient/ospfclient +%: ALWAYS + @$(MAKE) -s -C .. ospfclient/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am deleted file mode 100644 index b4e362bbb3..0000000000 --- a/ospfclient/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -## Automake.am for OSPF API client -AUTOMAKE_OPTIONS = subdir-objects - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -AM_CFLAGS = $(WERROR) - -lib_LTLIBRARIES = libfrrospfapiclient.la -libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0 -libfrrospfapiclient_la_LIBADD = ../lib/libfrr.la - -sbin_PROGRAMS = ospfclient - -libfrrospfapiclient_la_SOURCES = \ - ospf_apiclient.c - -ospfapiheaderdir = $(pkgincludedir)/ospfapi - -ospfapiheader_HEADERS = \ - ospf_apiclient.h - -ospfclient_SOURCES = \ - ospfclient.c - -ospfclient_LDADD = libfrrospfapiclient.la \ - ../lib/libfrr.la @LIBCAP@ - -ospfclient_CFLAGS = $(AM_CFLAGS) -ospfclient_LDFLAGS = $(AM_LDFLAGS) diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c index 5713105f42..03b543a786 100644 --- a/ospfclient/ospfclient.c +++ b/ospfclient/ospfclient.c @@ -307,6 +307,7 @@ int main(int argc, char *argv[]) } /* Initialization */ + zprivs_preinit(&ospfd_privs); zprivs_init(&ospfd_privs); master = thread_master_create(NULL); diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am new file mode 100644 index 0000000000..834d4aaba7 --- /dev/null +++ b/ospfclient/subdir.am @@ -0,0 +1,30 @@ +# +# ospfclient +# + +if OSPFCLIENT +lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la +sbin_PROGRAMS += ospfclient/ospfclient +endif + +ospfclient_libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0 +ospfclient_libfrrospfapiclient_la_LIBADD = lib/libfrr.la +ospfclient_libfrrospfapiclient_la_SOURCES = \ + ospfclient/ospf_apiclient.c \ + # end + +if OSPFCLIENT +ospfapiheaderdir = $(pkgincludedir)/ospfapi +ospfapiheader_HEADERS = \ + ospfclient/ospf_apiclient.h \ + # end +endif + +ospfclient_ospfclient_LDADD = \ + ospfclient/libfrrospfapiclient.la \ + lib/libfrr.la \ + @LIBCAP@ \ + # end +ospfclient_ospfclient_SOURCES = \ + ospfclient/ospfclient.c \ + # end diff --git a/ospfd/.gitignore b/ospfd/.gitignore index 4b8787c89e..752c875a62 100644 --- a/ospfd/.gitignore +++ b/ospfd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o ospfd diff --git a/ospfd/Makefile b/ospfd/Makefile new file mode 100644 index 0000000000..e4fab30e19 --- /dev/null +++ b/ospfd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ospfd/ospfd +%: ALWAYS + @$(MAKE) -s -C .. ospfd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am deleted file mode 100644 index c6a5ec91d2..0000000000 --- a/ospfd/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -AM_CFLAGS = $(WERROR) -DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -noinst_LIBRARIES = libfrrospf.a -module_LTLIBRARIES = -sbin_PROGRAMS = ospfd - -libfrrospf_a_SOURCES = \ - ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ - ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ - ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ - ospf_lsdb.c ospf_asbr.c ospf_routemap.c \ - ospf_opaque.c ospf_te.c ospf_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c \ - ospf_bfd.c ospf_memory.c ospf_dump_api.c - -ospfdheaderdir = $(pkgincludedir)/ospfd - -ospfdheader_HEADERS = \ - ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ - ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h \ - ospf_dump_api.h - -noinst_HEADERS = \ - ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ - ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ - ospf_flood.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h \ - ospf_bfd.h ospf_memory.h - -ospfd_SOURCES = ospf_main.c - -ospfd_LDADD = libfrrospf.a ../lib/libfrr.la @LIBCAP@ @LIBM@ - -if SNMP -module_LTLIBRARIES += ospfd_snmp.la -endif -ospfd_snmp_la_SOURCES = ospf_snmp.c -ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -ospfd_snmp_la_LIBADD = ../lib/libfrrsnmp.la - -EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt - -examplesdir = $(exampledir) -dist_examples_DATA = ospfd.conf.sample - diff --git a/ospfd/subdir.am b/ospfd/subdir.am new file mode 100644 index 0000000000..12c2313e65 --- /dev/null +++ b/ospfd/subdir.am @@ -0,0 +1,93 @@ +# +# ospfd +# + +if OSPFD +noinst_LIBRARIES += ospfd/libfrrospf.a +sbin_PROGRAMS += ospfd/ospfd +dist_examples_DATA += ospfd/ospfd.conf.sample +if SNMP +module_LTLIBRARIES += ospfd/ospfd_snmp.la +endif +endif + +ospfd_libfrrospf_a_SOURCES = \ + ospfd/ospf_abr.c \ + ospfd/ospf_api.c \ + ospfd/ospf_apiserver.c \ + ospfd/ospf_asbr.c \ + ospfd/ospf_ase.c \ + ospfd/ospf_bfd.c \ + ospfd/ospf_dump.c \ + ospfd/ospf_dump_api.c \ + ospfd/ospf_flood.c \ + ospfd/ospf_ia.c \ + ospfd/ospf_interface.c \ + ospfd/ospf_ism.c \ + ospfd/ospf_lsa.c \ + ospfd/ospf_lsdb.c \ + ospfd/ospf_memory.c \ + ospfd/ospf_neighbor.c \ + ospfd/ospf_network.c \ + ospfd/ospf_nsm.c \ + ospfd/ospf_opaque.c \ + ospfd/ospf_packet.c \ + ospfd/ospf_ri.c \ + ospfd/ospf_route.c \ + ospfd/ospf_routemap.c \ + ospfd/ospf_spf.c \ + ospfd/ospf_te.c \ + ospfd/ospf_vty.c \ + ospfd/ospf_zebra.c \ + ospfd/ospfd.c \ + # end + +if OSPFD +ospfdheaderdir = $(pkgincludedir)/ospfd +ospfdheader_HEADERS = \ + ospfd/ospf_api.h \ + ospfd/ospf_asbr.h \ + ospfd/ospf_dump.h \ + ospfd/ospf_dump_api.h \ + ospfd/ospf_ism.h \ + ospfd/ospf_lsa.h \ + ospfd/ospf_lsdb.h \ + ospfd/ospf_nsm.h \ + ospfd/ospf_opaque.h \ + ospfd/ospfd.h \ + # end +endif + +noinst_HEADERS += \ + ospfd/ospf_abr.h \ + ospfd/ospf_apiserver.h \ + ospfd/ospf_ase.h \ + ospfd/ospf_bfd.h \ + ospfd/ospf_flood.h \ + ospfd/ospf_ia.h \ + ospfd/ospf_interface.h \ + ospfd/ospf_memory.h \ + ospfd/ospf_neighbor.h \ + ospfd/ospf_network.h \ + ospfd/ospf_packet.h \ + ospfd/ospf_ri.h \ + ospfd/ospf_route.h \ + ospfd/ospf_spf.h \ + ospfd/ospf_te.h \ + ospfd/ospf_vty.h \ + ospfd/ospf_zebra.h \ + # end + +ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la @LIBCAP@ @LIBM@ +ospfd_ospfd_SOURCES = ospfd/ospf_main.c + +ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c +ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la + +EXTRA_DIST += \ + ospfd/ChangeLog.opaque.txt \ + ospfd/OSPF-MIB.txt \ + ospfd/OSPF-TRAP-MIB.txt \ + # end diff --git a/qpb/subdir.am b/qpb/subdir.am index 71e501b9c2..3c006fd221 100644 --- a/qpb/subdir.am +++ b/qpb/subdir.am @@ -16,7 +16,6 @@ qpb_libfrr_pb_la_SOURCES = \ if HAVE_PROTOBUF qpb_libfrr_pb_la_SOURCES += qpb/qpb_allocator.c nodist_qpb_libfrr_pb_la_SOURCES = qpb/qpb.pb-c.c -BUILT_SOURCES += qpb/qpb.pb-c.c CLEANFILES += \ qpb/qpb.pb-c.c \ qpb/qpb.pb-c.h \ diff --git a/redhat/daemons b/redhat/daemons index 94d6c72c30..8d12a1f5b8 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=no -watchfrr_options=("-Az" "-b_" "-r/etc/init.d/frr_restart_%s" "-s/etc/init.d/frr_start_%s" "-k/etc/init.d/frr_stop_%s") +watchfrr_options=("-b_" "-r/etc/init.d/frr_restart_%s" "-s/etc/init.d/frr_start_%s" "-k/etc/init.d/frr_stop_%s") # zebra=no bgpd=no diff --git a/redhat/frr.logrotate b/redhat/frr.logrotate index f43a86efe7..25a5587787 100644 --- a/redhat/frr.logrotate +++ b/redhat/frr.logrotate @@ -1,3 +1,11 @@ +/var/log/frr/frr.log { + notifempty + missingok + postrotate + /bin/kill -HUP `cat /var/run/*syslog*.pid 2> /dev/null` 2> /dev/null || true + endscript +} + /var/log/frr/zebra.log { notifempty missingok diff --git a/ripd/.gitignore b/ripd/.gitignore index 9bcfb635e5..177250ca61 100644 --- a/ripd/.gitignore +++ b/ripd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o ripd diff --git a/ripd/Makefile b/ripd/Makefile new file mode 100644 index 0000000000..2d6f838d0a --- /dev/null +++ b/ripd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ripd/ripd +%: ALWAYS + @$(MAKE) -s -C .. ripd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ripd/Makefile.am b/ripd/Makefile.am deleted file mode 100644 index 9c034f0c38..0000000000 --- a/ripd/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = librip.a -module_LTLIBRARIES = -sbin_PROGRAMS = ripd - -librip_a_SOURCES = \ - rip_memory.c \ - ripd.c rip_zebra.c rip_interface.c rip_debug.c \ - rip_routemap.c rip_peer.c rip_offset.c - -noinst_HEADERS = \ - rip_memory.h \ - ripd.h rip_debug.h rip_interface.h - -ripd_SOURCES = \ - rip_main.c $(librip_a_SOURCES) - -ripd_LDADD = ../lib/libfrr.la @LIBCAP@ - -if SNMP -module_LTLIBRARIES += ripd_snmp.la -endif -ripd_snmp_la_SOURCES = rip_snmp.c -ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -ripd_snmp_la_LIBADD = ../lib/libfrrsnmp.la - -examplesdir = $(exampledir) -dist_examples_DATA = ripd.conf.sample - -EXTRA_DIST = RIPv2-MIB.txt - diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 763bfc142c..0a6337bf76 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -143,10 +143,6 @@ static char *rip_peer_uptime(struct rip_peer *peer, char *buf, size_t len) uptime -= peer->uptime; tm = gmtime(&uptime); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/ripd/subdir.am b/ripd/subdir.am new file mode 100644 index 0000000000..7a8f2185ba --- /dev/null +++ b/ripd/subdir.am @@ -0,0 +1,42 @@ +# +# ripd +# + +if RIPD +noinst_LIBRARIES += ripd/librip.a +sbin_PROGRAMS += ripd/ripd +dist_examples_DATA += ripd/ripd.conf.sample +if SNMP +module_LTLIBRARIES += ripd/ripd_snmp.la +endif +endif + +ripd_librip_a_SOURCES = \ + ripd/rip_debug.c \ + ripd/rip_interface.c \ + ripd/rip_memory.c \ + ripd/rip_offset.c \ + ripd/rip_peer.c \ + ripd/rip_routemap.c \ + ripd/rip_zebra.c \ + ripd/ripd.c \ + # end + +noinst_HEADERS += \ + ripd/rip_debug.h \ + ripd/rip_interface.h \ + ripd/rip_memory.h \ + ripd/ripd.h \ + # end + +ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@ +ripd_ripd_SOURCES = \ + ripd/rip_main.c \ + # end + +ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c +ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la + +EXTRA_DIST += ripd/RIPv2-MIB.txt diff --git a/ripngd/.gitignore b/ripngd/.gitignore index e871fae3ed..213384d139 100644 --- a/ripngd/.gitignore +++ b/ripngd/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o ripngd diff --git a/ripngd/Makefile b/ripngd/Makefile new file mode 100644 index 0000000000..5b76bb2b40 --- /dev/null +++ b/ripngd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. ripngd/ripngd +%: ALWAYS + @$(MAKE) -s -C .. ripngd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am deleted file mode 100644 index 3a4be999a7..0000000000 --- a/ripngd/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -AM_CFLAGS = $(WERROR) - -noinst_LIBRARIES = libripng.a -sbin_PROGRAMS = ripngd - -libripng_a_SOURCES = \ - ripng_memory.c \ - ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ - ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c - -noinst_HEADERS = \ - ripng_memory.h \ - ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h - -ripngd_SOURCES = \ - ripng_main.c $(libripng_a_SOURCES) - -ripngd_LDADD = ../lib/libfrr.la @LIBCAP@ - -examplesdir = $(exampledir) -dist_examples_DATA = ripngd.conf.sample - diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 2a412f9b64..cd46d97402 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -151,10 +151,6 @@ static char *ripng_peer_uptime(struct ripng_peer *peer, char *buf, size_t len) uptime -= peer->uptime; tm = gmtime(&uptime); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/ripngd/subdir.am b/ripngd/subdir.am new file mode 100644 index 0000000000..1f7ff09d6e --- /dev/null +++ b/ripngd/subdir.am @@ -0,0 +1,36 @@ +# +# ripngd +# + +if RIPNGD +noinst_LIBRARIES += ripngd/libripng.a +sbin_PROGRAMS += ripngd/ripngd +endif + +ripngd_libripng_a_SOURCES = \ + ripngd/ripng_debug.c \ + ripngd/ripng_interface.c \ + ripngd/ripng_memory.c \ + ripngd/ripng_nexthop.c \ + ripngd/ripng_offset.c \ + ripngd/ripng_peer.c \ + ripngd/ripng_route.c \ + ripngd/ripng_routemap.c \ + ripngd/ripng_zebra.c \ + ripngd/ripngd.c \ + # end + +noinst_HEADERS += \ + ripngd/ripng_debug.h \ + ripngd/ripng_memory.h \ + ripngd/ripng_nexthop.h \ + ripngd/ripng_route.h \ + ripngd/ripngd.h \ + # end + +ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@ +ripngd_ripngd_SOURCES = \ + ripngd/ripng_main.c \ + # end + +dist_examples_DATA += ripngd/ripngd.conf.sample diff --git a/tests/.gitignore b/tests/.gitignore index 113bdea098..604ffaa8b6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -19,7 +19,6 @@ TAGS .arch-inventory .arch-ids __pycache__ -.dirstamp /bgpd/test_aspath /bgpd/test_capability /bgpd/test_ecommunity diff --git a/tests/Makefile.am b/tests/Makefile.am index 0c31c0441a..59ea3c4c69 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -85,9 +85,7 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" - -BUILT_SOURCES = \ - lib/cli/test_commands_defun.c \ +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ isisd/test_fuzz_isis_tlv_tests.h noinst_HEADERS = \ diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index b6df6d3b8d..77f1610fe2 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -45,7 +45,7 @@ int dump_args(struct vty *vty, const char *descr, int argc, return CMD_SUCCESS; } -static void vty_do_exit(void) +static void vty_do_exit(int isexit) { printf("\nend.\n"); cmd_terminate(); @@ -54,7 +54,8 @@ static void vty_do_exit(void) closezlog(); log_memstats_stderr("testcli"); - exit(0); + if (!isexit) + exit(0); } /* main routine. */ diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c index c2cb5c2ea5..1984f28e63 100644 --- a/tests/lib/test_privs.c +++ b/tests/lib/test_privs.c @@ -108,6 +108,7 @@ int main(int argc, char **argv) /* Library inits. */ memory_init(); + zprivs_preinit(&test_privs); zprivs_init(&test_privs); #define PRIV_STATE() \ diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf index 3f734eef02..0d92d13671 100644 --- a/tools/etc/frr/daemons.conf +++ b/tools/etc/frr/daemons.conf @@ -19,7 +19,7 @@ babeld_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=(-adz -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30) +watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30) # 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. diff --git a/tools/etc/frr/frr.conf b/tools/etc/frr/frr.conf index 2cd05bf803..61f7a65620 100644 --- a/tools/etc/frr/frr.conf +++ b/tools/etc/frr/frr.conf @@ -1,2 +1,3 @@ -log file /var/log/frr/frr.log -log timestamp precision 6 +# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log +# in /var/log/frr/frr.log +log syslog informational diff --git a/tools/etc/rsyslog.d/45-frr.conf b/tools/etc/rsyslog.d/45-frr.conf new file mode 100644 index 0000000000..ff7cd48318 --- /dev/null +++ b/tools/etc/rsyslog.d/45-frr.conf @@ -0,0 +1,36 @@ +# The lines below cause all FRR daemons and process to go +# to /var/log/frr/frr.log, then drops the message so it does +# not also go to /var/log/syslog, so the messages are not duplicated + +$outchannel frr_log,/var/log/frr/frr.log +if $programname == 'babeld' or + $programname == 'bgpd' or + $programname == 'eigrpd' or + $programname == 'frr' or + $programname == 'isisd' or + $programname == 'ldpd' or + $programname == 'nhrpd' or + $programname == 'ospf6d' or + $programname == 'ospfd' or + $programname == 'pimd' or + $programname == 'ripd' or + $programname == 'ripngd' or + $programname == 'watchfrr' or + $programname == 'zebra' + then :omfile:$frr_log + +if $programname == 'babeld' or + $programname == 'bgpd' or + $programname == 'eigrpd' or + $programname == 'frr' or + $programname == 'isisd' or + $programname == 'ldpd' or + $programname == 'nhrpd' or + $programname == 'ospf6d' or + $programname == 'ospfd' or + $programname == 'pimd' or + $programname == 'ripd' or + $programname == 'ripngd' or + $programname == 'watchfrr' or + $programname == 'zebra' + then stop diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 8b66ba2564..d179ed1d99 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -147,6 +147,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/zebra/zebra_fpm.c \ $(top_srcdir)/zebra/zebra_ptm.c \ $(top_srcdir)/zebra/zebra_mpls_vty.c \ + $(top_srcdir)/zebra/zebra_pw.c \ $(top_srcdir)/watchfrr/watchfrr_vty.c \ $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5886d39c19..76c42173da 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -923,6 +923,10 @@ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", }; +static struct cmd_node pw_node = { + PW_NODE, "%s(config-pw)# ", +}; + static struct cmd_node ns_node = { NS_NODE, "%s(config-logical-router)# ", }; @@ -1418,6 +1422,7 @@ static int vtysh_exit(struct vty *vty) vty->node = ENABLE_NODE; break; case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: @@ -1671,6 +1676,15 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd, + "pseudowire IFNAME", + "Static pseudowire configuration\n" + "Pseudowire name\n") +{ + vty->node = PW_NODE; + return CMD_SUCCESS; +} + /* TODO Implement "no interface command in isisd. */ DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | VTYSH_EIGRPD, @@ -2921,6 +2935,7 @@ void vtysh_init_vty(void) install_node(&bgp_node, NULL); install_node(&rip_node, NULL); install_node(&interface_node, NULL); + install_node(&pw_node, NULL); install_node(&link_params_node, NULL); install_node(&ns_node, NULL); install_node(&vrf_node, NULL); @@ -3093,6 +3108,10 @@ void vtysh_init_vty(void) install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); + install_element(PW_NODE, &vtysh_end_all_cmd); + install_element(PW_NODE, &vtysh_exit_interface_cmd); + install_element(PW_NODE, &vtysh_quit_interface_cmd); + install_element(NS_NODE, &vtysh_end_all_cmd); install_element(CONFIG_NODE, &vtysh_ns_cmd); @@ -3168,6 +3187,7 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(CONFIG_NODE, &vtysh_no_interface_cmd); install_element(CONFIG_NODE, &vtysh_no_interface_vrf_cmd); + install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 74509d1ec8..43aff0e3a5 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -181,6 +181,8 @@ void vtysh_config_parse_line(void *arg, const char *line) default: if (strncmp(line, "interface", strlen("interface")) == 0) config = config_get(INTERFACE_NODE, line); + else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) + config = config_get(PW_NODE, line); else if (strncmp(line, "logical-router", strlen("ns")) == 0) config = config_get(NS_NODE, line); else if (strncmp(line, "vrf", strlen("vrf")) == 0) diff --git a/watchfrr/Makefile.am b/watchfrr/Makefile.am index abe2266f20..bb53641eff 100644 --- a/watchfrr/Makefile.am +++ b/watchfrr/Makefile.am @@ -1,8 +1,6 @@ ## Process this file with Automake to create Makefile.in AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" - AM_CFLAGS = $(WERROR) sbin_PROGRAMS = watchfrr diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 6adb25f322..c9f721eacb 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -50,37 +50,14 @@ #define DEFAULT_LOGLEVEL LOG_INFO #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 -#ifdef PATH_WATCHFRR_PID -#define DEFAULT_PIDFILE PATH_WATCHFRR_PID -#else -#define DEFAULT_PIDFILE STATEDIR "/watchfrr.pid" -#endif -#ifdef DAEMON_VTY_DIR -#define VTYDIR DAEMON_VTY_DIR -#else -#define VTYDIR STATEDIR -#endif #define PING_TOKEN "PING" /* Needs to be global, referenced somewhere inside libfrr. */ struct thread_master *master; +static char pidfile_default[256]; -typedef enum { - MODE_MONITOR = 0, - MODE_GLOBAL_RESTART, - MODE_SEPARATE_RESTART, - MODE_PHASED_ZEBRA_RESTART, - MODE_PHASED_ALL_RESTART -} watch_mode_t; - -static const char *mode_str[] = { - "monitor", - "global restart", - "individual daemon restart", - "phased zebra restart", - "phased global restart for any failure", -}; +static bool watch_only = false; typedef enum { PHASE_NONE = 0, @@ -112,7 +89,6 @@ struct restart_info { }; static struct global_state { - watch_mode_t mode; restart_phase_t phase; struct thread *t_phase_hanging; const char *vtydir; @@ -121,29 +97,25 @@ static struct global_state { long restart_timeout; long min_restart_interval; long max_restart_interval; - int do_ping; struct daemon *daemons; const char *restart_command; const char *start_command; const char *stop_command; struct restart_info restart; - int unresponsive_restart; int loglevel; struct daemon *special; /* points to zebra when doing phased restart */ int numdaemons; int numpids; int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ } gs = { - .mode = MODE_MONITOR, .phase = PHASE_NONE, - .vtydir = VTYDIR, + .vtydir = frr_vtydir, .period = 1000 * DEFAULT_PERIOD, .timeout = DEFAULT_TIMEOUT, .restart_timeout = DEFAULT_RESTART_TIMEOUT, .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, - .do_ping = 1, }; typedef enum { @@ -176,11 +148,11 @@ struct daemon { #define OPTION_MINRESTART 2000 #define OPTION_MAXRESTART 2001 +#define OPTION_DRY 2002 static const struct option longopts[] = { {"daemon", no_argument, NULL, 'd'}, {"statedir", required_argument, NULL, 'S'}, - {"no-echo", no_argument, NULL, 'e'}, {"loglevel", required_argument, NULL, 'l'}, {"interval", required_argument, NULL, 'i'}, {"timeout", required_argument, NULL, 't'}, @@ -188,10 +160,7 @@ static const struct option longopts[] = { {"restart", required_argument, NULL, 'r'}, {"start-command", required_argument, NULL, 's'}, {"kill-command", required_argument, NULL, 'k'}, - {"restart-all", required_argument, NULL, 'R'}, - {"all-restart", no_argument, NULL, 'a'}, - {"always-all-restart", no_argument, NULL, 'A'}, - {"unresponsive-restart", no_argument, NULL, 'z'}, + {"dry", no_argument, NULL, OPTION_DRY}, {"min-restart-interval", required_argument, NULL, OPTION_MINRESTART}, {"max-restart-interval", required_argument, NULL, OPTION_MAXRESTART}, {"pid-file", required_argument, NULL, 'p'}, @@ -217,55 +186,19 @@ It then repeatedly sends echo commands over that socket to determine whether\n\ the daemon is responsive. If the daemon crashes, we will receive an EOF\n\ on the socket connection and know immediately that the daemon is down.\n\n\ The daemons to be monitored should be listed on the command line.\n\n\ -This program can run in one of 5 modes:\n\n\ -0. Mode: %s.\n\ - Just monitor and report on status changes. Example:\n\ - %s -d zebra ospfd bgpd\n\n\ -1. Mode: %s.\n\ - Whenever any daemon hangs or crashes, use the given command to restart\n\ - them all. Example:\n\ - %s -dz \\\n\ - -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\ - zebra ospfd\n\n\ -2. Mode: %s.\n\ - When any single daemon hangs or crashes, restart only the daemon that's\n\ - in trouble using the supplied restart command. Example:\n\ - %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\ -3. Mode: %s.\n\ - The same as the previous mode, except that there is special treatment when\n\ - the zebra daemon is in trouble. In that case, a phased restart approach\n\ - is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\ - daemons. Example:\n\ - %s -adz -r '/sbin/service %%s restart' \\\n\ - -s '/sbin/service %%s start' \\\n\ - -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ -4. Mode: %s.\n\ - This is the same as the previous mode, except that the phased restart\n\ - procedure is used whenever any of the daemons hangs or crashes. Example:\n\ - %s -Adz -r '/sbin/service %%s restart' \\\n\ - -s '/sbin/service %%s start' \\\n\ - -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ -As of this writing, it is believed that mode 2 [%s]\n\ -is not safe, and mode 3 [%s] may not be safe with some of the\n\ -routing daemons.\n\n\ In order to avoid attempting to restart the daemons in a fast loop,\n\ the -m and -M options allow you to control the minimum delay between\n\ restart commands. The minimum restart delay is recalculated each time\n\ a restart is attempted: if the time since the last restart attempt exceeds\n\ twice the -M value, then the restart delay is set to the -m value.\n\ Otherwise, the interval is doubled (but capped at the -M value).\n\n", - progname, mode_str[0], progname, mode_str[1], progname, - mode_str[2], progname, mode_str[3], progname, mode_str[4], - progname, mode_str[2], mode_str[3]); + progname); fprintf(target, "Options:\n\ -d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ to syslog instead of stdout.\n\ -S, --statedir Set the vty socket directory (default is %s)\n\ --e, --no-echo Do not ping the daemons to test responsiveness (this\n\ - option is necessary if the daemons do not support the\n\ - echo command)\n\ -l, --loglevel Set the logging level (default is %d).\n\ The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\ but it can be set higher than %d if extra-verbose debugging\n\ @@ -285,7 +218,6 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ - Note that -r and -R are incompatible.\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ @@ -294,33 +226,19 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ --R, --restart-all\n\ - When one or more daemons is down, try to restart everything\n\ - using the Bourne shell command supplied as the argument.\n\ - Note that -r and -R are incompatible.\n\ --z, --unresponsive-restart\n\ - When a daemon is unresponsive, treat it as being down for\n\ - restart purposes.\n\ --a, --all-restart\n\ - When zebra hangs or crashes, restart all daemons using\n\ - this phased approach: 1. stop all other daemons; 2. restart\n\ - zebra; 3. start other daemons. Requires -r, -s, and -k.\n\ --A, --always-all-restart\n\ - When any daemon (not just zebra) hangs or crashes, use the\n\ - same phased restart mechanism described above for -a.\n\ - Requires -r, -s, and -k.\n\ + --dry Do not start or restart anything, just log.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s).\n\ -b, --blank-string\n\ When the supplied argument string is found in any of the\n\ - various shell command arguments (-r, -s, -k, or -R), replace\n\ + various shell command arguments (-r, -s, or -k), replace\n\ it with a space. This is an ugly hack to circumvent problems\n\ passing command-line arguments with embedded spaces.\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n", - VTYDIR, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, + frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD, - DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, DEFAULT_PIDFILE); + DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, pidfile_default); } static pid_t run_background(char *shell_cmd) @@ -390,15 +308,10 @@ static int restart_kill(struct thread *t_kill) static struct restart_info *find_child(pid_t child) { - if (gs.mode == MODE_GLOBAL_RESTART) { - if (gs.restart.pid == child) - return &gs.restart; - } else { - struct daemon *dmn; - for (dmn = gs.daemons; dmn; dmn = dmn->next) { - if (dmn->restart.pid == child) - return &dmn->restart; - } + struct daemon *dmn; + for (dmn = gs.daemons; dmn; dmn = dmn->next) { + if (dmn->restart.pid == child) + return &dmn->restart; } return NULL; } @@ -700,8 +613,7 @@ static void daemon_up(struct daemon *dmn, const char *why) dmn->connect_tries = 0; zlog_notice("%s state -> up : %s", dmn->name, why); daemon_send_ready(); - if (gs.do_ping) - SET_WAKEUP_ECHO(dmn); + SET_WAKEUP_ECHO(dmn); phase_check(); } @@ -889,61 +801,46 @@ static void phase_check(void) static void try_restart(struct daemon *dmn) { - switch (gs.mode) { - case MODE_MONITOR: + if (watch_only) return; - case MODE_GLOBAL_RESTART: - run_job(&gs.restart, "restart", gs.restart_command, 0, 1); - break; - case MODE_SEPARATE_RESTART: - run_job(&dmn->restart, "restart", gs.restart_command, 0, 1); - break; - case MODE_PHASED_ZEBRA_RESTART: - if (dmn != gs.special) { - if ((gs.special->state == DAEMON_UP) - && (gs.phase == PHASE_NONE)) - run_job(&dmn->restart, "restart", - gs.restart_command, 0, 1); - else - zlog_debug( - "%s: postponing restart attempt because master %s daemon " - "not up [%s], or phased restart in progress", - dmn->name, gs.special->name, - state_str[gs.special->state]); - break; - } - /*FALLTHRU*/ - case MODE_PHASED_ALL_RESTART: - if ((gs.phase != PHASE_NONE) || gs.numpids) { + if (dmn != gs.special) { + if ((gs.special->state == DAEMON_UP) + && (gs.phase == PHASE_NONE)) + run_job(&dmn->restart, "restart", gs.restart_command, 0, + 1); + else + zlog_debug( + "%s: postponing restart attempt because master %s daemon " + "not up [%s], or phased restart in progress", + dmn->name, gs.special->name, + state_str[gs.special->state]); + return; + } + + if ((gs.phase != PHASE_NONE) || gs.numpids) { + if (gs.loglevel > LOG_DEBUG + 1) + zlog_debug( + "postponing phased global restart: restart already in " + "progress [%s], or outstanding child processes [%d]", + phase_str[gs.phase], gs.numpids); + return; + } + /* Is it too soon for a restart? */ + { + struct timeval delay; + if (time_elapsed(&delay, &gs.special->restart.time)->tv_sec + < gs.special->restart.interval) { if (gs.loglevel > LOG_DEBUG + 1) zlog_debug( - "postponing phased global restart: restart already in " - "progress [%s], or outstanding child processes [%d]", - phase_str[gs.phase], gs.numpids); - break; + "postponing phased global restart: " + "elapsed time %ld < retry interval %ld", + (long)delay.tv_sec, + gs.special->restart.interval); + return; } - /* Is it too soon for a restart? */ - { - struct timeval delay; - if (time_elapsed(&delay, &gs.special->restart.time) - ->tv_sec - < gs.special->restart.interval) { - if (gs.loglevel > LOG_DEBUG + 1) - zlog_debug( - "postponing phased global restart: " - "elapsed time %ld < retry interval %ld", - (long)delay.tv_sec, - gs.special->restart.interval); - break; - } - } - run_job(&gs.restart, "restart", gs.restart_command, 0, 1); - break; - default: - zlog_err("error: unknown restart mode %d", gs.mode); - break; } + run_job(&gs.restart, "restart", gs.restart_command, 0, 1); } static int wakeup_unresponsive(struct thread *t_wakeup) @@ -973,10 +870,8 @@ static int wakeup_no_answer(struct thread *t_wakeup) "%s state -> unresponsive : no response yet to ping " "sent %ld seconds ago", dmn->name, gs.timeout); - if (gs.unresponsive_restart) { - SET_WAKEUP_UNRESPONSIVE(dmn); - try_restart(dmn); - } + SET_WAKEUP_UNRESPONSIVE(dmn); + try_restart(dmn); return 0; } @@ -1071,46 +966,41 @@ FRR_DAEMON_INFO(watchfrr, WATCHFRR, .privs = &watchfrr_privs, ) +#define DEPRECATED_OPTIONS "aAezR:" + int main(int argc, char **argv) { int opt; - const char *pidfile = DEFAULT_PIDFILE; + const char *pidfile = pidfile_default; const char *special = "zebra"; const char *blankstr = NULL; + snprintf(pidfile_default, sizeof(pidfile_default), "%s/watchfrr.pid", + frr_vtydir); + frr_preinit(&watchfrr_di, argc, argv); progname = watchfrr_di.progname; - frr_opt_add("aAb:dek:l:i:p:r:R:S:s:t:T:z", longopts, ""); + frr_opt_add("b:dk:l:i:p:r:S:s:t:T:" DEPRECATED_OPTIONS, longopts, ""); gs.restart.name = "all"; while ((opt = frr_getopt(argc, argv, NULL)) != EOF) { + if (opt && opt < 128 && strchr(DEPRECATED_OPTIONS, opt)) { + fprintf(stderr, + "The -%c option no longer exists.\n" + "Please refer to the watchfrr(8) man page.\n", + opt); + exit(1); + } + switch (opt) { case 0: break; - case 'a': - if ((gs.mode != MODE_MONITOR) - && (gs.mode != MODE_SEPARATE_RESTART)) { - fputs("Ambiguous operating mode selected.\n", - stderr); - frr_help_exit(1); - } - gs.mode = MODE_PHASED_ZEBRA_RESTART; - break; - case 'A': - if ((gs.mode != MODE_MONITOR) - && (gs.mode != MODE_SEPARATE_RESTART)) { - fputs("Ambiguous operating mode selected.\n", - stderr); - frr_help_exit(1); - } - gs.mode = MODE_PHASED_ALL_RESTART; - break; case 'b': blankstr = optarg; break; - case 'e': - gs.do_ping = 0; + case OPTION_DRY: + watch_only = true; break; case 'k': if (!valid_command(optarg)) { @@ -1172,12 +1062,6 @@ int main(int argc, char **argv) pidfile = optarg; break; case 'r': - if ((gs.mode == MODE_GLOBAL_RESTART) - || (gs.mode == MODE_SEPARATE_RESTART)) { - fputs("Ambiguous operating mode selected.\n", - stderr); - frr_help_exit(1); - } if (!valid_command(optarg)) { fprintf(stderr, "Invalid restart command, must contain '%%s': %s\n", @@ -1185,23 +1069,6 @@ int main(int argc, char **argv) frr_help_exit(1); } gs.restart_command = optarg; - if (gs.mode == MODE_MONITOR) - gs.mode = MODE_SEPARATE_RESTART; - break; - case 'R': - if (gs.mode != MODE_MONITOR) { - fputs("Ambiguous operating mode selected.\n", - stderr); - frr_help_exit(1); - } - if (strchr(optarg, '%')) { - fprintf(stderr, - "Invalid restart-all arg, must not contain '%%s': %s\n", - optarg); - frr_help_exit(1); - } - gs.restart_command = optarg; - gs.mode = MODE_GLOBAL_RESTART; break; case 's': if (!valid_command(optarg)) { @@ -1238,49 +1105,22 @@ int main(int argc, char **argv) frr_help_exit(1); } } break; - case 'z': - gs.unresponsive_restart = 1; - break; default: fputs("Invalid option.\n", stderr); frr_help_exit(1); } } - if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) { - fputs("Option -z requires a -r or -R restart option.\n", + if (watch_only + && (gs.start_command || gs.stop_command || gs.restart_command)) { + fputs("Options -r/-s/-k are not used when --dry is active.\n", stderr); - frr_help_exit(1); } - switch (gs.mode) { - case MODE_MONITOR: - if (gs.restart_command || gs.start_command || gs.stop_command) { - fprintf(stderr, - "No kill/(re)start commands needed for %s mode.\n", - mode_str[gs.mode]); - frr_help_exit(1); - } - break; - case MODE_GLOBAL_RESTART: - case MODE_SEPARATE_RESTART: - if (!gs.restart_command || gs.start_command - || gs.stop_command) { - fprintf(stderr, - "No start/kill commands needed in [%s] mode.\n", - mode_str[gs.mode]); - frr_help_exit(1); - } - break; - case MODE_PHASED_ZEBRA_RESTART: - case MODE_PHASED_ALL_RESTART: - if (!gs.restart_command || !gs.start_command - || !gs.stop_command) { - fprintf(stderr, - "Need start, kill, and restart commands in [%s] mode.\n", - mode_str[gs.mode]); - frr_help_exit(1); - } - break; + if (!watch_only + && (!gs.restart_command || !gs.start_command || !gs.stop_command)) { + fprintf(stderr, + "Options -s (start), -k (kill), and -r (restart) are required.\n"); + frr_help_exit(1); } if (blankstr) { @@ -1343,9 +1183,7 @@ int main(int argc, char **argv) gs.daemons = dmn; tail = dmn; - if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) - || (gs.mode == MODE_PHASED_ALL_RESTART)) - && !strcmp(dmn->name, special)) + if (!strcmp(dmn->name, special)) gs.special = dmn; } } @@ -1353,12 +1191,9 @@ int main(int argc, char **argv) fputs("Must specify one or more daemons to monitor.\n", stderr); frr_help_exit(1); } - if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) - || (gs.mode == MODE_PHASED_ALL_RESTART)) - && !gs.special) { - fprintf(stderr, - "In mode [%s], but cannot find master daemon %s\n", - mode_str[gs.mode], special); + if (!watch_only && !gs.special) { + fprintf(stderr, "\"%s\" daemon must be in daemon list\n", + special); frr_help_exit(1); } @@ -1383,8 +1218,9 @@ int main(int argc, char **argv) strcpy(p, dmn->name); p += strlen(p); } - zlog_notice("%s %s watching [%s], mode [%s]", progname, - FRR_VERSION, buf, mode_str[gs.mode]); + zlog_notice("%s %s watching [%s]%s", progname, + FRR_VERSION, buf, + watch_only ? ", monitor mode" : ""); } } diff --git a/zebra/debug.c b/zebra/debug.c index 6aedea1e39..25f47bc51a 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -32,6 +32,7 @@ unsigned long zebra_debug_fpm; unsigned long zebra_debug_nht; unsigned long zebra_debug_mpls; unsigned long zebra_debug_vxlan; +unsigned long zebra_debug_pw; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -82,6 +83,8 @@ DEFUN (show_debugging_zebra, vty_out(vty, " Zebra next-hop tracking debugging is on\n"); if (IS_ZEBRA_DEBUG_MPLS) vty_out(vty, " Zebra MPLS debugging is on\n"); + if (IS_ZEBRA_DEBUG_PW) + vty_out(vty, " Zebra pseudowire debugging is on\n"); return CMD_SUCCESS; } @@ -130,6 +133,21 @@ DEFUN (debug_zebra_vxlan, return CMD_WARNING; } +DEFUN (debug_zebra_pw, + debug_zebra_pw_cmd, + "[no] debug zebra pseudowires", + "Negate a command or set its defaults\n" + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra pseudowires\n") +{ + if (strmatch(argv[0]->text, "no")) + UNSET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); + else + SET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); + return CMD_WARNING; +} + DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet [] [detail]", @@ -419,6 +437,10 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug zebra vxlan\n"); write++; } + if (IS_ZEBRA_DEBUG_PW) { + vty_out(vty, "debug zebra pseudowires\n"); + write++; + } return write; } @@ -431,6 +453,7 @@ void zebra_debug_init(void) zebra_debug_fpm = 0; zebra_debug_mpls = 0; zebra_debug_vxlan = 0; + zebra_debug_pw = 0; install_node(&debug_node, config_write_debug); @@ -440,6 +463,7 @@ void zebra_debug_init(void) install_element(ENABLE_NODE, &debug_zebra_nht_cmd); install_element(ENABLE_NODE, &debug_zebra_mpls_cmd); install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd); + install_element(ENABLE_NODE, &debug_zebra_pw_cmd); install_element(ENABLE_NODE, &debug_zebra_packet_cmd); install_element(ENABLE_NODE, &debug_zebra_kernel_cmd); install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd); @@ -459,6 +483,7 @@ void zebra_debug_init(void) install_element(CONFIG_NODE, &debug_zebra_nht_cmd); install_element(CONFIG_NODE, &debug_zebra_mpls_cmd); install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd); + install_element(CONFIG_NODE, &debug_zebra_pw_cmd); install_element(CONFIG_NODE, &debug_zebra_packet_cmd); install_element(CONFIG_NODE, &debug_zebra_kernel_cmd); install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index b52bb7d0e9..987f9d0125 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -44,6 +44,8 @@ #define ZEBRA_DEBUG_VXLAN 0x01 +#define ZEBRA_DEBUG_PW 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -66,6 +68,7 @@ #define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) #define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS) #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN) +#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; @@ -75,6 +78,7 @@ extern unsigned long zebra_debug_fpm; extern unsigned long zebra_debug_nht; extern unsigned long zebra_debug_mpls; extern unsigned long zebra_debug_vxlan; +extern unsigned long zebra_debug_pw; extern void zebra_debug_init(void); diff --git a/zebra/interface.c b/zebra/interface.c index 03ddf8d386..c4d0363994 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -48,6 +48,7 @@ #include "zebra/rt_netlink.h" #include "zebra/interface.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_static.h" #define ZEBRA_PTM_SUPPORT @@ -119,8 +120,6 @@ static int if_zebra_new_hook(struct interface *ifp) route_table_init_with_delegate(&zebra_if_table_delegate); ifp->info = zebra_if; - - zebra_vrf_static_route_interface_fixup(ifp); return 0; } @@ -510,6 +509,8 @@ void if_add_update(struct interface *ifp) zlog_debug( "interface %s vrf %u index %d becomes active.", ifp->name, ifp->vrf_id, ifp->ifindex); + + static_ifindex_update(ifp, true); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s vrf %u index %d is added.", @@ -675,6 +676,8 @@ void if_delete_update(struct interface *ifp) zlog_debug("interface %s vrf %u index %d is now inactive.", ifp->name, ifp->vrf_id, ifp->ifindex); + static_ifindex_update(ifp, false); + /* Delete connected routes from the kernel. */ if_delete_connected(ifp); @@ -714,6 +717,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) old_vrf_id = ifp->vrf_id; + static_ifindex_update(ifp, false); + /* Uninstall connected routes. */ if_uninstall_connected(ifp); @@ -737,6 +742,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) /* Install connected routes (in new VRF). */ if_install_connected(ifp); + static_ifindex_update(ifp, true); + /* Due to connected route change, schedule RIB processing for both old * and new VRF. */ @@ -745,8 +752,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) ifp->vrf_id, ifp->name); rib_update(old_vrf_id, RIB_UPDATE_IF_CHANGE); rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - - zebra_vrf_static_route_interface_fixup(ifp); } static void ipv6_ll_address_to_mac(struct in6_addr *address, u_char *mac) @@ -859,8 +864,6 @@ void if_up(struct interface *ifp) ifp->vrf_id, ifp->name); rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - zebra_vrf_static_route_interface_fixup(ifp); - /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed * on them for ARP suppression. diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5df57b2530..5ca6a488c3 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -627,6 +627,7 @@ int ifm_read(struct if_msghdr *ifm) #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ + ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: interface %s index %d", __func__, ifp->name, diff --git a/zebra/main.c b/zebra/main.c index ddd6db5254..538c2f0663 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -307,6 +307,7 @@ int main(int argc, char **argv) zebra_mpls_init(); zebra_mpls_vty_init(); + zebra_pw_vty_init(); /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ diff --git a/zebra/rib.h b/zebra/rib.h index eca2be5eee..de941bcbbe 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -89,6 +89,7 @@ struct route_entry { #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2 #define ROUTE_ENTRY_CHANGED 0x4 #define ROUTE_ENTRY_SELECTED_FIB 0x8 +#define ROUTE_ENTRY_LABELS_CHANGED 0x10 /* Nexthop information. */ u_char nexthop_num; diff --git a/zebra/subdir.am b/zebra/subdir.am index ceffa863e9..0391cab9fd 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -56,6 +56,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_ns.c \ zebra/zebra_ptm.c \ zebra/zebra_ptm_redistribute.c \ + zebra/zebra_pw.c \ zebra/zebra_rib.c \ zebra/zebra_rnh.c \ zebra/zebra_routemap.c \ @@ -95,6 +96,7 @@ noinst_HEADERS += \ zebra/zebra_ns.h \ zebra/zebra_ptm.h \ zebra/zebra_ptm_redistribute.h \ + zebra/zebra_pw.h \ zebra/zebra_rnh.h \ zebra/zebra_routemap.h \ zebra/zebra_static.h \ diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index e44e5d2e6b..d1ab2dbb85 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2222,7 +2222,7 @@ found: return 0; SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); rib_queue_add(rn); return 0; @@ -2405,7 +2405,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) nexthop_del_labels(nexthop); SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, - ROUTE_ENTRY_NEXTHOPS_CHANGED); + ROUTE_ENTRY_LABELS_CHANGED); update = 1; } diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index c3d09aedbd..119cd5b700 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -37,6 +37,7 @@ extern struct zebra_privs_t zserv_privs; struct { u_int32_t rtseq; int fd; + int ioctl_fd; } kr_state; static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, @@ -330,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp) return ret; } +static int kmpw_install(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + struct sockaddr_storage ss; + struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + + memset(&imr, 0, sizeof(imr)); + switch (pw->type) { + case PW_TYPE_ETHERNET: + imr.imr_type = IMR_TYPE_ETHERNET; + break; + case PW_TYPE_ETHERNET_TAGGED: + imr.imr_type = IMR_TYPE_ETHERNET_TAGGED; + break; + default: + zlog_err("%s: unhandled pseudowire type (%#X)", __func__, + pw->type); + return -1; + } + + if (pw->flags & F_PSEUDOWIRE_CWORD) + imr.imr_flags |= IMR_FLAG_CONTROLWORD; + + /* pseudowire nexthop */ + memset(&ss, 0, sizeof(ss)); + switch (pw->af) { + case AF_INET: + sa_in->sin_family = AF_INET; + sa_in->sin_len = sizeof(struct sockaddr_in); + sa_in->sin_addr = pw->nexthop.ipv4; + break; + case AF_INET6: + sa_in6->sin6_family = AF_INET6; + sa_in6->sin6_len = sizeof(struct sockaddr_in6); + sa_in6->sin6_addr = pw->nexthop.ipv6; + break; + default: + zlog_err("%s: unhandled pseudowire address-family (%u)", + __func__, pw->af); + return -1; + } + memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, + sizeof(imr.imr_nexthop)); + + /* pseudowire local/remote labels */ + imr.imr_lshim.shim_label = pw->local_label; + imr.imr_rshim.shim_label = pw->remote_label; + + /* ioctl */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + +static int kmpw_uninstall(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + + memset(&ifr, 0, sizeof(ifr)); + memset(&imr, 0, sizeof(imr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + #define MAX_RTSOCK_BUF 128 * 1024 int mpls_kernel_init(void) { @@ -341,6 +421,12 @@ int mpls_kernel_init(void) return -1; } + if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) + == -1) { + zlog_warn("%s: ioctl socket", __func__); + return -1; + } + /* grow receive buffer, don't wanna miss messages */ optlen = sizeof(default_rcvbuf); if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf, @@ -359,6 +445,10 @@ int mpls_kernel_init(void) kr_state.rtseq = 1; + /* register hook to install/uninstall pseudowires */ + hook_register(pw_install, kmpw_install); + hook_register(pw_uninstall, kmpw_uninstall); + return 0; } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c new file mode 100644 index 0000000000..4f1d8b0915 --- /dev/null +++ b/zebra/zebra_pw.c @@ -0,0 +1,533 @@ +/* Zebra PW code + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include + +#include "log.h" +#include "memory.h" +#include "thread.h" +#include "command.h" +#include "vrf.h" + +#include "zebra/debug.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zebra_pw.h" + +DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire") + +DEFINE_QOBJ_TYPE(zebra_pw) + +DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) +DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) + +#define MPLS_NO_LABEL MPLS_INVALID_LABEL + +extern struct zebra_t zebrad; + +static int zebra_pw_enabled(struct zebra_pw *); +static void zebra_pw_install(struct zebra_pw *); +static void zebra_pw_uninstall(struct zebra_pw *); +static int zebra_pw_install_retry(struct thread *); +static int zebra_pw_check_reachability(struct zebra_pw *); +static void zebra_pw_update_status(struct zebra_pw *, int); + +static inline int zebra_pw_compare(const struct zebra_pw *a, + const struct zebra_pw *b) +{ + return (strcmp(a->ifname, b->ifname)); +} + +RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare) +RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare) + +struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, + uint8_t protocol, struct zserv *client) +{ + struct zebra_pw *pw; + + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: adding pseudowire %s protocol %s", + zvrf_id(zvrf), ifname, zebra_route_string(protocol)); + + pw = XCALLOC(MTYPE_PW, sizeof(*pw)); + strlcpy(pw->ifname, ifname, sizeof(pw->ifname)); + pw->protocol = protocol; + pw->vrf_id = zvrf_id(zvrf); + pw->client = client; + pw->status = PW_STATUS_UP; + pw->local_label = MPLS_NO_LABEL; + pw->remote_label = MPLS_NO_LABEL; + pw->flags = F_PSEUDOWIRE_CWORD; + + RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw); + if (pw->protocol == ZEBRA_ROUTE_STATIC) { + RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw); + QOBJ_REG(pw, zebra_pw); + } + + return pw; +} + +void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id, + pw->ifname, zebra_route_string(pw->protocol)); + + /* remove nexthop tracking */ + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + + /* uninstall */ + if (pw->status == PW_STATUS_UP) + hook_call(pw_uninstall, pw); + else if (pw->install_retry_timer) + THREAD_TIMER_OFF(pw->install_retry_timer); + + /* unlink and release memory */ + RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw); + if (pw->protocol == ZEBRA_ROUTE_STATIC) + RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw); + XFREE(MTYPE_PW, pw); +} + +void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af, + union g_addr *nexthop, uint32_t local_label, + uint32_t remote_label, uint8_t flags, + union pw_protocol_fields *data) +{ + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + + pw->ifindex = ifindex; + pw->type = type; + pw->af = af; + pw->nexthop = *nexthop; + pw->local_label = local_label; + pw->remote_label = remote_label; + pw->flags = flags; + pw->data = *data; + + if (zebra_pw_enabled(pw)) + zebra_register_rnh_pseudowire(pw->vrf_id, pw); + else + zebra_pw_uninstall(pw); +} + +struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname) +{ + struct zebra_pw pw; + strlcpy(pw.ifname, ifname, sizeof(pw.ifname)); + return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw)); +} + +static int zebra_pw_enabled(struct zebra_pw *pw) +{ + if (pw->protocol == ZEBRA_ROUTE_STATIC) { + if (pw->local_label == MPLS_NO_LABEL + || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC) + return 0; + return 1; + } else + return pw->enabled; +} + +void zebra_pw_update(struct zebra_pw *pw) +{ + if (zebra_pw_check_reachability(pw) < 0) { + zebra_pw_uninstall(pw); + /* wait for NHT and try again later */ + } else { + /* + * Install or reinstall the pseudowire (e.g. to update + * parameters like the nexthop or the use of the control word). + */ + zebra_pw_install(pw); + } +} + +static void zebra_pw_install(struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: installing pseudowire %s protocol %s", + pw->vrf_id, pw->ifname, + zebra_route_string(pw->protocol)); + + if (hook_call(pw_install, pw)) { + zebra_pw_install_failure(pw); + return; + } + + if (pw->status == PW_STATUS_DOWN) + zebra_pw_update_status(pw, PW_STATUS_UP); +} + +static void zebra_pw_uninstall(struct zebra_pw *pw) +{ + if (pw->status == PW_STATUS_DOWN) + return; + + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: uninstalling pseudowire %s protocol %s", + pw->vrf_id, pw->ifname, + zebra_route_string(pw->protocol)); + + /* ignore any possible error */ + hook_call(pw_uninstall, pw); + + if (zebra_pw_enabled(pw)) + zebra_pw_update_status(pw, PW_STATUS_DOWN); +} + +/* + * Installation of the pseudowire in the kernel or hardware has failed. This + * function will notify the pseudowire client about the failure and schedule + * to retry the installation later. This function can be called by an external + * agent that performs the pseudowire installation in an asynchronous way. + */ +void zebra_pw_install_failure(struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug( + "%u: failed installing pseudowire %s, " + "scheduling retry in %u seconds", + pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL); + + /* schedule to retry later */ + THREAD_TIMER_OFF(pw->install_retry_timer); + thread_add_timer(zebrad.master, zebra_pw_install_retry, pw, + PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer); + + zebra_pw_update_status(pw, PW_STATUS_DOWN); +} + +static int zebra_pw_install_retry(struct thread *thread) +{ + struct zebra_pw *pw = THREAD_ARG(thread); + + pw->install_retry_timer = NULL; + zebra_pw_install(pw); + + return 0; +} + +static void zebra_pw_update_status(struct zebra_pw *pw, int status) +{ + pw->status = status; + if (pw->client) + zsend_pw_update(pw->client, pw); +} + +static int zebra_pw_check_reachability(struct zebra_pw *pw) +{ + struct route_entry *re; + struct nexthop *nexthop; + + /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */ + + /* find route to the remote end of the pseudowire */ + re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id, + &pw->nexthop, NULL); + if (!re) { + if (IS_ZEBRA_DEBUG_PW) + zlog_warn("%s: no route found for %s", __func__, + pw->ifname); + return -1; + } + + /* + * Need to ensure that there's a label binding for all nexthops. + * Otherwise, ECMP for this route could render the pseudowire unusable. + */ + for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + if (!nexthop->nh_label) { + if (IS_ZEBRA_DEBUG_PW) + zlog_warn("%s: unlabeled route for %s", + __func__, pw->ifname); + return -1; + } + } + + return 0; +} + +void zebra_pw_client_close(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + struct zebra_pw *pw, *tmp; + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) + { + zvrf = vrf->info; + RB_FOREACH_SAFE(pw, zebra_pw_head, &zvrf->pseudowires, tmp) + { + if (pw->client != client) + continue; + zebra_pw_del(zvrf, pw); + } + } +} + +void zebra_pw_init(struct zebra_vrf *zvrf) +{ + RB_INIT(zebra_pw_head, &zvrf->pseudowires); + RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires); +} + +void zebra_pw_exit(struct zebra_vrf *zvrf) +{ + struct zebra_pw *pw; + + while ((pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires)) != NULL) + zebra_pw_del(zvrf, pw); +} + +DEFUN_NOSH (pseudowire_if, + pseudowire_if_cmd, + "[no] pseudowire IFNAME", + NO_STR + "Static pseudowire configuration\n" + "Pseudowire name\n") +{ + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + int idx = 0; + const char *ifname; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return CMD_WARNING; + + argv_find(argv, argc, "IFNAME", &idx); + ifname = argv[idx]->arg; + pw = zebra_pw_find(zvrf, ifname); + if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) { + vty_out(vty, "%% Pseudowire is not static\n"); + return CMD_WARNING; + } + + if (argv_find(argv, argc, "no", &idx)) { + if (!pw) + return CMD_SUCCESS; + zebra_pw_del(zvrf, pw); + } + + if (!pw) + pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL); + VTY_PUSH_CONTEXT(PW_NODE, pw); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_labels, + pseudowire_labels_cmd, + "[no] mpls label local (16-1048575) remote (16-1048575)", + NO_STR + "MPLS L2VPN PW command\n" + "MPLS L2VPN static labels\n" + "Local pseudowire label\n" + "Local pseudowire label\n" + "Remote pseudowire label\n" + "Remote pseudowire label\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + mpls_label_t local_label, remote_label; + + if (argv_find(argv, argc, "no", &idx)) { + local_label = MPLS_NO_LABEL; + remote_label = MPLS_NO_LABEL; + } else { + argv_find(argv, argc, "local", &idx); + local_label = atoi(argv[idx + 1]->arg); + argv_find(argv, argc, "remote", &idx); + remote_label = atoi(argv[idx + 1]->arg); + } + + zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, + local_label, remote_label, pw->flags, &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_neighbor, + pseudowire_neighbor_cmd, + "[no] neighbor ", + NO_STR + "Specify the IPv4 or IPv6 address of the remote endpoint\n" + "IPv4 address\n" + "IPv6 address\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + const char *address; + int af; + union g_addr nexthop; + + af = AF_UNSPEC; + memset(&nexthop, 0, sizeof(nexthop)); + + if (!argv_find(argv, argc, "no", &idx)) { + argv_find(argv, argc, "neighbor", &idx); + address = argv[idx + 1]->arg; + + if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1) + af = AF_INET; + else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1) + af = AF_INET6; + else { + vty_out(vty, "%% Malformed address\n"); + return CMD_WARNING; + } + } + + zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop, + pw->local_label, pw->remote_label, pw->flags, + &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_control_word, + pseudowire_control_word_cmd, + "[no] control-word ", + NO_STR + "Control-word options\n" + "Exclude control-word in pseudowire packets\n" + "Include control-word in pseudowire packets\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + uint8_t flags = 0; + + if (argv_find(argv, argc, "no", &idx)) + flags = F_PSEUDOWIRE_CWORD; + else { + argv_find(argv, argc, "control-word", &idx); + if (argv[idx + 1]->text[0] == 'i') + flags = F_PSEUDOWIRE_CWORD; + } + + zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, + pw->local_label, pw->remote_label, flags, &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (show_pseudowires, + show_pseudowires_cmd, + "show pseudowires", + SHOW_STR + "Pseudowires") +{ + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return 0; + + vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor", + "Labels", "Protocol", "Status"); + + RB_FOREACH(pw, zebra_pw_head, &zvrf->pseudowires) + { + char buf_nbr[INET6_ADDRSTRLEN]; + char buf_labels[64]; + + inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr)); + + if (pw->local_label != MPLS_NO_LABEL + && pw->remote_label != MPLS_NO_LABEL) + snprintf(buf_labels, sizeof(buf_labels), "%u/%u", + pw->local_label, pw->remote_label); + else + snprintf(buf_labels, sizeof(buf_labels), "-"); + + vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname, + (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels, + zebra_route_string(pw->protocol), + (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) + ? "UP" + : "DOWN"); + } + + return CMD_SUCCESS; +} + +/* Pseudowire configuration write function. */ +static int zebra_pw_config(struct vty *vty) +{ + int write = 0; + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return 0; + + RB_FOREACH(pw, zebra_static_pw_head, &zvrf->static_pseudowires) + { + vty_out(vty, "pseudowire %s\n", pw->ifname); + if (pw->local_label != MPLS_NO_LABEL + && pw->remote_label != MPLS_NO_LABEL) + vty_out(vty, " mpls label local %u remote %u\n", + pw->local_label, pw->remote_label); + else + vty_out(vty, + " ! Incomplete config, specify the static " + "MPLS labels\n"); + + if (pw->af != AF_UNSPEC) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf)); + vty_out(vty, " neighbor %s\n", buf); + } else + vty_out(vty, + " ! Incomplete config, specify a neighbor " + "address\n"); + + if (!(pw->flags & F_PSEUDOWIRE_CWORD)) + vty_out(vty, " control-word exclude\n"); + + vty_out(vty, "!\n"); + write = 1; + } + + return write; +} + +static struct cmd_node pw_node = { + PW_NODE, "%s(config-pw)# ", 1, +}; + +void zebra_pw_vty_init(void) +{ + install_node(&pw_node, zebra_pw_config); + install_default(PW_NODE); + + install_element(CONFIG_NODE, &pseudowire_if_cmd); + install_element(PW_NODE, &pseudowire_labels_cmd); + install_element(PW_NODE, &pseudowire_neighbor_cmd); + install_element(PW_NODE, &pseudowire_control_word_cmd); + + install_element(VIEW_NODE, &show_pseudowires_cmd); +} diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h new file mode 100644 index 0000000000..417d26fe65 --- /dev/null +++ b/zebra/zebra_pw.h @@ -0,0 +1,75 @@ +/* Zebra PW code + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef ZEBRA_PW_H_ +#define ZEBRA_PW_H_ + +#include +#include + +#include "hook.h" +#include "qobj.h" + +#define PW_INSTALL_RETRY_INTERVAL 30 + +struct zebra_pw { + RB_ENTRY(zebra_pw) pw_entry, static_pw_entry; + vrf_id_t vrf_id; + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + int enabled; + int status; + uint8_t protocol; + struct zserv *client; + struct rnh *rnh; + struct thread *install_retry_timer; + QOBJ_FIELDS +}; +DECLARE_QOBJ_TYPE(zebra_pw) + +RB_HEAD(zebra_pw_head, zebra_pw); +RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare); + +RB_HEAD(zebra_static_pw_head, zebra_pw); +RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); + +DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) +DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) + +struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t, + struct zserv *); +void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *); +void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, + uint32_t, uint32_t, uint8_t, union pw_protocol_fields *); +struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *); +void zebra_pw_update(struct zebra_pw *); +void zebra_pw_install_failure(struct zebra_pw *); +void zebra_pw_client_close(struct zserv *); +void zebra_pw_init(struct zebra_vrf *); +void zebra_pw_exit(struct zebra_vrf *); +void zebra_pw_vty_init(void); + +#endif /* ZEBRA_PW_H_ */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 8ab46f683c..77cfa9860f 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->zebra_static_route_list = list_new(); + rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; rnh->node = rn; @@ -161,6 +162,7 @@ void zebra_free_rnh(struct rnh *rnh) rnh->flags |= ZEBRA_NHT_DELETED; list_free(rnh->client_list); list_free(rnh->zebra_static_route_list); + list_free(rnh->zebra_pseudowire_list); free_state(rnh->vrf_id, rnh->state, rnh->node); XFREE(MTYPE_RNH, rnh); } @@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, } listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list)) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, type); } @@ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, listnode_delete(rnh->zebra_static_route_list, static_rn); if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list)) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); } @@ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id, } } +/* XXX move this utility function elsewhere? */ +static void addr2hostprefix(int af, const union g_addr *addr, + struct prefix *prefix) +{ + switch (af) { + case AF_INET: + prefix->family = AF_INET; + prefix->prefixlen = IPV4_MAX_BITLEN; + prefix->u.prefix4 = addr->ipv4; + break; + case AF_INET6: + prefix->family = AF_INET6; + prefix->prefixlen = IPV6_MAX_BITLEN; + prefix->u.prefix6 = addr->ipv6; + break; + default: + zlog_warn("%s: unknown address family %d", __func__, af); + break; + } +} + +void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct prefix nh; + struct rnh *rnh; + + addr2hostprefix(pw->af, &pw->nexthop, &nh); + rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE); + if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) { + listnode_add(rnh->zebra_pseudowire_list, pw); + pw->rnh = rnh; + zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh); + } +} + +void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct rnh *rnh; + + rnh = pw->rnh; + if (!rnh) + return; + + listnode_delete(rnh->zebra_pseudowire_list, pw); + pw->rnh = NULL; + + if (list_isempty(rnh->client_list) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) + zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); +} + /* Apply the NHT route-map for a client to the route (and nexthops) * resolving a NH. */ @@ -595,6 +651,15 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, } } +static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) +{ + struct zebra_pw *pw; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw)) + zebra_pw_update(pw); +} + /* * See if a tracked nexthop entry has undergone any change, and if so, * take appropriate action; this involves notifying any clients and/or @@ -636,6 +701,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force, /* Process static routes attached to this nexthop */ zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn, rnh->state); + + /* Process pseudowires attached to this nexthop */ + zebra_rnh_process_pseudowires(vrfid, rnh); } } @@ -694,8 +762,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family, re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); - if (re) + if (re) { UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + } } /* Evaluate all tracked entries (nexthops or routes for import into BGP) @@ -840,7 +910,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->nexthop_num != r2->nexthop_num) return 1; - if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)) + if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED) + || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED)) return 1; return 0; @@ -1003,5 +1074,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (!list_isempty(rnh->zebra_static_route_list)) vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); + if (!list_isempty(rnh->zebra_pseudowire_list)) + vty_out(vty, " zebra[pseudowires]"); vty_out(vty, "\n"); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index f8d89ec8ca..7e183684da 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -42,6 +42,8 @@ struct rnh { struct list * zebra_static_route_list; /* static routes dependent on this NH */ + struct list + *zebra_pseudowire_list; /* pseudowires dependent on this NH */ struct route_node *node; int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ @@ -67,6 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t, struct route_node *rn); extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, struct route_node *); +extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *); +extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 6cebae997c..dba228ea35 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "vty.h" #include "zebra/debug.h" @@ -81,11 +82,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix4 = si->addr.ipv4; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &si->addr.ipv4, NULL, si->ifindex); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: nexthop = route_entry_nexthop_ifindex_add(re, si->ifindex); break; @@ -100,7 +101,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix6 = si->addr.ipv6; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &si->addr.ipv6, si->ifindex); break; @@ -156,11 +157,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix4 = si->addr.ipv4; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &si->addr.ipv4, NULL, si->ifindex); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: nexthop = route_entry_nexthop_ifindex_add(re, si->ifindex); break; @@ -175,7 +176,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix6 = si->addr.ipv6; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &si->addr.ipv6, si->ifindex); break; @@ -214,6 +215,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, } } +/* this works correctly with IFNAME<>IFINDEX because a static route on a + * non-active interface will have IFINDEX_INTERNAL and thus compare false + */ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE @@ -225,12 +229,12 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - && si->type == STATIC_IPV4_GATEWAY_IFINDEX + && si->type == STATIC_IPV4_GATEWAY_IFNAME && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4) && nexthop->ifindex == si->ifindex) return 1; else if (nexthop->type == NEXTHOP_TYPE_IFINDEX - && si->type == STATIC_IFINDEX + && si->type == STATIC_IFNAME && nexthop->ifindex == si->ifindex) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV6 @@ -238,7 +242,7 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - && si->type == STATIC_IPV6_GATEWAY_IFINDEX + && si->type == STATIC_IPV6_GATEWAY_IFNAME && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6) && nexthop->ifindex == si->ifindex) return 1; @@ -360,7 +364,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, const char *ifname, u_char flags, + const char *ifname, u_char flags, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label) { @@ -376,15 +380,15 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, if (!gate && (type == STATIC_IPV4_GATEWAY - || type == STATIC_IPV4_GATEWAY_IFINDEX + || type == STATIC_IPV4_GATEWAY_IFNAME || type == STATIC_IPV6_GATEWAY - || type == STATIC_IPV6_GATEWAY_IFINDEX)) + || type == STATIC_IPV6_GATEWAY_IFNAME)) return -1; - if (!ifindex - && (type == STATIC_IFINDEX - || type == STATIC_IPV4_GATEWAY_IFINDEX - || type == STATIC_IPV6_GATEWAY_IFINDEX)) + if (!ifname + && (type == STATIC_IFNAME + || type == STATIC_IPV4_GATEWAY_IFNAME + || type == STATIC_IPV6_GATEWAY_IFNAME)) return -1; /* Lookup static route prefix. */ @@ -397,7 +401,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, && IPV4_ADDR_SAME(gate, &si->addr.ipv4)) || (afi == AFI_IP6 && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!ifindex || ifindex == si->ifindex)) { + && (!strcmp (ifname ? ifname : "", si->ifname))) { if ((distance == si->distance) && (tag == si->tag) && !memcmp(&si->snh_label, snh_label, sizeof(struct static_nh_label)) @@ -411,7 +415,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, /* Distance or tag or label changed, delete existing first. */ if (update) - static_delete_route(afi, safi, type, p, src_p, gate, ifindex, + static_delete_route(afi, safi, type, p, src_p, gate, ifname, update->tag, update->distance, zvrf, &update->snh_label); @@ -423,20 +427,20 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->flags = flags; si->tag = tag; si->vrf_id = zvrf_id(zvrf); - si->ifindex = ifindex; - if (si->ifindex) - strcpy(si->ifname, ifname); + if (ifname) + strlcpy(si->ifname, ifname, sizeof(si->ifname)); + si->ifindex = IFINDEX_INTERNAL; switch (type) { case STATIC_IPV4_GATEWAY: - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: si->addr.ipv4 = gate->ipv4; break; case STATIC_IPV6_GATEWAY: - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: si->addr.ipv6 = gate->ipv6; break; - case STATIC_IFINDEX: + case STATIC_IFNAME: break; } @@ -471,15 +475,25 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->prev = pp; si->next = cp; - /* Install into rib. */ - static_install_route(afi, safi, p, src_p, si); + /* check whether interface exists in system & install if it does */ + if (!ifname) + static_install_route(afi, safi, p, src_p, si); + else { + struct interface *ifp; + + ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); + if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { + si->ifindex = ifp->ifindex; + static_install_route(afi, safi, p, src_p, si); + } + } return 1; } int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, route_tag_t tag, u_char distance, + const char *ifname, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label) { @@ -504,7 +518,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, && IPV4_ADDR_SAME(gate, &si->addr.ipv4)) || (afi == AFI_IP6 && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!ifindex || ifindex == si->ifindex) + && (!strcmp(ifname ? ifname : "", si->ifname)) && (!tag || (tag == si->tag)) && (!snh_label->num_labels || !memcmp(&si->snh_label, snh_label, @@ -517,8 +531,9 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, return 0; } - /* Install into rib. */ - static_uninstall_route(afi, safi, p, src_p, si); + /* Uninstall from rib. */ + if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL) + static_uninstall_route(afi, safi, p, src_p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -536,3 +551,49 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, return 1; } + +static void static_ifindex_update_af(struct interface *ifp, bool up, + afi_t afi, safi_t safi) +{ + struct route_table *stable; + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + struct route_node *rn; + struct static_route *si; + struct prefix *p, *src_pp; + struct prefix_ipv6 *src_p; + + stable = zebra_vrf_static_table(afi, safi, zvrf); + if (!stable) + return; + + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { + srcdest_rnode_prefixes(rn, &p, &src_pp); + src_p = (struct prefix_ipv6 *)src_pp; + + for (si = rn->info; si; si = si->next) { + if (!si->ifname[0]) + continue; + if (up) { + if (strcmp(si->ifname, ifp->name)) + continue; + si->ifindex = ifp->ifindex; + static_install_route(afi, safi, p, src_p, si); + } else { + if (si->ifindex != ifp->ifindex) + continue; + static_uninstall_route(afi, safi, p, src_p, + si); + si->ifindex = IFINDEX_INTERNAL; + } + } + } +} + +/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ +void static_ifindex_update(struct interface *ifp, bool up) +{ + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST); +} diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 885774895f..6ab47094a1 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -30,12 +30,12 @@ struct static_nh_label { }; typedef enum { - STATIC_IFINDEX, + STATIC_IFNAME, STATIC_IPV4_GATEWAY, - STATIC_IPV4_GATEWAY_IFINDEX, + STATIC_IPV4_GATEWAY_IFNAME, STATIC_BLACKHOLE, STATIC_IPV6_GATEWAY, - STATIC_IPV6_GATEWAY_IFINDEX, + STATIC_IPV6_GATEWAY_IFNAME, } zebra_static_types; /* Static route information. */ @@ -84,16 +84,18 @@ extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, const char *ifname, u_char flags, + const char *ifname, u_char flags, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label); extern int static_delete_route(afi_t, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, - union g_addr *gate, ifindex_t ifindex, + union g_addr *gate, const char *ifname, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label); +extern void static_ifindex_update(struct interface *ifp, bool up); + #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index feca13d3a2..ff140bad67 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -95,51 +95,6 @@ static int zebra_vrf_new(struct vrf *vrf) return 0; } -/* - * Moving an interface amongst different vrf's - * causes the interface to get a new ifindex - * so we need to find static routes with - * the old ifindex and replace with new - * ifindex to insert back into the table - */ -void zebra_vrf_static_route_interface_fixup(struct interface *ifp) -{ - afi_t afi; - safi_t safi; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); - struct route_table *stable = NULL; - struct route_node *rn = NULL; - struct static_route *si = NULL; - - if (!zvrf) - return; - - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (stable) - for (rn = route_top(stable); rn; - rn = route_next(rn)) { - if (rn->info) { - si = rn->info; - if ((strcmp(si->ifname, - ifp->name) - == 0) - && (si->ifindex - != ifp->ifindex)) { - si->ifindex = - ifp->ifindex; - static_install_route( - afi, safi, - &rn->p, NULL, - si); - } - } - } - } - } -} - /* Callback upon enabling a VRF. */ static int zebra_vrf_enable(struct vrf *vrf) { @@ -248,6 +203,7 @@ static int zebra_vrf_delete(struct vrf *vrf) zebra_vxlan_close_tables(zvrf); zebra_mpls_close_tables(zvrf); + zebra_pw_exit(zvrf); for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp)) if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); @@ -417,6 +373,7 @@ struct zebra_vrf *zebra_vrf_alloc(void) zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); + zebra_pw_init(zvrf); return zvrf; } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index eb0687bf8a..dca53bb9f3 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -23,6 +23,7 @@ #define __ZEBRA_RIB_H__ #include +#include /* MPLS (Segment Routing) global block */ typedef struct mpls_srgb_t_ { @@ -89,6 +90,10 @@ struct zebra_vrf { /* MPLS Segment Routing Global block */ mpls_srgb_t mpls_srgb; + /* Pseudowires. */ + struct zebra_pw_head pseudowires; + struct zebra_static_pw_head static_pseudowires; + /* MPLS processing flags */ u_int16_t mpls_flags; #define MPLS_FLAG_SCHEDULE_LSPS (1 << 0) @@ -124,7 +129,6 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id, u_int32_t table_id); -extern void zebra_vrf_static_route_interface_fixup(struct interface *ifp); extern void zebra_vrf_update_all(struct zserv *client); extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 13c4429d6a..e260338131 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -55,9 +55,6 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - /* VNI range as per RFC 7432 */ #define CMD_VNI_RANGE "(1-16777215)" @@ -80,7 +77,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, u_char flag = 0; route_tag_t tag = 0; struct zebra_vrf *zvrf; - unsigned int ifindex = 0; u_char type; struct static_nh_label snh_label; @@ -207,26 +203,15 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, gatep = &gate; } - if (ifname) { - struct interface *ifp; - ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); - if (!ifp) { - vty_out(vty, "%% Malformed Interface name %s\n", - ifname); - ifindex = IFINDEX_DELETED; - } else - ifindex = ifp->ifindex; - } - if (gate_str == NULL && ifname == NULL) type = STATIC_BLACKHOLE; else if (gate_str && ifname) { if (afi == AFI_IP) - type = STATIC_IPV4_GATEWAY_IFINDEX; + type = STATIC_IPV4_GATEWAY_IFNAME; else - type = STATIC_IPV6_GATEWAY_IFINDEX; + type = STATIC_IPV6_GATEWAY_IFNAME; } else if (ifname) - type = STATIC_IFINDEX; + type = STATIC_IFNAME; else { if (afi == AFI_IP) type = STATIC_IPV4_GATEWAY; @@ -235,10 +220,10 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, } if (!negate) - static_add_route(afi, safi, type, &p, src_p, gatep, ifindex, - ifname, flag, tag, distance, zvrf, &snh_label); + static_add_route(afi, safi, type, &p, src_p, gatep, ifname, + flag, tag, distance, zvrf, &snh_label); else - static_delete_route(afi, safi, type, &p, src_p, gatep, ifindex, + static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); return CMD_SUCCESS; @@ -1705,7 +1690,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, &si->addr.ipv6, buf, sizeof buf)); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: vty_out(vty, " %s", si->ifname); break; /* blackhole and Null0 mean the same thing */ @@ -1715,7 +1700,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, else vty_out(vty, " Null0"); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: vty_out(vty, " %s %s", inet_ntop(AF_INET, &si->addr.ipv4, buf, @@ -1723,7 +1708,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, ifindex2ifname(si->ifindex, si->vrf_id)); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: vty_out(vty, " %s %s", inet_ntop(AF_INET6, &si->addr.ipv6, buf, diff --git a/zebra/zserv.c b/zebra/zserv.c index 8700cc5102..a3a8c11c51 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1087,6 +1087,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, return zebra_server_send_message(client); } +/* + * Function used by Zebra to send a PW status update to LDP daemon + */ +int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); + stream_write(s, pw->ifname, IF_NAMESIZE); + stream_putl(s, pw->ifindex); + stream_putl(s, pw->status); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zebra_server_send_message(client); +} + /* Register zebra server interface information. Send current all interface and address information. */ static int zread_interface_add(struct zserv *client, u_short length, @@ -1879,14 +1900,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, if (command == ZEBRA_MPLS_LABELS_ADD) { mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, ifindex); - if (out_label != MPLS_IMP_NULL_LABEL) - mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, - ifindex, distance, out_label); + mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, + distance, out_label); } else if (command == ZEBRA_MPLS_LABELS_DELETE) { mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); - if (out_label != MPLS_IMP_NULL_LABEL) - mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, - ifindex, distance, out_label); + mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, + distance, out_label); } } /* Send response to a label manager connect request to client */ @@ -2041,6 +2060,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client, } } +static int zread_pseudowire(int command, struct zserv *client, u_short length, + vrf_id_t vrf_id) +{ + struct stream *s; + struct zebra_vrf *zvrf; + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + uint8_t protocol; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(vrf_id); + if (!zvrf) + return -1; + + /* Get input stream. */ + s = client->ibuf; + + /* Get data. */ + stream_get(ifname, s, IF_NAMESIZE); + ifindex = stream_getl(s); + type = stream_getl(s); + af = stream_getl(s); + switch (af) { + case AF_INET: + nexthop.ipv4.s_addr = stream_get_ipv4(s); + break; + case AF_INET6: + stream_get(&nexthop.ipv6, s, 16); + break; + default: + return -1; + } + local_label = stream_getl(s); + remote_label = stream_getl(s); + flags = stream_getc(s); + stream_get(&data, s, sizeof(data)); + protocol = client->proto; + + pw = zebra_pw_find(zvrf, ifname); + switch (command) { + case ZEBRA_PW_ADD: + if (pw) { + zlog_warn("%s: pseudowire %s already exists [%s]", + __func__, ifname, + zserv_command_string(command)); + return -1; + } + + zebra_pw_add(zvrf, ifname, protocol, client); + break; + case ZEBRA_PW_DELETE: + if (!pw) { + zlog_warn("%s: pseudowire %s not found [%s]", __func__, + ifname, zserv_command_string(command)); + return -1; + } + + zebra_pw_del(zvrf, pw); + break; + case ZEBRA_PW_SET: + case ZEBRA_PW_UNSET: + if (!pw) { + zlog_warn("%s: pseudowire %s not found [%s]", __func__, + ifname, zserv_command_string(command)); + return -1; + } + + switch (command) { + case ZEBRA_PW_SET: + pw->enabled = 1; + break; + case ZEBRA_PW_UNSET: + pw->enabled = 0; + break; + } + + zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label, + remote_label, flags, &data); + break; + } + + return 0; +} + /* Cleanup registered nexthops (across VRFs) upon client disconnect. */ static void zebra_client_close_cleanup_rnh(struct zserv *client) { @@ -2085,6 +2195,9 @@ static void zebra_client_close(struct zserv *client) zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), client); + /* Remove pseudowires associated with this client */ + zebra_pw_client_close(client); + /* Close file descriptor. */ if (client->sock) { unsigned long nroutes; @@ -2438,6 +2551,12 @@ static int zebra_client_read(struct thread *thread) case ZEBRA_INTERFACE_SET_MASTER: zread_interface_set_master(client, sock, length); break; + case ZEBRA_PW_ADD: + case ZEBRA_PW_DELETE: + case ZEBRA_PW_SET: + case ZEBRA_PW_UNSET: + zread_pseudowire(command, client, length, vrf_id); + break; default: zlog_info("Zebra received unknown command %d", command); break; @@ -2591,10 +2710,6 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) now -= *time1; tm = gmtime(&now); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (now < ONE_DAY_SECOND) snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/zebra/zserv.h b/zebra/zserv.h index a2cf5d9f41..f661572d53 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -30,6 +30,8 @@ #include "zclient.h" #include "zebra/zebra_ns.h" +#include "zebra/zebra_pw.h" + /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -175,6 +177,7 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *, vrf_id_t); extern int zsend_interface_link_params(struct zserv *, struct interface *); +extern int zsend_pw_update(struct zserv *, struct zebra_pw *); extern pid_t pid;