diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-04-04 17:55:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-04 17:55:00 +0200 |
commit | b3cfe637a66a5de00c72125f5fa051155ccb4a29 (patch) | |
tree | 16af08958977f24dc9b563bca5bb7a003da0f040 | |
parent | Merge pull request #322 from qlyoung/fix-distance-commands (diff) | |
parent | vtysh: handle "show modules" like "show memory" (diff) | |
download | frr-b3cfe637a66a5de00c72125f5fa051155ccb4a29.tar.xz frr-b3cfe637a66a5de00c72125f5fa051155ccb4a29.zip |
Merge pull request #294 from opensourcerouting/modules
Loadable module support
74 files changed, 1416 insertions, 502 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 50afc7ed6..af6c8faf0 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -67,6 +67,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a +module_LTLIBRARIES = sbin_PROGRAMS = bgpd bin_PROGRAMS = bgp_btoa @@ -75,7 +76,7 @@ libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ - bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \ + bgp_dump.c bgp_ecommunity.c bgp_lcommunity.c \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ @@ -89,7 +90,7 @@ noinst_HEADERS = \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_lcommunity.h \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ - bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ + bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h @@ -101,6 +102,14 @@ bgp_btoa_SOURCES = bgp_btoa.c bgp_btoa_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ bgp_btoa_LDFLAGS = $(BGP_VNC_RFP_LD_FLAGS) +if SNMP +module_LTLIBRARIES += bgpd_snmp.la +endif + +bgpd_snmp_la_SOURCES = bgp_snmp.c +bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +bgpd_snmp_la_LIBADD = ../lib/libfrrsnmp.la + examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \ bgpd.conf.vnc.sample diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 7dc7f053d..2bbdca595 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -45,14 +45,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_advertise.h" -#ifdef HAVE_SNMP -#include "bgpd/bgp_snmp.h" -#endif /* HAVE_SNMP */ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" +DEFINE_HOOK(peer_backward_transition, (struct peer *peer), (peer)) +DEFINE_HOOK(peer_established, (struct peer *peer), (peer)) + /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h */ @@ -1061,9 +1061,7 @@ bgp_stop (struct peer *peer) zlog_debug ("%s remove from all update group", peer->host); update_group_remove_peer_afs(peer); -#ifdef HAVE_SNMP - bgpTrapBackwardTransition (peer); -#endif /* HAVE_SNMP */ + hook_call(peer_backward_transition, peer); /* Reset peer synctime */ peer->synctime = 0; @@ -1508,9 +1506,7 @@ bgp_establish (struct peer *peer) zlog_debug ("%s graceful restart timer stopped", peer->host); } -#ifdef HAVE_SNMP - bgpTrapEstablished (peer); -#endif /* HAVE_SNMP */ + hook_call(peer_established, peer); /* Reset uptime, send keepalive, send current table. */ peer->uptime = bgp_clock (); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index e47d07702..4d0b48f52 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -109,4 +109,8 @@ extern void bgp_start_routeadv (struct bgp *); */ extern void bgp_adjust_routeadv (struct peer *); +#include "hook.h" +DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)) +DECLARE_HOOK(peer_established, (struct peer *peer), (peer)) + #endif /* _QUAGGA_BGP_FSM_H */ diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 5e6218e8a..f45d68384 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -20,7 +20,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -31,6 +30,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "smux.h" #include "filter.h" +#include "hook.h" +#include "libfrr.h" +#include "version.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -38,7 +40,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_fsm.h" -#include "bgpd/bgp_snmp.h" /* BGP4-MIB described in RFC1657. */ #define BGP4MIB 1,3,6,1,2,1,15 @@ -838,7 +839,7 @@ static struct trap_object bgpTrapList[] = {3, {3, 1, BGPPEERSTATE}} }; -void +static int bgpTrapEstablished (struct peer *peer) { int ret; @@ -847,7 +848,7 @@ bgpTrapEstablished (struct peer *peer) ret = inet_aton (peer->host, &addr); if (ret == 0) - return; + return 0; oid_copy_addr (index, &addr, IN_ADDR_SIZE); @@ -857,9 +858,10 @@ bgpTrapEstablished (struct peer *peer) index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPESTABLISHED); + return 0; } -void +static int bgpTrapBackwardTransition (struct peer *peer) { int ret; @@ -868,7 +870,7 @@ bgpTrapBackwardTransition (struct peer *peer) ret = inet_aton (peer->host, &addr); if (ret == 0) - return; + return 0; oid_copy_addr (index, &addr, IN_ADDR_SIZE); @@ -878,12 +880,29 @@ bgpTrapBackwardTransition (struct peer *peer) index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPBACKWARDTRANSITION); + return 0; } -void -bgp_snmp_init (void) +static int +bgp_snmp_init (struct thread_master *tm) { - smux_init (bm->master); + smux_init (tm); REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); + return 0; +} + +static int +bgp_snmp_module_init (void) +{ + hook_register(peer_established, bgpTrapEstablished); + hook_register(peer_backward_transition, bgpTrapBackwardTransition); + hook_register(frr_late_init, bgp_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "bgpd_snmp", + .version = FRR_VERSION, + .description = "bgpd AgentX SNMP module", + .init = bgp_snmp_module_init +) diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h deleted file mode 100644 index 7a0d9dd00..000000000 --- a/bgpd/bgp_snmp.h +++ /dev/null @@ -1,28 +0,0 @@ -/* BGP4 SNMP support - Copyright (C) 1999, 2000 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra 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, or (at your option) any -later version. - -GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#ifndef _QUAGGA_BGP_SNMP_H -#define _QUAGGA_BGP_SNMP_H - -extern void bgp_snmp_init (void); -extern void bgpTrapEstablished (struct peer *); -extern void bgpTrapBackwardTransition (struct peer *); - -#endif /* _QUAGGA_BGP_SNMP_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 30243e80b..1733f2956 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -72,9 +72,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" -#ifdef HAVE_SNMP -#include "bgpd/bgp_snmp.h" -#endif /* HAVE_SNMP */ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" @@ -7647,6 +7644,8 @@ bgp_if_finish (struct bgp *bgp) } } +extern void bgp_snmp_init (void); + void bgp_init (void) { @@ -7695,10 +7694,6 @@ bgp_init (void) /* Community list initialize. */ bgp_clist = community_list_init (); -#ifdef HAVE_SNMP - bgp_snmp_init (); -#endif /* HAVE_SNMP */ - /* BFD init */ bgp_bfd_init(); } diff --git a/configure.ac b/configure.ac index e46e44a8b..5f2e3ed51 100755 --- a/configure.ac +++ b/configure.ac @@ -55,6 +55,13 @@ dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow AC_SUBST(pkgsrcdir) AC_SUBST(pkgsrcrcdir) +AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directory (${libdir}/frr/modules)])], [ + moduledir="$withval" +], [ + moduledir="\${libdir}/frr/modules" +]) +AC_SUBST([moduledir], [$moduledir]) + AC_ARG_ENABLE(tcmalloc, AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]), [case "${enableval}" in @@ -358,9 +365,7 @@ if test "${enable_shell_access}" = "yes"; then AC_DEFINE(HAVE_SHELL_ACCESS,,Allow user to use ssh/telnet/bash) fi -if test "${enable_fpm}" = "yes"; then - AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) -fi +AM_CONDITIONAL([FPM], [test "x$enable_fpm" = "xyes"]) if test "x${enable_dev_build}" = "xyes"; then AC_DEFINE(DEV_BUILD,,Build for development) @@ -1317,8 +1322,8 @@ if test "${enable_snmp}" != ""; then if test x"$NETSNMP_CONFIG" = x"no"; then AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config]) fi - LIBS="$LIBS `${NETSNMP_CONFIG} --agent-libs`" - CFLAGS="`${NETSNMP_CONFIG} --base-cflags` $CFLAGS" + SNMP_LIBS="`${NETSNMP_CONFIG} --agent-libs`" + SNMP_CFLAGS="`${NETSNMP_CONFIG} --base-cflags`" AC_MSG_CHECKING([whether we can link to Net-SNMP]) AC_LINK_IFELSE([AC_LANG_PROGRAM([ int main(void); @@ -1330,7 +1335,6 @@ int main(void); ])],[AC_MSG_RESULT(yes)],[ AC_MSG_RESULT(no) AC_MSG_ERROR([--enable-snmp given but not usable])]) - AC_DEFINE(HAVE_SNMP,,SNMP) case "${enable_snmp}" in yes) SNMP_METHOD=agentx @@ -1346,6 +1350,53 @@ int main(void); AH_TEMPLATE([SNMP_AGENTX], [Use SNMP AgentX to interface with snmpd]) AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd) fi +AM_CONDITIONAL([SNMP], [test "x${SNMP_METHOD}" != "x"]) +AC_SUBST(SNMP_LIBS) +AC_SUBST(SNMP_CFLAGS) + +dnl --------------- +dnl dlopen & dlinfo +dnl --------------- +AC_SEARCH_LIBS(dlopen, [dl dld], [], [ + AC_MSG_ERROR([unable to find the dlopen()]) +]) + +AC_CHECK_HEADERS([link.h]) + +AC_MSG_CHECKING([for dlinfo(RTLD_DI_ORIGIN)]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include <stdlib.h> +#ifdef HAVE_LINK_H +#include <link.h> +#endif +#include <dlfcn.h> +]], [[ + char origin[1]; + dlinfo (NULL, RTLD_DI_ORIGIN, &origin); +]])], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_DLINFO_ORIGIN, 1, [Have dlinfo RTLD_DI_ORIGIN]) +], [ + AC_MSG_RESULT(no) +]) + +AC_MSG_CHECKING([for dlinfo(RTLD_DI_LINKMAP)]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include <stdlib.h> +#ifdef HAVE_LINK_H +#include <link.h> +#endif +#include <dlfcn.h> +]], [[ + struct link_map *lm = NULL; + dlinfo (NULL, RTLD_DI_LINKMAP, &lm); +]])], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_DLINFO_LINKMAP, 1, [Have dlinfo RTLD_DI_LINKMAP]) +], [ + AC_MSG_RESULT(no) +]) + dnl --------------------------- dnl sockaddr and netinet checks @@ -1646,14 +1697,18 @@ AC_DEFINE_UNQUOTED(VTYSH_BIN_PATH, "$vtysh_bin",path to vtysh binary) CFG_SYSCONF="$sysconfdir" CFG_SBIN="$sbindir" CFG_STATE="$frr_statedir" +CFG_MODULE="$moduledir" for I in 1 2 3 4 5 6 7 8 9 10; do eval CFG_SYSCONF="\"$CFG_SYSCONF\"" eval CFG_SBIN="\"$CFG_SBIN\"" eval CFG_STATE="\"$CFG_STATE\"" + eval CFG_MODULE="\"$CFG_MODULE\"" done AC_SUBST(CFG_SYSCONF) AC_SUBST(CFG_SBIN) AC_SUBST(CFG_STATE) +AC_SUBST(CFG_MODULE) +AC_DEFINE_UNQUOTED(MODULE_PATH, "$CFG_MODULE", path to modules) dnl --------------------------- dnl Check htonl works correctly @@ -1728,6 +1783,7 @@ linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${frr_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` example directory : `eval echo \`echo ${exampledir}\`` +module directory : ${CFG_MODULE} user to run as : ${enable_user} group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} diff --git a/doc/basic.texi b/doc/basic.texi index cea33eaa8..05d72bc80 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -18,6 +18,7 @@ daemons. * Config Commands:: Commands used in config files * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons +* Loadable Module Support:: Using extension modules * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @@ -372,6 +373,51 @@ Print program version. @end table +@node Loadable Module Support +@section Loadable Module Support + +FRR supports loading extension modules at startup. Loading, reloading or +unloading modules at runtime is not supported (yet). To load a module, use +the following command line option at daemon startup: + +@table @samp +@item -M @var{module:options} +@itemx --module @var{module:options} + +Load the specified module, optionally passing options to it. If the module +name contains a slash (/), it is assumed to be a full pathname to a file to +be loaded. If it does not contain a slash, the +@code{@value{INSTALL_PREFIX_MODULES}} directory is searched for a module of +the given name; first with the daemon name prepended (e.g. @code{zebra_mod} +for @code{mod}), then without the daemon name prepended. + +This option is available on all daemons, though some daemons may not have +any modules available to be loaded. +@end table + + +@subsection The SNMP Module + +If SNMP is enabled during compile-time and installed as part of the package, +the @code{snmp} module can be loaded for the @command{zebra}, +@command{bgpd}, @command{ospfd}, @command{ospf6d} and @command{ripd} daemons. + +The module ignores any options passed to it. Refer to @ref{SNMP Support} +for information on its usage. + + +@subsection The FPM Module + +If FPM is enabled during compile-time and installed as part of the package, +the @code{fpm} module can be loaded for the @command{zebra} daemon. This +provides the Forwarding Plane Manager ("FPM") API. + +The module expects its argument to be either @code{netlink} or +@code{protobuf}, specifying the encapsulation to use. @code{netlink} is the +default, and @code{protobuf} may not be available if the module was built +without protobuf support. Refer to @ref{zebra FIB push interface} for more +information. + @node Virtual Terminal Interfaces @section Virtual Terminal Interfaces diff --git a/doc/bgpd.8.in b/doc/bgpd.8.in index 9026f2cde..0df1b1dce 100644 --- a/doc/bgpd.8.in +++ b/doc/bgpd.8.in @@ -27,6 +27,9 @@ bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with @PACKAGE_FULLNAME@ ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B bgpd @@ -76,6 +79,11 @@ When the program terminates, retain routes added by \fBbgpd\fR. \fB\-S\fR, \fB\-\-skip_runas\fR Skip setting the process effective user and group. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBbgpd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/defines.texi.in b/doc/defines.texi.in index 43d744293..0fadba964 100644 --- a/doc/defines.texi.in +++ b/doc/defines.texi.in @@ -13,6 +13,7 @@ @set INSTALL_PREFIX_ETC @CFG_SYSCONF@ @set INSTALL_PREFIX_SBIN @CFG_SBIN@ @set INSTALL_PREFIX_STATE @CFG_STATE@ +@set INSTALL_PREFIX_MODULES @CFG_MODULE@ @set INSTALL_USER @enable_user@ @set INSTALL_GROUP @enable_group@ @set INSTALL_VTY_GROUP @enable_vty_group@ diff --git a/doc/dev-modules.md b/doc/dev-modules.md new file mode 100644 index 000000000..87bc96318 --- /dev/null +++ b/doc/dev-modules.md @@ -0,0 +1,119 @@ +# Module and Hook support (developer docs) + +## What it does + +It uses `dlopen()` to load DSOs at startup. + + +## Limitations + +* can't load, unload, or reload during runtime. This just needs some work + and can probably be done in the future. +* doesn't fix any of the "things need to be changed in the code in the library" + issues. Most prominently, you can't add a CLI node because CLI nodes are + listed in the library... +* if your module crashes, the daemon crashes. Should be obvious. +* **does not provide a stable API or ABI**. Your module must match a version + of FRR and you may have to update it frequently to match changes. +* **does not create a license boundary**. Your module will need to link + libzebra and include header files from the daemons, meaning it will be + GPL-encumbered. + + +## Installation + +Look for `moduledir` in `configure.ac`, default is normally +`/usr/lib64/frr/modules` but depends on `--libdir` / `--prefix`. + +The daemon's name is prepended when looking for a module, e.g. "snmp" tries +to find "zebra_snmp" first when used in zebra. This is just to make it nicer +for the user, with the snmp module having the same name everywhere. + +Modules can be packaged separately from FRR. The SNMP and FPM modules are +good candidates for this because they have dependencies (net-snmp / protobuf) +that are not FRR dependencies. However, any distro packages should have an +"exact-match" dependency onto the FRR package. Using a module from a +different FRR version will probably blow up nicely. + +For snapcraft (and during development), modules can be loaded with full path +(e.g. -M `$SNAP/lib/frr/modules/zebra_snmp.so`). Note that libtool puts output +files in the .libs directory, so during development you have to use +`./zebra -M .libs/zebra_snmp.so`. + + +## Creating a module + +... best to look at the existing SNMP or FPM modules. + +Basic boilerplate: + +``` +#include "hook.h" +#include "module.h" + +static int +module_init (void) +{ + hook_register(frr_late_init, module_late_init); + return 0; +} + +FRR_MODULE_SETUP( + .name = "my module", + .version = "0.0", + .description = "my module", + .init = module_init, +) +``` + +The `frr_late_init` hook will be called after the daemon has finished its +other startup and is about to enter the main event loop; this is the best +place for most initialisation. + + +## Compiler & Linker magic + +There's a `THIS_MODULE` (like in the Linux kernel), which uses `visibility` +attributes to restrict it to the current module. If you get a linker error +with `_frrmod_this_module`, there is some linker SNAFU. This shouldn't be +possible, though one way to get it would be to not include libzebra (which +provides a fallback definition for the symbol). + +libzebra and the daemons each have their own `THIS_MODULE`, as do all loadable +modules. In any other libraries (e.g. `libfrrsnmp`), `THIS_MODULE` will use +the definition in libzebra; same applies if the main executable doesn't use +`FRR_DAEMON_INFO` (e.g. all testcases). + +The deciding factor here is "what dynamic linker unit are you using the symbol +from." If you're in a library function and want to know who called you, you +can't use `THIS_MODULE` (because that'll just tell you you're in the library). +Put a macro around your function that adds `THIS_MODULE` in the *caller's +code calling your function*. + +The idea is to use this in the future for module unloading. Hooks already +remember which module they were installed by, as groundwork for a function +that removes all of a module's installed hooks. + +There's also the `frr_module` symbol in modules, pretty much a standard entry +point for loadable modules. + + +## Hooks + +Hooks are just points in the code where you can register your callback to +be called. The parameter list is specific to the hook point. Since there is +no stable API, the hook code has some extra type safety checks making sure +you get a compiler warning when the hook parameter list doesn't match your +callback. Don't ignore these warnings. + + +## Relation to MTYPE macros + +The MTYPE macros, while primarily designed to decouple MTYPEs from the library +and beautify the code, also work very nicely with loadable modules -- both +constructors and destructors are executed when loading/unloading modules. + +This means there is absolutely no change required to MTYPEs, you can just use +them in a module and they will even clean up themselves when we implement +module unloading and an unload happens. In fact, it's impossible to create +a bug where unloading fails to de-register a MTYPE. diff --git a/doc/isisd.8.in b/doc/isisd.8.in index 9ffcbc618..542c28993 100644 --- a/doc/isisd.8.in +++ b/doc/isisd.8.in @@ -23,6 +23,9 @@ isisd \- an IS-IS routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B isisd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBisisd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ldpd.8.in b/doc/ldpd.8.in index 1683de46c..2d68a31a5 100644 --- a/doc/ldpd.8.in +++ b/doc/ldpd.8.in @@ -23,6 +23,9 @@ ldpd \- an LDP engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ldpd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBldpd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/main.texi b/doc/main.texi index dfe02e1b5..706baa25f 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -385,7 +385,8 @@ ip protocol rip route-map RM1 Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Frr -routing suite. +routing suite. This is a loadable module that needs to be enabled +at startup as described in @ref{Loadable Module Support}. In Frr, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and @@ -440,9 +441,9 @@ independently. @end itemize As mentioned before, zebra encodes routes sent to the FPM in netlink -format by default. The format can be controlled via the -@code{--fpm_format} command-line option to zebra, which currently -takes the values @code{netlink} and @code{protobuf}. +format by default. The format can be controlled via the FPM module's +load-time option to zebra, which currently takes the values @code{netlink} +and @code{protobuf}. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, diff --git a/doc/nhrpd.8.in b/doc/nhrpd.8.in index c5e4f7e32..09b662ae7 100644 --- a/doc/nhrpd.8.in +++ b/doc/nhrpd.8.in @@ -23,6 +23,9 @@ nhrpd \- a Next Hop Routing Protocol routing engine for use with @PACKAGE_FULLNA ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B nhrpd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBnhrpd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ospf6d.8.in b/doc/ospf6d.8.in index 7f94782be..02d9d8083 100644 --- a/doc/ospf6d.8.in +++ b/doc/ospf6d.8.in @@ -23,6 +23,9 @@ ospf6d \- an OSPFv3 routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ospf6d @@ -64,6 +67,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBospf6d\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ospfd.8.in b/doc/ospfd.8.in index 1b86551ca..6bad77771 100644 --- a/doc/ospfd.8.in +++ b/doc/ospfd.8.in @@ -23,6 +23,9 @@ ospfd \- an OSPFv2 routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ospfd @@ -66,6 +69,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-a\fR, \fB\-\-apiserver \fR Enable OSPF apiserver. Default is disabled. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBospfd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/pimd.8.in b/doc/pimd.8.in index 60b844b1e..3fb060e56 100644 --- a/doc/pimd.8.in +++ b/doc/pimd.8.in @@ -26,6 +26,9 @@ pimd \- a PIM routing for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B pimd @@ -70,6 +73,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBpimd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .TP diff --git a/doc/ripd.8.in b/doc/ripd.8.in index 6db5ac364..a84668e6d 100644 --- a/doc/ripd.8.in +++ b/doc/ripd.8.in @@ -23,6 +23,9 @@ ripd \- a RIP routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ripd @@ -67,6 +70,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBripd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ripngd.8.in b/doc/ripngd.8.in index 4c5f2bb11..98039219a 100644 --- a/doc/ripngd.8.in +++ b/doc/ripngd.8.in @@ -23,6 +23,9 @@ ripngd \- a RIPNG routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ripngd @@ -67,6 +70,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBripngd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/snmp.texi b/doc/snmp.texi index c2c889de7..d9656941d 100644 --- a/doc/snmp.texi +++ b/doc/snmp.texi @@ -8,6 +8,10 @@ but is able to connect to a SNMP agent using the SMUX protocol (@cite{RFC1227}) or the AgentX protocol (@cite{RFC2741}) and make the routing protocol MIBs available through it. +Note that SNMP Support needs to be enabled at compile-time and loaded as +module on daemon startup. Refer to @ref{Loadable Module Support} on +the latter. + @menu * Getting and installing an SNMP agent:: * AgentX configuration:: diff --git a/doc/watchfrr.8.in b/doc/watchfrr.8.in index 813f87abd..82098e1b0 100644 --- a/doc/watchfrr.8.in +++ b/doc/watchfrr.8.in @@ -108,13 +108,13 @@ Set the logging (LOG_DEBUG), but higher number can be supplied if extra debugging messages are required. .TP -.BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number +.BI \-\-min\-restart\-interval " number Set the minimum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "60"). .TP -.BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number +.BI \-\-max\-restart\-interval " number Set the maximum .I number of seconds to wait between invocations of the daemon restart commands (the diff --git a/doc/zebra.8.in b/doc/zebra.8.in index 4599a8563..f5b8bd4d8 100644 --- a/doc/zebra.8.in +++ b/doc/zebra.8.in @@ -23,6 +23,9 @@ zebra \- a routing manager for use with associated @PACKAGE_FULLNAME@ components ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B zebra @@ -86,6 +89,14 @@ maximum before starting zebra. Note that this affects Linux only. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR and \fBfpm\fR modules may be +available for \fBzebra\fR, if the package was built with SNMP and FPM support +respectively. The \fBfpm\fR module takes an additional colon-separated +argument specifying the encapsulation, either \fBnetlink\fR or \fBprotobuf\fR. +It should thus be loaded with \fB-M fpm:netlink\fR or \fB-M fpm:protobuf\fR. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/lib/Makefile.am b/lib/Makefile.am index 1a8c7af42..14b7130c8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -20,7 +20,7 @@ libfrr_la_SOURCES = \ command.c \ sockunion.c prefix.c thread.c if.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c log.c plist.c \ - zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ + zclient.c sockopt.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \ ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \ imsg-buffer.c imsg.c skiplist.c \ @@ -31,12 +31,28 @@ libfrr_la_SOURCES = \ spf_backoff.c \ libfrr.c \ strlcpy.c \ - strlcat.c + strlcat.c \ + module.c \ + hook.c \ + # end BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h libfrr_la_LIBADD = @LIBCAP@ +if SNMP +lib_LTLIBRARIES += libfrrsnmp.la +endif + +libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 +libfrrsnmp_la_LIBADD = libfrr.la $(SNMP_LIBS) +libfrrsnmp_la_SOURCES = \ + agentx.c \ + smux.c \ + snmp.c \ + #end + pkginclude_HEADERS = \ buffer.h checksum.h filter.h getopt.h hash.h \ if.h linklist.h log.h \ @@ -54,6 +70,8 @@ pkginclude_HEADERS = \ monotime.h \ spf_backoff.h \ srcdest_table.h \ + module.h \ + hook.h \ libfrr.h \ # end diff --git a/lib/agentx.c b/lib/agentx.c index 4175e7ba9..11d5c9385 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -21,7 +21,7 @@ #include <zebra.h> -#if defined HAVE_SNMP && defined SNMP_AGENTX +#ifdef SNMP_AGENTX #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> @@ -315,4 +315,4 @@ smux_trap (struct variable *vp, size_t vp_len, return 1; } -#endif /* HAVE_SNMP */ +#endif /* SNMP_AGENTX */ diff --git a/lib/hook.c b/lib/hook.c new file mode 100644 index 000000000..04d803cd8 --- /dev/null +++ b/lib/hook.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "memory.h" +#include "hook.h" + +DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry") + +void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg, + struct frrmod_runtime *module, const char *funcname) +{ + struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)); + he->hookfn = funcptr; + he->hookarg = arg; + he->has_arg = has_arg; + he->module = module; + he->fnname = funcname; + + he->next = hook->entries; + hook->entries = he; +} + +void _hook_unregister(struct hook *hook, void *funcptr, + void *arg, bool has_arg) +{ + struct hookent *he, **prev; + + for (prev = &hook->entries; (he = *prev) != NULL; prev = &he->next) + if (he->hookfn == funcptr && he->hookarg == arg + && he->has_arg == has_arg) + { + *prev = he->next; + XFREE(MTYPE_HOOK_ENTRY, he); + break; + } +} + diff --git a/lib/hook.h b/lib/hook.h new file mode 100644 index 000000000..0cb7ab5c7 --- /dev/null +++ b/lib/hook.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _FRR_HOOK_H +#define _FRR_HOOK_H + +#include <stdbool.h> + +#include "module.h" +#include "memory.h" + +/* type-safe subscribable hook points + * + * where "type-safe" applies to the function pointers used for subscriptions + * + * overall usage: + * - to create a hook: + * + * mydaemon.h: + * #include "hook.h" + * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * + * mydaemon.c: + * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * ... + * hook_call (some_update_event, info) + * + * Note: the second and third macro args must be the hook function's + * parameter list, with the same names for each parameter. The second + * macro arg is with types (used for defining things), the third arg is + * just the names (used for passing along parameters). + * + * Do not use parameter names starting with "hook", these can collide with + * names used by the hook code itself. + * + * The return value is always "int" for now; hook_call will sum up the + * return values from each registered user. Default is 0. + * + * There are no pre-defined semantics for the value, in most cases it is + * ignored. For success/failure indication, 0 should be success, and + * handlers should make sure to only return 0 or 1 (not -1 or other values). + * + * + * - to use a hook / create a handler: + * + * #include "mydaemon.h" + * int event_handler (struct eventinfo *info) { ... } + * hook_register (some_update_event, event_handler); + * + * or, if you need an argument to be passed along (addonptr will be added + * as first argument when calling the handler): + * + * #include "mydaemon.h" + * int event_handler (void *addonptr, struct eventinfo *info) { ... } + * hook_register_arg (some_update_event, event_handler, addonptr); + * + * (addonptr isn't typesafe, but that should be manageable.) + */ + +/* TODO: + * - hook_unregister_all_module() + * - introspection / CLI / debug + * - testcases ;) + * + * For loadable modules, the idea is that hooks could be automatically + * unregistered when a module is unloaded. + * + * It's also possible to add a constructor (MTYPE style) to DEFINE_HOOK, + * which would make it possible for the CLI to show all hooks and all + * registered handlers. + */ + +struct hookent { + struct hookent *next; + void *hookfn; /* actually a function pointer */ + void *hookarg; + bool has_arg; + struct frrmod_runtime *module; + const char *fnname; +}; + +struct hook { + const char *name; + struct hookent *entries; +}; + +/* subscribe/add callback function to a hook + * + * always use hook_register(), which uses the static inline helper from + * DECLARE_HOOK in order to get type safety + */ +extern void _hook_register(struct hook *hook, void *funcptr, void *arg, + bool has_arg, struct frrmod_runtime *module, + const char *funcname); +#define hook_register(hookname, func) \ + _hook_register(&_hook_ ## hookname, \ + _hook_typecheck_ ## hookname (func), \ + NULL, false, THIS_MODULE, #func) +#define hook_register_arg(hookname, func, arg) \ + _hook_register(&_hook_ ## hookname, \ + _hook_typecheck_arg_ ## hookname (func), \ + arg, true, THIS_MODULE, #func) + +extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, + bool has_arg); +#define hook_unregister(hookname, func) \ + _hook_unregister(&_hook_ ## hookname, \ + _hook_typecheck_ ## hookname (func), NULL, false) +#define hook_unregister_arg(hookname, func, arg) \ + _hook_unregister(&_hook_ ## hookname, \ + _hook_typecheck_arg_ ## hookname (func), arg, true) + +/* invoke hooks + * this is private (static) to the file that has the DEFINE_HOOK statement + */ +#define hook_call(hookname, ...) \ + hook_call_ ## hookname (__VA_ARGS__) + +/* helpers to add the void * arg */ +#define HOOK_ADDDEF(...) (void *hookarg , ## __VA_ARGS__) +#define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__) + +/* use in header file - declares the hook and its arguments + * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2)) + * as above, "passlist" must use the same order and same names as "arglist" + * + * theoretically passlist is not neccessary, but let's keep things simple and + * use exact same args on DECLARE and DEFINE. + */ +#define DECLARE_HOOK(hookname, arglist, passlist) \ + extern struct hook _hook_ ## hookname; \ + __attribute__((unused)) \ + static void *_hook_typecheck_ ## hookname ( \ + int (*funcptr) arglist) { \ + return (void *)funcptr; } \ + __attribute__((unused)) \ + static void *_hook_typecheck_arg_ ## hookname ( \ + int (*funcptr) HOOK_ADDDEF arglist) { \ + return (void *)funcptr; } + +/* use in source file - contains hook-related definitions. + */ +#define DEFINE_HOOK(hookname, arglist, passlist) \ + struct hook _hook_ ## hookname = { \ + .name = #hookname, \ + .entries = NULL, \ + }; \ + static int hook_call_ ## hookname arglist { \ + int hooksum = 0; \ + struct hookent *he = _hook_ ## hookname .entries; \ + void *hookarg; \ + union { \ + void *voidptr; \ + int (*fptr) arglist; \ + int (*farg) HOOK_ADDDEF arglist; \ + } hookp; \ + for (; he; he = he->next) { \ + hookarg = he->hookarg; \ + hookp.voidptr = he->hookfn; \ + if (!he->has_arg) \ + hooksum += hookp.fptr passlist; \ + else \ + hooksum += hookp.farg HOOK_ADDARG passlist; \ + } \ + return hooksum; \ + } + +#endif /* _FRR_HOOK_H */ diff --git a/lib/libfrr.c b/lib/libfrr.c index b7ce0679c..64f8be2ca 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -28,6 +28,9 @@ #include "memory_vty.h" #include "zclient.h" #include "log_int.h" +#include "module.h" + +DEFINE_HOOK(frr_late_init, (struct thread_master *tm), (tm)) const char frr_sysconfdir[] = SYSCONFDIR; const char frr_vtydir[] = DAEMON_VTY_DIR; @@ -64,14 +67,16 @@ static const struct option lo_always[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, { NULL } }; static const struct optspec os_always = { - "hvdi:", + "hvdM:", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" + " -M, --module Load specified module\n" " --vty_socket Override vty socket path\n", lo_always }; @@ -184,12 +189,18 @@ void frr_help_exit(int status) exit(status); } +struct option_chain { + struct option_chain *next; + const char *arg; +}; +static struct option_chain *modules = NULL, **modnext = &modules; static int errors = 0; static int frr_opt(int opt) { static int vty_port_set = 0; static int vty_addr_set = 0; + struct option_chain *oc; char *err; switch (opt) { @@ -203,6 +214,13 @@ static int frr_opt(int opt) case 'd': di->daemon_mode = 1; break; + case 'M': + oc = XMALLOC(MTYPE_TMP, sizeof(*oc)); + oc->arg = optarg; + oc->next = NULL; + *modnext = oc; + modnext = &oc->next; + break; case 'i': if (di->flags & FRR_NO_CFG_PID_DRY) return 1; @@ -295,9 +313,12 @@ int frr_getopt(int argc, char * const argv[], int *longindex) return opt; } +static struct thread_master *master; struct thread_master *frr_init(void) { - struct thread_master *master; + struct option_chain *oc; + struct frrmod_runtime *module; + char moderr[256]; srandom(time(NULL)); @@ -307,6 +328,17 @@ struct thread_master *frr_init(void) zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl); #endif + frrmod_init(di->module); + while (modules) { + modules = (oc = modules)->next; + module = frrmod_load(oc->arg, moderr, sizeof(moderr)); + if (!module) { + fprintf(stderr, "%s\n", moderr); + exit(1); + } + XFREE(MTYPE_TMP, oc); + } + zprivs_init(di->privs); master = thread_master_create(); @@ -324,6 +356,8 @@ struct thread_master *frr_init(void) void frr_config_fork(void) { + hook_call(frr_late_init, master); + if (di->instance) { snprintf(config_default, sizeof(config_default), "%s/%s-%d.conf", frr_sysconfdir, di->name, di->instance); diff --git a/lib/libfrr.h b/lib/libfrr.h index d37f406f5..a40fc3489 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -26,6 +26,8 @@ #include "thread.h" #include "log.h" #include "getopt.h" +#include "module.h" +#include "hook.h" #define FRR_NO_PRIVSEP (1 << 0) #define FRR_NO_TCPVTY (1 << 1) @@ -40,6 +42,7 @@ struct frr_daemon_info { const char *name; const char *logname; unsigned short instance; + struct frrmod_runtime *module; char *vty_addr; int vty_port; @@ -67,15 +70,22 @@ struct frr_daemon_info { * i.e. "ZEBRA" or "BGP" * * note that this macro is also a latch-on point for other changes (e.g. - * upcoming plugin support) that need to place some per-daemon things. Each + * upcoming module support) that need to place some per-daemon things. Each * daemon should have one of these. */ #define FRR_DAEMON_INFO(execname, constname, ...) \ static struct frr_daemon_info execname ##_di = { \ .name = # execname, \ .logname = # constname, \ + .module = THIS_MODULE, \ __VA_ARGS__ \ - }; + }; \ + FRR_COREMOD_SETUP( \ + .name = # execname, \ + .description = # execname " daemon", \ + .version = FRR_VERSION, \ + ) \ + /* end */ extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv); @@ -86,6 +96,7 @@ extern void frr_help_exit(int status); extern struct thread_master *frr_init(void); +DECLARE_HOOK(frr_late_init, (struct thread_master *tm), (tm)) extern void frr_config_fork(void); extern void frr_vty_serv(void); diff --git a/lib/memory_vty.c b/lib/memory_vty.c index 149b32913..6d63bc2d5 100644 --- a/lib/memory_vty.c +++ b/lib/memory_vty.c @@ -1,23 +1,22 @@ /* - * Memory management routine - * Copyright (C) 1998 Kunihiro Ishiguro + * Memory and dynamic module VTY routine * - * This file is part of GNU Zebra. + * Copyright (C) 1998 Kunihiro Ishiguro + * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc. * - * GNU Zebra 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, or (at your option) any - * later version. + * 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. * - * GNU Zebra 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. + * 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA */ #include <zebra.h> @@ -25,9 +24,12 @@ #if (defined(GNU_LINUX) && defined(HAVE_MALLINFO)) #include <malloc.h> #endif /* HAVE_MALLINFO */ +#include <dlfcn.h> +#include <link.h> #include "log.h" #include "memory.h" +#include "module.h" #include "memory_vty.h" /* Looking up memory status from vty interface. */ @@ -110,10 +112,55 @@ DEFUN (show_memory, return CMD_SUCCESS; } +DEFUN (show_modules, + show_modules_cmd, + "show modules", + "Show running system information\n" + "Loaded modules\n") +{ + struct frrmod_runtime *plug = frrmod_list; + + vty_out (vty, "%-12s %-25s %s%s%s", + "Module Name", "Version", "Description", + VTY_NEWLINE, VTY_NEWLINE); + while (plug) + { + const struct frrmod_info *i = plug->info; + + vty_out (vty, "%-12s %-25s %s%s", i->name, i->version, i->description, + VTY_NEWLINE); + if (plug->dl_handle) + { +#ifdef HAVE_DLINFO_ORIGIN + char origin[MAXPATHLEN] = ""; + dlinfo (plug->dl_handle, RTLD_DI_ORIGIN, &origin); +# ifdef HAVE_DLINFO_LINKMAP + const char *name; + struct link_map *lm = NULL; + dlinfo (plug->dl_handle, RTLD_DI_LINKMAP, &lm); + if (lm) + { + name = strrchr(lm->l_name, '/'); + name = name ? name + 1 : lm->l_name; + vty_out (vty, "\tfrom: %s/%s%s", origin, name, VTY_NEWLINE); + } +# else + vty_out (vty, "\tfrom: %s %s", origin, plug->load_name, VTY_NEWLINE); +# endif +#else + vty_out (vty, "\tfrom: %s%s", plug->load_name, VTY_NEWLINE); +#endif + } + plug = plug->next; + } + return CMD_SUCCESS; +} + void memory_init (void) { install_element (VIEW_NODE, &show_memory_cmd); + install_element (VIEW_NODE, &show_modules_cmd); } /* Stats querying from users */ diff --git a/lib/module.c b/lib/module.c new file mode 100644 index 000000000..4ebe3c0da --- /dev/null +++ b/lib/module.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <dlfcn.h> + +#include "module.h" +#include "memory.h" +#include "version.h" + +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") + +static struct frrmod_info frrmod_default_info = { + .name = "libfrr", + .version = FRR_VERSION, + .description = "libfrr core module", +}; +union _frrmod_runtime_u frrmod_default = { + .r.info = &frrmod_default_info, + .r.finished_loading = 1, +}; + +// if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) +// union _frrmod_runtime_u _frrmod_this_module +// __attribute__((weak, alias("frrmod_default"))); +// elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) +#pragma weak _frrmod_this_module = frrmod_default +// else +// error need weak symbol support +// endif + +struct frrmod_runtime *frrmod_list = &frrmod_default.r; +static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next; +static const char *execname = NULL; + +void frrmod_init(struct frrmod_runtime *modinfo) +{ + modinfo->finished_loading = 1; + *frrmod_last = modinfo; + frrmod_last = &modinfo->next; + + execname = modinfo->info->name; +} + +struct frrmod_runtime *frrmod_load(const char *spec, + char *err, size_t err_len) +{ + void *handle = NULL; + char name[PATH_MAX], fullpath[PATH_MAX], *args; + struct frrmod_runtime *rtinfo, **rtinfop; + const struct frrmod_info *info; + + snprintf(name, sizeof(name), "%s", spec); + args = strchr(name, ':'); + if (args) + *args++ = '\0'; + + if (!strchr(name, '/')) { + if (!handle && execname) { + snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", + MODULE_PATH, execname, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s/%s.so", + MODULE_PATH, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s", name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + if (err) + snprintf(err, err_len, + "loading module \"%s\" failed: %s", + name, dlerror()); + return NULL; + } + + rtinfop = dlsym(handle, "frr_module"); + if (!rtinfop) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "\"%s\" is not a Quagga module: %s", + name, dlerror()); + return NULL; + } + rtinfo = *rtinfop; + rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name); + rtinfo->dl_handle = handle; + if (args) + rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args); + info = rtinfo->info; + + if (rtinfo->finished_loading) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" already loaded", + name); + goto out_fail; + } + + if (info->init && info->init()) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" initialisation failed", + name); + goto out_fail; + } + + rtinfo->finished_loading = 1; + + *frrmod_last = rtinfo; + frrmod_last = &rtinfo->next; + return rtinfo; + +out_fail: + if (rtinfo->load_args) + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + return NULL; +} + +#if 0 +void frrmod_unload(struct frrmod_runtime *module) +{ +} +#endif diff --git a/lib/module.h b/lib/module.h new file mode 100644 index 000000000..cb66e6097 --- /dev/null +++ b/lib/module.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _FRR_MODULE_H +#define _FRR_MODULE_H + +#include <stdint.h> +#include <stdbool.h> + +#if !defined(__GNUC__) +# error module code needs GCC visibility extensions +#elif __GNUC__ < 4 +# error module code needs GCC visibility extensions +#else +# define DSO_PUBLIC __attribute__ ((visibility ("default"))) +# define DSO_SELF __attribute__ ((visibility ("protected"))) +# define DSO_LOCAL __attribute__ ((visibility ("hidden"))) +#endif + +struct frrmod_runtime; + +struct frrmod_info { + /* single-line few-word title */ + const char *name; + /* human-readable version number, should not contain spaces */ + const char *version; + /* one-paragraph description */ + const char *description; + + int (*init)(void); +}; + +/* primary entry point structure to be present in loadable module under + * "_frrmod_this_module" dlsym() name + * + * note space for future extensions is reserved below, so other modules + * (e.g. memory management, hooks) can add fields + * + * const members/info are in frrmod_info. + */ +struct frrmod_runtime { + struct frrmod_runtime *next; + + const struct frrmod_info *info; + void *dl_handle; + bool finished_loading; + + char *load_name; + char *load_args; +}; + +/* space-reserving foo */ +struct _frrmod_runtime_size { + struct frrmod_runtime r; + /* this will barf if frrmod_runtime exceeds 1024 bytes ... */ + uint8_t space[1024 - sizeof(struct frrmod_runtime)]; +}; +union _frrmod_runtime_u { + struct frrmod_runtime r; + struct _frrmod_runtime_size s; +}; + +extern union _frrmod_runtime_u _frrmod_this_module; +#define THIS_MODULE (&_frrmod_this_module.r) + +#define FRR_COREMOD_SETUP(...) \ + static const struct frrmod_info _frrmod_info = { __VA_ARGS__ }; \ + DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \ + .r.info = &_frrmod_info, \ + }; +#define FRR_MODULE_SETUP(...) \ + FRR_COREMOD_SETUP(__VA_ARGS__) \ + DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; + +extern struct frrmod_runtime *frrmod_list; + +extern void frrmod_init(struct frrmod_runtime *modinfo); +extern struct frrmod_runtime *frrmod_load(const char *spec, + char *err, size_t err_len); +#if 0 +/* not implemented yet */ +extern void frrmod_unload(struct frrmod_runtime *module); +#endif + +#endif /* _FRR_MODULE_H */ diff --git a/lib/smux.c b/lib/smux.c index 3abfadcd2..370b8f138 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -21,7 +21,7 @@ #include <zebra.h> -#if defined HAVE_SNMP && defined SNMP_SMUX +#ifdef SNMP_SMUX #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -1445,4 +1445,4 @@ smux_start(void) /* Schedule first connection. */ smux_event (SMUX_SCHEDULE, 0); } -#endif /* HAVE_SNMP */ +#endif /* SNMP_SMUX */ diff --git a/lib/snmp.c b/lib/snmp.c index f6f9845e2..1cbd41c72 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -21,7 +21,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -130,4 +129,3 @@ smux_header_table (struct variable *v, oid *name, size_t *length, int exact, return MATCH_SUCCEEDED; } -#endif /* HAVE_SNMP */ diff --git a/lib/thread.c b/lib/thread.c index 6138e7971..e707fc584 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1037,28 +1037,6 @@ thread_process_fds_helper (struct thread_master *m, struct thread *thread, threa #if defined(HAVE_POLL) -#if defined(HAVE_SNMP) -/* add snmp fds to poll set */ -static void -add_snmp_pollfds(struct thread_master *m, fd_set *snmpfds, int fdsetsize) -{ - int i; - m->handler.pfdcountsnmp = m->handler.pfdcount; - /* cycle trough fds and add neccessary fds to poll set */ - for (i=0;i<fdsetsize;++i) - { - if (FD_ISSET(i, snmpfds)) - { - assert (m->handler.pfdcountsnmp <= m->handler.pfdsize); - - m->handler.pfds[m->handler.pfdcountsnmp].fd = i; - m->handler.pfds[m->handler.pfdcountsnmp].events = POLLIN; - m->handler.pfdcountsnmp++; - } - } -} -#endif - /* check poll events */ static void check_pollfds(struct thread_master *m, fd_set *readfd, int num) diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index 06fc7a30a..933a97ca8 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -7,6 +7,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libospf6.a +module_LTLIBRARIES = sbin_PROGRAMS = ospf6d libospf6_a_SOURCES = \ @@ -14,7 +15,7 @@ libospf6_a_SOURCES = \ 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 ospf6_snmp.c \ + ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c \ ospf6d.c ospf6_bfd.c noinst_HEADERS = \ @@ -22,7 +23,7 @@ noinst_HEADERS = \ 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 ospf6_snmp.h \ + ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h \ ospf6d.h ospf6_bfd.h ospf6d_SOURCES = \ @@ -30,5 +31,12 @@ ospf6d_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_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_interface.c b/ospf6d/ospf6_interface.c index 8e0779df9..8cf7f4afa 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -41,12 +41,14 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_spf.h" -#include "ospf6_snmp.h" #include "ospf6d.h" #include "ospf6_bfd.h" DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names") DEFINE_QOBJ_TYPE(ospf6_interface) +DEFINE_HOOK(ospf6_interface_change, + (struct ospf6_interface *oi, int state, int old_state), + (oi, state, old_state)) unsigned char conf_debug_ospf6_interface = 0; @@ -518,16 +520,7 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((next_state == OSPF6_INTERFACE_POINTTOPOINT) || - (next_state == OSPF6_INTERFACE_DROTHER) || - (next_state == OSPF6_INTERFACE_BDR) || - (next_state == OSPF6_INTERFACE_DR) || - (next_state < prev_state)) - ospf6TrapIfStateChange (oi); -#endif - + hook_call(ospf6_interface_change, oi, next_state, prev_state); } diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 179477a63..846cde419 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -23,6 +23,7 @@ #define OSPF6_INTERFACE_H #include "qobj.h" +#include "hook.h" #include "if.h" /* Debug option */ @@ -182,4 +183,8 @@ extern void install_element_ospf6_clear_interface (void); extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); +DECLARE_HOOK(ospf6_interface_change, + (struct ospf6_interface *oi, int state, int old_state), + (oi, state, old_state)) + #endif /* OSPF6_INTERFACE_H */ diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index ec79a1552..118210dfc 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -38,7 +38,6 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_flood.h" -#include "ospf6_snmp.h" #include "ospf6d.h" #include "ospf6_bfd.h" #include "ospf6_abr.h" @@ -47,6 +46,10 @@ #include "ospf6_spf.h" #include "ospf6_zebra.h" +DEFINE_HOOK(ospf6_neighbor_change, + (struct ospf6_neighbor *on, int state, int next_state), + (on, state, next_state)) + unsigned char conf_debug_ospf6_neighbor = 0; const char *ospf6_neighbor_state_str[] = @@ -202,13 +205,7 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int e next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((next_state == OSPF6_NEIGHBOR_FULL) || - (next_state == OSPF6_NEIGHBOR_TWOWAY) || - (next_state < prev_state)) - ospf6TrapNbrStateChange (on); -#endif + hook_call(ospf6_neighbor_change, on, next_state, prev_state); ospf6_bfd_trigger_event(on, prev_state, next_state); } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index f9e197e99..c275ff830 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -22,6 +22,8 @@ #ifndef OSPF6_NEIGHBOR_H #define OSPF6_NEIGHBOR_H +#include "hook.h" + /* Debug option */ extern unsigned char conf_debug_ospf6_neighbor; #define OSPF6_DEBUG_NEIGHBOR_STATE 0x01 @@ -179,4 +181,8 @@ extern void ospf6_neighbor_init (void); extern int config_write_ospf6_debug_neighbor (struct vty *vty); extern void install_element_ospf6_debug_neighbor (void); +DECLARE_HOOK(ospf6_neighbor_change, + (struct ospf6_neighbor *on, int state, int next_state), + (on, state, next_state)) + #endif /* OSPF6_NEIGHBOR_H */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 86cfd17c8..96f1e3dd2 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -21,8 +21,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP - #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -32,6 +30,8 @@ #include "vector.h" #include "vrf.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -45,7 +45,6 @@ #include "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6d.h" -#include "ospf6_snmp.h" /* OSPFv3-MIB */ #define OSPFv3MIB 1,3,6,1,2,1,191 @@ -1139,11 +1138,18 @@ static struct trap_object ospf6IfTrapList[] = {4, {1, 7, 1, OSPFv3IFAREAID}} }; -void -ospf6TrapNbrStateChange (struct ospf6_neighbor *on) +static int +ospf6TrapNbrStateChange (struct ospf6_neighbor *on, + int next_state, int prev_state) { oid index[3]; + /* Terminal state or regression */ + if ((next_state != OSPF6_NEIGHBOR_FULL) && + (next_state != OSPF6_NEIGHBOR_TWOWAY) && + (next_state >= prev_state)) + return 0; + index[0] = on->ospf6_if->interface->ifindex; index[1] = on->ospf6_if->instance_id; index[2] = ntohl (on->router_id); @@ -1155,13 +1161,23 @@ ospf6TrapNbrStateChange (struct ospf6_neighbor *on) ospf6NbrTrapList, sizeof ospf6NbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); + return 0; } -void -ospf6TrapIfStateChange (struct ospf6_interface *oi) +static int +ospf6TrapIfStateChange (struct ospf6_interface *oi, + int next_state, int prev_state) { oid index[2]; + /* Terminal state or regression */ + if ((next_state != OSPF6_INTERFACE_POINTTOPOINT) && + (next_state != OSPF6_INTERFACE_DROTHER) && + (next_state != OSPF6_INTERFACE_BDR) && + (next_state != OSPF6_INTERFACE_DR) && + (next_state >= prev_state)) + return 0; + index[0] = oi->interface->ifindex; index[1] = oi->instance_id; @@ -1172,15 +1188,30 @@ ospf6TrapIfStateChange (struct ospf6_interface *oi) ospf6IfTrapList, sizeof ospf6IfTrapList / sizeof (struct trap_object), IFSTATECHANGE); + return 0; } /* Register OSPFv3-MIB. */ -void +static int ospf6_snmp_init (struct thread_master *master) { smux_init (master); REGISTER_MIB ("OSPFv3MIB", ospfv3_variables, variable, ospfv3_oid); + return 0; } -#endif /* HAVE_SNMP */ +static int +ospf6_snmp_module_init (void) +{ + hook_register(ospf6_interface_change, ospf6TrapIfStateChange); + hook_register(ospf6_neighbor_change, ospf6TrapNbrStateChange); + hook_register(frr_late_init, ospf6_snmp_init); + return 0; +} +FRR_MODULE_SETUP( + .name = "ospf6d_snmp", + .version = FRR_VERSION, + .description = "ospf6d AgentX SNMP module", + .init = ospf6_snmp_module_init, +) diff --git a/ospf6d/ospf6_snmp.h b/ospf6d/ospf6_snmp.h deleted file mode 100644 index fa1b0c37a..000000000 --- a/ospf6d/ospf6_snmp.h +++ /dev/null @@ -1,31 +0,0 @@ -/* OSPFv3 SNMP support - * Copyright (C) 2004 Yasuhiro Ohara - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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, or (at your option) any - * later version. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef OSPF6_SNMP_H -#define OSPF6_SNMP_H - -extern void ospf6TrapNbrStateChange (struct ospf6_neighbor *); -extern void ospf6TrapIfStateChange (struct ospf6_interface *); -extern void ospf6_snmp_init (struct thread_master *); - -#endif /*OSPF6_SNMP_H*/ - - diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 2aaed5fcb..036cc6d4c 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -45,10 +45,6 @@ #include "ospf6d.h" #include "ospf6_bfd.h" -#ifdef HAVE_SNMP -#include "ospf6_snmp.h" -#endif /*HAVE_SNMP*/ - char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION; struct route_node * @@ -1215,10 +1211,6 @@ ospf6_init (void) ospf6_asbr_init (); ospf6_abr_init (); -#ifdef HAVE_SNMP - ospf6_snmp_init (master); -#endif /*HAVE_SNMP*/ - ospf6_bfd_init(); install_node (&debug_node, config_write_ospf6_debug); diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 71e0df0dc..e9d0ed219 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -6,13 +6,14 @@ 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_snmp.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 @@ -26,13 +27,20 @@ ospfdheader_HEADERS = \ 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_snmp.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.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_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) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 4fb206589..b4a282a52 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -47,11 +47,10 @@ #include "ospfd/ospf_abr.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_dump.h" -#ifdef HAVE_SNMP -#include "ospfd/ospf_snmp.h" -#endif /* HAVE_SNMP */ DEFINE_QOBJ_TYPE(ospf_interface) +DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data *vd), (vd)) +DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data *vd), (vd)) int ospf_if_get_output_cost (struct ospf_interface *oi) @@ -993,9 +992,7 @@ void ospf_vl_add (struct ospf *ospf, struct ospf_vl_data *vl_data) { listnode_add (ospf->vlinks, vl_data); -#ifdef HAVE_SNMP - ospf_snmp_vl_add (vl_data); -#endif /* HAVE_SNMP */ + hook_call(ospf_vl_add, vl_data); } void @@ -1004,9 +1001,7 @@ ospf_vl_delete (struct ospf *ospf, struct ospf_vl_data *vl_data) ospf_vl_shutdown (vl_data); ospf_vl_if_delete (vl_data); -#ifdef HAVE_SNMP - ospf_snmp_vl_delete (vl_data); -#endif /* HAVE_SNMP */ + hook_call(ospf_vl_delete, vl_data); listnode_delete (ospf->vlinks, vl_data); ospf_vl_data_free (vl_data); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index bd51bbf42..39202f777 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -24,6 +24,7 @@ #define _ZEBRA_OSPF_INTERFACE_H #include "qobj.h" +#include "hook.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" @@ -309,4 +310,7 @@ extern u_char ospf_default_iftype (struct interface *ifp); state of the interface. */ extern void ospf_if_set_multicast (struct ospf_interface *); +DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data *vd), (vd)) +DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data *vd), (vd)) + #endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 9630616ac..717c99c21 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -43,7 +43,10 @@ #include "ospfd/ospf_packet.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" -#include "ospfd/ospf_snmp.h" + +DEFINE_HOOK(ospf_ism_change, + (struct ospf_interface *oi, int state, int oldstate), + (oi, state, oldstate)) /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor * @@ -545,19 +548,7 @@ ism_change_state (struct ospf_interface *oi, int state) oi->state = state; oi->state_change++; -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || - (state == ISM_PointToPoint) || (state < old_state)) - { - /* ospfVirtIfStateChange */ - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - ospfTrapVirtIfStateChange (oi); - /* ospfIfStateChange */ - else - ospfTrapIfStateChange (oi); - } -#endif + hook_call(ospf_ism_change, oi, state, old_state); /* Set multicast memberships appropriately for new state. */ ospf_if_set_multicast(oi); diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index f0357a482..fa8e6d70f 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -24,6 +24,8 @@ #ifndef _ZEBRA_OSPF_ISM_H #define _ZEBRA_OSPF_ISM_H +#include "hook.h" + /* OSPF Interface State Machine Status. */ #define ISM_DependUpon 0 #define ISM_Down 1 @@ -35,10 +37,6 @@ #define ISM_DR 7 #define OSPF_ISM_STATE_MAX 8 -/* Because DR/DROther values are exhanged wrt RFC */ -#define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ - ((x) == ISM_DR) ? ISM_DROther : (x)) - /* OSPF Interface State Machine Event. */ #define ISM_NoEvent 0 #define ISM_InterfaceUp 1 @@ -111,4 +109,8 @@ extern int ospf_ism_event (struct thread *); extern void ism_change_status (struct ospf_interface *, int); extern int ospf_hello_timer (struct thread *thread); +DECLARE_HOOK(ospf_ism_change, + (struct ospf_interface *oi, int state, int oldstate), + (oi, state, oldstate)) + #endif /* _ZEBRA_OSPF_ISM_H */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index f462c207e..38718b35d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -225,9 +225,6 @@ main (int argc, char **argv) ospf_bfd_init(); ospf_route_map_init (); -#ifdef HAVE_SNMP - ospf_snmp_init (); -#endif /* HAVE_SNMP */ ospf_opaque_init (); /* Need to initialize the default ospf structure, so the interface mode diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 01617055c..97f3f6a38 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -48,9 +48,12 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" -#include "ospfd/ospf_snmp.h" #include "ospfd/ospf_bfd.h" +DEFINE_HOOK(ospf_nsm_change, + (struct ospf_neighbor *on, int state, int oldstate), + (on, state, oldstate)) + static void nsm_clear_adj (struct ospf_neighbor *); /* OSPF NSM Timer functions. */ @@ -838,35 +841,12 @@ ospf_nsm_event (struct thread *thread) /* If state is changed. */ if (next_state != nbr->state) { + int old_state = nbr->state; + nsm_notice_state_change (nbr, next_state, event); -#ifdef HAVE_SNMP - int send_trap_virt = 0; - int send_trap = 0; - /* Terminal state or regression */ - if ((next_state == NSM_Full) - || (next_state == NSM_TwoWay) - || (next_state < nbr->state)) - { - /* ospfVirtNbrStateChange */ - if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) - send_trap_virt = 1; - /* ospfNbrStateChange trap */ - else - /* To/From FULL, only managed by DR */ - if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) - || (nbr->oi->state == ISM_DR)) - send_trap = 1; - } -#endif nsm_change_state (nbr, next_state); -#ifdef HAVE_SNMP - if (send_trap_virt) { - ospfTrapVirtNbrStateChange(nbr); - } else if (send_trap) { - ospfTrapNbrStateChange(nbr); - } -#endif + hook_call(ospf_nsm_change, nbr, next_state, old_state); } /* Make sure timer is set. */ diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index 9b7e14a4a..4531f6ec7 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -24,6 +24,8 @@ #ifndef _ZEBRA_OSPF_NSM_H #define _ZEBRA_OSPF_NSM_H +#include "hook.h" + /* OSPF Neighbor State Machine State. */ #define NSM_DependUpon 0 #define NSM_Deleted 1 @@ -86,5 +88,9 @@ extern int ospf_db_summary_isempty (struct ospf_neighbor *); extern int ospf_db_summary_count (struct ospf_neighbor *); extern void ospf_db_summary_clear (struct ospf_neighbor *); +DECLARE_HOOK(ospf_nsm_change, + (struct ospf_neighbor *on, int state, int oldstate), + (on, state, oldstate)) + #endif /* _ZEBRA_OSPF_NSM_H */ diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 4afbda878..32449d559 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -24,7 +24,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -35,6 +34,8 @@ #include "command.h" #include "memory.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -47,7 +48,7 @@ #include "ospfd/ospf_flood.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_dump.h" -#include "ospfd/ospf_snmp.h" +#include "ospfd/ospf_zebra.h" /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 @@ -205,6 +206,10 @@ #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR +/* Because DR/DROther values are exhanged wrt RFC */ +#define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ + ((x) == ISM_DR) ? ISM_DROther : (x)) + /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES @@ -1429,7 +1434,7 @@ ospf_snmp_if_free (struct ospf_snmp_if *osif) XFREE (MTYPE_TMP, osif); } -void +static int ospf_snmp_if_delete (struct interface *ifp) { struct listnode *node, *nnode; @@ -1441,12 +1446,13 @@ ospf_snmp_if_delete (struct interface *ifp) { list_delete_node (ospf_snmp_iflist, node); ospf_snmp_if_free (osif); - return; + break; } } + return 0; } -void +static int ospf_snmp_if_update (struct interface *ifp) { struct listnode *node; @@ -1511,6 +1517,7 @@ ospf_snmp_if_update (struct interface *ifp) osif->ifp = ifp; listnode_add_after (ospf_snmp_iflist, pn, osif); + return 0; } static int @@ -1914,7 +1921,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, static struct route_table *ospf_snmp_vl_table; -void +static int ospf_snmp_vl_add (struct ospf_vl_data *vl_data) { struct prefix_ls lp; @@ -1931,9 +1938,10 @@ ospf_snmp_vl_add (struct ospf_vl_data *vl_data) route_unlock_node (rn); rn->info = vl_data; + return 0; } -void +static int ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) { struct prefix_ls lp; @@ -1947,10 +1955,11 @@ ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); if (! rn) - return; + return 0; rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); + return 0; } static struct ospf_vl_data * @@ -2651,7 +2660,7 @@ static struct trap_object ospfVirtIfTrapList[] = {3, {9, 1, OSPFVIRTIFSTATE}} }; -void +static void ospfTrapNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2673,7 +2682,7 @@ ospfTrapNbrStateChange (struct ospf_neighbor *on) NBRSTATECHANGE); } -void +static void ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2692,7 +2701,29 @@ ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) VIRTNBRSTATECHANGE); } -void +static int +ospf_snmp_nsm_change (struct ospf_neighbor *nbr, + int next_state, int old_state) +{ + /* Terminal state or regression */ + if ((next_state == NSM_Full) + || (next_state == NSM_TwoWay) + || (next_state < old_state)) + { + /* ospfVirtNbrStateChange */ + if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) + ospfTrapVirtNbrStateChange(nbr); + /* ospfNbrStateChange trap */ + else + /* To/From FULL, only managed by DR */ + if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) + || (nbr->oi->state == ISM_DR)) + ospfTrapNbrStateChange(nbr); + } + return 0; +} + +static void ospfTrapIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2713,7 +2744,7 @@ ospfTrapIfStateChange (struct ospf_interface *oi) IFSTATECHANGE); } -void +static void ospfTrapVirtIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2731,13 +2762,53 @@ ospfTrapVirtIfStateChange (struct ospf_interface *oi) sizeof ospfVirtIfTrapList / sizeof (struct trap_object), VIRTIFSTATECHANGE); } + +static int +ospf_snmp_ism_change (struct ospf_interface *oi, + int state, int old_state) +{ + /* Terminal state or regression */ + if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || + (state == ISM_PointToPoint) || (state < old_state)) + { + /* ospfVirtIfStateChange */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + ospfTrapVirtIfStateChange (oi); + /* ospfIfStateChange */ + else + ospfTrapIfStateChange (oi); + } + return 0; +} + /* Register OSPF2-MIB. */ -void -ospf_snmp_init () +static int +ospf_snmp_init (struct thread_master *tm) { ospf_snmp_iflist = list_new (); ospf_snmp_vl_table = route_table_init (); - smux_init (om->master); + smux_init (tm); REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); + return 0; +} + +static int +ospf_snmp_module_init (void) +{ + hook_register(ospf_if_update, ospf_snmp_if_update); + hook_register(ospf_if_delete, ospf_snmp_if_delete); + hook_register(ospf_vl_add, ospf_snmp_vl_add); + hook_register(ospf_vl_delete, ospf_snmp_vl_delete); + hook_register(ospf_ism_change, ospf_snmp_ism_change); + hook_register(ospf_nsm_change, ospf_snmp_nsm_change); + + hook_register(frr_late_init, ospf_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "ospfd_snmp", + .version = FRR_VERSION, + .description = "ospfd AgentX SNMP module", + .init = ospf_snmp_module_init, +) diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h deleted file mode 100644 index 413d1d7f7..000000000 --- a/ospfd/ospf_snmp.h +++ /dev/null @@ -1,38 +0,0 @@ -/* OSPFv2 SNMP support - * Copyright (C) 2000 IP Infusion Inc. - * - * Written by Kunihiro Ishiguro <kunihiro@zebra.org> - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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, or (at your option) any - * later version. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef _ZEBRA_OSPF_SNMP_H -#define _ZEBRA_OSPF_SNMP_H - -extern void ospf_snmp_if_update (struct interface *); -extern void ospf_snmp_if_delete (struct interface *); - -extern void ospf_snmp_vl_add (struct ospf_vl_data *); -extern void ospf_snmp_vl_delete (struct ospf_vl_data *); - -extern void ospfTrapIfStateChange (struct ospf_interface *); -extern void ospfTrapVirtIfStateChange (struct ospf_interface *); -extern void ospfTrapNbrStateChange (struct ospf_neighbor *); -extern void ospfTrapVirtNbrStateChange (struct ospf_neighbor *); - -#endif /* _ZEBRA_OSPF_SNMP_H */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index cb14273ee..abb6db034 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -50,11 +50,11 @@ #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_zebra.h" -#ifdef HAVE_SNMP -#include "ospfd/ospf_snmp.h" -#endif /* HAVE_SNMP */ #include "ospfd/ospf_te.h" +DEFINE_HOOK(ospf_if_update, (struct interface *ifp), (ifp)) +DEFINE_HOOK(ospf_if_delete, (struct interface *ifp), (ifp)) + /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -112,9 +112,7 @@ ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length, ospf_if_update (NULL, ifp); -#ifdef HAVE_SNMP - ospf_snmp_if_update (ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_update, ifp); return 0; } @@ -143,9 +141,7 @@ ospf_interface_delete (int command, struct zclient *zclient, ("Zebra: interface delete %s[%u] index %d flags %llx metric %d mtu %d", ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); -#ifdef HAVE_SNMP - ospf_snmp_if_delete (ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_delete, ifp); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if (rn->info) @@ -277,9 +273,7 @@ ospf_interface_address_add (int command, struct zclient *zclient, ospf_if_update (NULL, c->ifp); -#ifdef HAVE_SNMP - ospf_snmp_if_update (c->ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_update, c->ifp); return 0; } @@ -324,9 +318,7 @@ ospf_interface_address_delete (int command, struct zclient *zclient, /* Call interface hook functions to clean up */ ospf_if_free (oi); -#ifdef HAVE_SNMP - ospf_snmp_if_update (c->ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_update, c->ifp); connected_free (c); diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 8e93ed269..22c71a49e 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -24,6 +24,7 @@ #define _ZEBRA_OSPF_ZEBRA_H #include "vty.h" +#include "hook.h" #define EXTERNAL_METRIC_TYPE_1 0 #define EXTERNAL_METRIC_TYPE_2 1 @@ -79,5 +80,8 @@ extern int ospf_distance_unset (struct vty *, struct ospf *, const char *, const char *, const char *); extern void ospf_zebra_init(struct thread_master *, u_short); +DECLARE_HOOK(ospf_if_update, (struct interface *ifp), (ifp)) +DECLARE_HOOK(ospf_if_delete, (struct interface *ifp), (ifp)) + #endif /* _ZEBRA_OSPF_ZEBRA_H */ diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index a3bd0ca12..9198d5c62 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -574,7 +574,6 @@ extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); extern void ospf_route_map_init (void); -extern void ospf_snmp_init (void); extern void ospf_master_init (struct thread_master *master); diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 7967ff153..827869121 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -7,11 +7,12 @@ 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_snmp.c \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c \ rip_routemap.c rip_peer.c rip_offset.c noinst_HEADERS = \ @@ -23,6 +24,13 @@ ripd_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_LDFLAGS = -avoid-version -module -shared -export-dynamic +ripd_snmp_la_LIBADD = ../lib/libfrrsnmp.la + examplesdir = $(exampledir) dist_examples_DATA = ripd.conf.sample diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 4c750faf4..a4ee2ba57 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -42,6 +42,9 @@ #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" +DEFINE_HOOK(rip_ifaddr_add, (struct connected *ifc), (ifc)) +DEFINE_HOOK(rip_ifaddr_del, (struct connected *ifc), (ifc)) + /* static prototypes */ static void rip_enable_apply (struct interface *); static void rip_passive_interface_apply (struct interface *); @@ -673,9 +676,7 @@ rip_interface_address_add (int command, struct zclient *zclient, /* Check if this prefix needs to be redistributed */ rip_apply_address_add(ifc); -#ifdef HAVE_SNMP - rip_ifaddr_add (ifc->ifp, ifc); -#endif /* HAVE_SNMP */ + hook_call(rip_ifaddr_add, ifc); } return 0; @@ -723,9 +724,7 @@ rip_interface_address_delete (int command, struct zclient *zclient, zlog_debug ("connected address %s/%d is deleted", inet_ntoa (p->u.prefix4), p->prefixlen); -#ifdef HAVE_SNMP - rip_ifaddr_delete (ifc->ifp, ifc); -#endif /* HAVE_SNMP */ + hook_call(rip_ifaddr_del, ifc); /* Chech wether this prefix needs to be removed */ rip_apply_address_del(ifc); diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index fede5bed0..06cd3cef6 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -21,16 +21,18 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include "if.h" +#include "vrf.h" #include "log.h" #include "prefix.h" #include "command.h" #include "table.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ripd/ripd.h" @@ -174,24 +176,27 @@ rip2Globals (struct variable *v, oid name[], size_t *length, return NULL; } -void -rip_ifaddr_add (struct interface *ifp, struct connected *ifc) +static int +rip_snmp_ifaddr_add (struct connected *ifc) { + struct interface *ifp = ifc->ifp; struct prefix *p; struct route_node *rn; p = ifc->address; if (p->family != AF_INET) - return; + return 0; rn = route_node_get (rip_ifaddr_table, p); rn->info = ifp; + return 0; } -void -rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) +static int +rip_snmp_ifaddr_del (struct connected *ifc) { + struct interface *ifp = ifc->ifp; struct prefix *p; struct route_node *rn; struct interface *i; @@ -199,11 +204,11 @@ rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) p = ifc->address; if (p->family != AF_INET) - return; + return 0; rn = route_node_lookup (rip_ifaddr_table, p); if (! rn) - return; + return 0; i = rn->info; if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) { @@ -211,6 +216,7 @@ rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) route_unlock_node (rn); route_unlock_node (rn); } + return 0; } static struct interface * @@ -582,12 +588,29 @@ rip2PeerTable (struct variable *v, oid name[], size_t *length, } /* Register RIPv2-MIB. */ -void -rip_snmp_init () +static int +rip_snmp_init (struct thread_master *master) { rip_ifaddr_table = route_table_init (); smux_init (master); REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); + return 0; } -#endif /* HAVE_SNMP */ + +static int +rip_snmp_module_init (void) +{ + hook_register(rip_ifaddr_add, rip_snmp_ifaddr_add); + hook_register(rip_ifaddr_del, rip_snmp_ifaddr_del); + + hook_register(frr_late_init, rip_snmp_init); + return 0; +} + +FRR_MODULE_SETUP( + .name = "ripd_snmp", + .version = FRR_VERSION, + .description = "ripd AgentX SNMP module", + .init = rip_snmp_module_init, +) diff --git a/ripd/ripd.c b/ripd/ripd.c index 45d5bf1ea..b668b0a0b 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -4064,11 +4064,6 @@ rip_init (void) /* Debug related init. */ rip_debug_init (); - /* SNMP init. */ -#ifdef HAVE_SNMP - rip_snmp_init (); -#endif /* HAVE_SNMP */ - /* Access list install. */ access_list_init (); access_list_add_hook (rip_distribute_update_all_wrapper); diff --git a/ripd/ripd.h b/ripd/ripd.h index 68b3d1fc6..eeb008e3d 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -23,6 +23,7 @@ #define _ZEBRA_RIP_H #include "qobj.h" +#include "hook.h" #include "rip_memory.h" /* RIP version number. */ @@ -391,7 +392,6 @@ extern void rip_if_init (void); extern void rip_if_down_all (void); extern void rip_route_map_init (void); extern void rip_route_map_reset (void); -extern void rip_snmp_init (void); extern void rip_zclient_init(struct thread_master *); extern void rip_zclient_reset (void); extern void rip_offset_init (void); @@ -432,8 +432,6 @@ extern void rip_offset_clean (void); extern void rip_info_free (struct rip_info *); extern u_char rip_distance_apply (struct rip_info *); extern void rip_redistribute_clean (void); -extern void rip_ifaddr_add (struct interface *, struct connected *); -extern void rip_ifaddr_delete (struct interface *, struct connected *); extern struct rip_info *rip_ecmp_add (struct rip_info *); extern struct rip_info *rip_ecmp_replace (struct rip_info *); @@ -448,4 +446,8 @@ extern struct thread_master *master; /* RIP statistics for SNMP. */ extern long rip_global_route_changes; extern long rip_global_queries; + +DECLARE_HOOK(rip_ifaddr_add, (struct connected *ifc), (ifc)) +DECLARE_HOOK(rip_ifaddr_del, (struct connected *ifc), (ifc)) + #endif /* _ZEBRA_RIP_H */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 7d5fa8442..d0038ea3c 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2010,29 +2010,43 @@ DEFUNSH (VTYSH_ZEBRA, return CMD_SUCCESS; } -/* Memory */ -DEFUN (vtysh_show_memory, - vtysh_show_memory_cmd, - "show memory", - SHOW_STR - "Memory statistics\n") +static int +show_per_daemon (const char *line, const char *headline) { unsigned int i; int ret = CMD_SUCCESS; - char line[] = "show memory\n"; - + for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { - fprintf (stdout, "Memory statistics for %s:\n", + fprintf (stdout, headline, vtysh_client[i].name); ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"\n"); } - + return ret; } +/* Memory */ +DEFUN (vtysh_show_memory, + vtysh_show_memory_cmd, + "show memory", + SHOW_STR + "Memory statistics\n") +{ + return show_per_daemon ("show memory\n", "Memory statistics for %s:\n"); +} + +DEFUN (vtysh_show_modules, + vtysh_show_modules_cmd, + "show modules", + SHOW_STR + "Loaded modules\n") +{ + return show_per_daemon ("show modules\n", "Module information for %s:\n"); +} + /* Logging commands. */ DEFUN (vtysh_show_logging, vtysh_show_logging_cmd, @@ -3388,6 +3402,7 @@ vtysh_init_vty (void) #endif install_element (VIEW_NODE, &vtysh_show_memory_cmd); + install_element (VIEW_NODE, &vtysh_show_modules_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 50bc065c6..af7a513d2 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -19,33 +19,22 @@ mpls_method = @MPLS_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) \ $(rt_method) $(rtread_method) $(kernel_method) $(mpls_method) -if HAVE_NETLINK -othersrc = zebra_fpm_netlink.c -endif - -if HAVE_PROTOBUF -protobuf_srcs = zebra_fpm_protobuf.c -endif - -if DEV_BUILD -dev_srcs = zebra_fpm_dt.c -endif - AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra - noinst_PROGRAMS = testzebra +module_LTLIBRARIES = zebra_SOURCES = \ zebra_memory.c \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ - redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ - irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ + redistribute.c debug.c rtadv.c zebra_vty.c \ + irdp_main.c irdp_interface.c irdp_packet.c router-id.c \ + zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \ - $(protobuf_srcs) zebra_mroute.c \ - $(dev_srcs) label_manager.c + zebra_mroute.c \ + label_manager.c \ + # end testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \ @@ -57,17 +46,41 @@ noinst_HEADERS = \ zebra_memory.h \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ - rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \ + rt_netlink.h zebra_fpm_private.h zebra_rnh.h \ zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \ zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \ kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h -zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) +zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) testzebra_LDADD = ../lib/libfrr.la $(LIBCAP) zebra_DEPENDENCIES = $(otherobj) +if SNMP +module_LTLIBRARIES += zebra_snmp.la +endif +zebra_snmp_la_SOURCES = zebra_snmp.c +zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +zebra_snmp_la_LIBADD = ../lib/libfrrsnmp.la + +if FPM +module_LTLIBRARIES += zebra_fpm.la +endif +zebra_fpm_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +zebra_fpm_la_LIBADD = $(Q_FPM_PB_CLIENT_LDOPTS) +zebra_fpm_la_SOURCES = zebra_fpm.c +if HAVE_NETLINK +zebra_fpm_la_SOURCES += zebra_fpm_netlink.c +endif +if HAVE_PROTOBUF +zebra_fpm_la_SOURCES += zebra_fpm_protobuf.c +endif +if DEV_BUILD +zebra_fpm_la_SOURCES += zebra_fpm_dt.c +endif + + EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ if_sysctl.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \ diff --git a/zebra/main.c b/zebra/main.c index 26e66f961..459e6148d 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -43,7 +43,6 @@ #include "zebra/router-id.h" #include "zebra/irdp.h" #include "zebra/rtadv.h" -#include "zebra/zebra_fpm.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ns.h" #include "zebra/redistribute.h" @@ -84,7 +83,6 @@ struct option longopts[] = { "batch", no_argument, NULL, 'b'}, { "allow_delete", no_argument, NULL, 'a'}, { "keep_kernel", no_argument, NULL, 'k'}, - { "fpm_format", required_argument, NULL, 'F'}, { "socket", required_argument, NULL, 'z'}, { "ecmp", required_argument, NULL, 'e'}, { "label_socket", no_argument, NULL, 'l'}, @@ -221,21 +219,18 @@ main (int argc, char **argv) { // int batch_mode = 0; char *zserv_path = NULL; - char *fpm_format = NULL; /* Socket to external label manager */ char *lblmgr_path = NULL; - frr_preinit(&zebra_di, argc, argv); - frr_opt_add("bakF:z:e:l:r" + frr_opt_add("bakz:e:l:r" #ifdef HAVE_NETLINK "s:" #endif , longopts, " -b, --batch Runs in batch mode\n" " -a, --allow_delete Allow other processes to delete zebra routes\n" - " -F, --fpm_format Set fpm format to 'netlink' or 'protobuf'\n" " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -l, --label_socket Socket to external label manager\n"\ @@ -266,9 +261,6 @@ main (int argc, char **argv) case 'k': keep_kernel_mode = 1; break; - case 'F': - fpm_format = optarg; - break; case 'e': multipath_num = atoi (optarg); if (multipath_num > MULTIPATH_NUM || multipath_num <= 0) @@ -329,16 +321,6 @@ main (int argc, char **argv) /* Initialize NS( and implicitly the VRF module), and make kernel routing socket. */ zebra_ns_init (); -#ifdef HAVE_SNMP - zebra_snmp_init (); -#endif /* HAVE_SNMP */ - -#ifdef HAVE_FPM - zfpm_init (zebrad.master, 1, 0, fpm_format); -#else - zfpm_init (zebrad.master, 0, 0, fpm_format); -#endif - /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in diff --git a/zebra/misc_null.c b/zebra/misc_null.c index a83c30741..49cb92bd7 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -25,7 +25,6 @@ #include "zebra/rtadv.h" #include "zebra/irdp.h" #include "zebra/interface.h" -#include "zebra/zebra_fpm.h" void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } @@ -35,9 +34,3 @@ void ifstat_update_proc (void) { return; } #ifdef HAVE_NET_RT_IFLIST void ifstat_update_sysctl (void) { return; } #endif - -void -zfpm_trigger_update (struct route_node *rn, const char *reason) -{ - return; -} diff --git a/zebra/rib.h b/zebra/rib.h index c0cde50ba..5381d76b9 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -24,6 +24,7 @@ #define _ZEBRA_RIB_H #include "zebra.h" +#include "hook.h" #include "linklist.h" #include "prefix.h" #include "table.h" @@ -490,4 +491,6 @@ rib_tables_iter_cleanup (rib_tables_iter_t *iter) iter->state = RIB_TABLES_ITER_S_DONE; } +DECLARE_HOOK(rib_update, (struct route_node *rn, const char *reason), (rn, reason)) + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 1007d0ac1..4d491f320 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -31,6 +31,10 @@ #include "zebra/rib.h" #include "zebra/zserv.h" +/* Thank you, Solaris, for polluting application symbol namespace. */ +#undef hook_register +#undef hook_unregister + #include <sys/stream.h> #include <sys/tihdr.h> diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index afa557096..405b2e9f7 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -25,10 +25,12 @@ #include <zebra.h> #include "log.h" +#include "libfrr.h" #include "stream.h" #include "thread.h" #include "network.h" #include "command.h" +#include "version.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -36,7 +38,6 @@ #include "zebra/zebra_vrf.h" #include "fpm/fpm.h" -#include "zebra_fpm.h" #include "zebra_fpm_private.h" /* @@ -254,6 +255,8 @@ typedef struct zfpm_glob_t_ static zfpm_glob_t zfpm_glob_space; static zfpm_glob_t *zfpm_g = &zfpm_glob_space; +static int zfpm_trigger_update (struct route_node *rn, const char *reason); + static int zfpm_read_cb (struct thread *thread); static int zfpm_write_cb (struct thread *thread); @@ -1296,7 +1299,6 @@ zfpm_start_connect_timer (const char *reason) zfpm_set_state (ZFPM_STATE_ACTIVE, reason); } -#if defined (HAVE_FPM) /* * zfpm_is_enabled * @@ -1307,7 +1309,6 @@ zfpm_is_enabled (void) { return zfpm_g->enabled; } -#endif /* * zfpm_conn_is_up @@ -1331,7 +1332,7 @@ zfpm_conn_is_up (void) * The zebra code invokes this function to indicate that we should * send an update to the FPM about the given route_node. */ -void +static int zfpm_trigger_update (struct route_node *rn, const char *reason) { rib_dest_t *dest; @@ -1342,7 +1343,7 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) * all destinations once the connection comes up. */ if (!zfpm_conn_is_up ()) - return; + return 0; dest = rib_dest_from_rnode (rn); @@ -1353,12 +1354,12 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) if (!zfpm_is_table_for_fpm (rib_dest_table (dest))) { zfpm_g->stats.non_fpm_table_triggers++; - return; + return 0; } if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { zfpm_g->stats.redundant_triggers++; - return; + return 0; } if (reason) @@ -1375,9 +1376,10 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) * Make sure that writes are enabled. */ if (zfpm_g->t_write) - return; + return 0; zfpm_write_on (); + return 0; } /* @@ -1411,7 +1413,6 @@ zfpm_stats_timer_cb (struct thread *t) return 0; } -#if defined (HAVE_FPM) /* * zfpm_stop_stats_timer */ @@ -1424,7 +1425,6 @@ zfpm_stop_stats_timer (void) zfpm_debug ("Stopping existing stats timer"); THREAD_TIMER_OFF (zfpm_g->t_stats); } -#endif /* * zfpm_start_stats_timer @@ -1447,7 +1447,6 @@ zfpm_start_stats_timer (void) zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \ } while (0) -#if defined (HAVE_FPM) /* * zfpm_show_stats */ @@ -1600,7 +1599,6 @@ DEFUN ( no_fpm_remote_ip, return CMD_SUCCESS; } -#endif /* * zfpm_init_message_format @@ -1670,7 +1668,7 @@ zfpm_init_message_format (const char *format) * Returns ZERO on success. */ -int fpm_remote_srv_write (struct vty *vty ) +static int fpm_remote_srv_write (struct vty *vty) { struct in_addr in; @@ -1684,6 +1682,15 @@ int fpm_remote_srv_write (struct vty *vty ) } +/* Zebra node */ +static struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "", + 1 +}; + + /** * zfpm_init * @@ -1695,17 +1702,12 @@ int fpm_remote_srv_write (struct vty *vty ) * * Returns TRUE on success. */ -int -zfpm_init (struct thread_master *master, int enable, uint16_t port, - const char *format) +static int +zfpm_init (struct thread_master *master) { - static int initialized = 0; - - if (initialized) { - return 1; - } - - initialized = 1; + int enable = 1; + uint16_t port = 0; + const char *format = THIS_MODULE->load_args; memset (zfpm_g, 0, sizeof (*zfpm_g)); zfpm_g->master = master; @@ -1717,12 +1719,11 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_stats_init (&zfpm_g->last_ivl_stats); zfpm_stats_init (&zfpm_g->cumulative_stats); -#if defined (HAVE_FPM) + install_node (&zebra_node, fpm_remote_srv_write); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); install_element (CONFIG_NODE, &fpm_remote_ip_cmd); install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd); -#endif zfpm_init_message_format(format); @@ -1734,10 +1735,6 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_g->enabled = enable; - if (!enable) { - return 1; - } - if (!zfpm_g->fpm_server) zfpm_g->fpm_server = FPM_DEFAULT_IP; @@ -1751,6 +1748,20 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_start_stats_timer (); zfpm_start_connect_timer ("initialized"); + return 0; +} - return 1; +static int +zebra_fpm_module_init (void) +{ + hook_register(rib_update, zfpm_trigger_update); + hook_register(frr_late_init, zfpm_init); + return 0; } + +FRR_MODULE_SETUP( + .name = "zebra_fpm", + .version = FRR_VERSION, + .description = "zebra FPM (Forwarding Plane Manager) module", + .init = zebra_fpm_module_init, +) diff --git a/zebra/zebra_fpm.h b/zebra/zebra_fpm.h deleted file mode 100644 index fdb069965..000000000 --- a/zebra/zebra_fpm.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Header file exported by the zebra FPM module to zebra. - * - * Copyright (C) 2012 by Open Source Routing. - * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") - * - * This file is part of GNU Zebra. - * - * GNU Zebra 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, or (at your option) - * any later version. - * - * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _ZEBRA_FPM_H -#define _ZEBRA_FPM_H - -/* - * Externs. - */ -extern int zfpm_init (struct thread_master *master, int enable, uint16_t port, - const char *message_format); -extern void zfpm_trigger_update (struct route_node *rn, const char *reason); -extern int fpm_remote_srv_write (struct vty *vty); - -#endif /* _ZEBRA_FPM_H */ diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index fba57c68f..11869d8a2 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -53,7 +53,7 @@ create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, } fpm__delete_route__init(msg); - msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); @@ -159,7 +159,7 @@ create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, fpm__add_route__init(msg); - msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); qpb_address_family_set (&msg->address_family, rib_dest_af(dest)); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f5b54a2c0..b3e70e46f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -48,11 +48,12 @@ #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" #include "zebra/debug.h" -#include "zebra/zebra_fpm.h" #include "zebra/zebra_rnh.h" #include "zebra/interface.h" #include "zebra/connected.h" +DEFINE_HOOK(rib_update, (struct route_node *rn, const char *reason), (rn, reason)) + /* Should we allow non Quagga processes to delete our routes */ extern int allow_delete; @@ -1110,7 +1111,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, struct rib *old) * Make sure we update the FPM any time we send new information to * the kernel. */ - zfpm_trigger_update (rn, "installing in kernel"); + hook_call(rib_update, rn, "installing in kernel"); ret = kernel_route_rib (p, src_p, old, rib); /* If install succeeds, update FIB flag for nexthops. */ @@ -1154,7 +1155,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) * Make sure we update the FPM any time we send new information to * the kernel. */ - zfpm_trigger_update (rn, "uninstalling from kernel"); + hook_call(rib_update, rn, "uninstalling from kernel"); ret = kernel_route_rib (p, src_p, rib, NULL); for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) @@ -1172,7 +1173,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { if (info->safi == SAFI_UNICAST) - zfpm_trigger_update (rn, "rib_uninstall"); + hook_call(rib_update, rn, "rib_uninstall"); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); @@ -1253,7 +1254,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct rib *new) { - zfpm_trigger_update (rn, "new route selected"); + hook_call(rib_update, rn, "new route selected"); /* Update real nexthop. This may actually determine if nexthop is active or not. */ if (!nexthop_active_update (rn, new, 1)) @@ -1289,7 +1290,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct rib *old) { - zfpm_trigger_update (rn, "removing existing route"); + hook_call(rib_update, rn, "removing existing route"); /* Uninstall from kernel. */ if (IS_ZEBRA_DEBUG_RIB) @@ -1326,7 +1327,7 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, if (new != old || CHECK_FLAG (new->status, RIB_ENTRY_CHANGED)) { - zfpm_trigger_update (rn, "updating existing route"); + hook_call(rib_update, rn, "updating existing route"); /* Update the nexthop; we could determine here that nexthop is inactive. */ if (nexthop_active_update (rn, new, 1)) @@ -2874,7 +2875,7 @@ rib_close_table (struct route_table *table) continue; if (info->safi == SAFI_UNICAST) - zfpm_trigger_update (rn, NULL); + hook_call(rib_update, rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 19364b5b9..8adb8873d 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -25,7 +25,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -36,6 +35,9 @@ #include "smux.h" #include "table.h" #include "vrf.h" +#include "hook.h" +#include "libfrr.h" +#include "version.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -571,10 +573,24 @@ ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, return NULL; } -void -zebra_snmp_init () +static int +zebra_snmp_init (struct thread_master *tm) { - smux_init (zebrad.master); + smux_init (tm); REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); + return 0; +} + +static int +zebra_snmp_module_init (void) +{ + hook_register(frr_late_init, zebra_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "zebra_snmp", + .version = FRR_VERSION, + .description = "zebra AgentX SNMP module", + .init = zebra_snmp_module_init, +) diff --git a/zebra/zserv.c b/zebra/zserv.c index 85fdd5312..3477dc36d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -53,7 +53,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rtadv.h" #include "zebra/zebra_mpls.h" -#include "zebra/zebra_fpm.h" #include "zebra/zebra_mroute.h" #include "zebra/label_manager.h" @@ -2851,25 +2850,6 @@ static struct cmd_node forwarding_node = 1 }; -#ifdef HAVE_FPM -/* function to write the fpm config info */ -static int -config_write_fpm (struct vty *vty) -{ - return - fpm_remote_srv_write (vty); -} - -/* Zebra node */ -static struct cmd_node zebra_node = -{ - ZEBRA_NODE, - "", - 1 -}; -#endif - - /* Initialisation of zebra and installation of commands. */ void zebra_init (void) @@ -2880,9 +2860,6 @@ zebra_init (void) /* Install configuration write function. */ install_node (&table_node, config_write_table); install_node (&forwarding_node, config_write_forwarding); -#ifdef HAVE_FPM - install_node (&zebra_node, config_write_fpm); -#endif install_element (VIEW_NODE, &show_ip_forwarding_cmd); install_element (CONFIG_NODE, &ip_forwarding_cmd); diff --git a/zebra/zserv.h b/zebra/zserv.h index 9e3473823..cd1948373 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -149,7 +149,6 @@ extern void route_read (struct zebra_ns *); extern void kernel_init (struct zebra_ns *); extern void kernel_terminate (struct zebra_ns *); extern void zebra_route_map_init (void); -extern void zebra_snmp_init (void); extern void zebra_vty_init (void); extern int zsend_vrf_add (struct zserv *, struct zebra_vrf *); |