summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2017-04-04 17:55:00 +0200
committerGitHub <noreply@github.com>2017-04-04 17:55:00 +0200
commitb3cfe637a66a5de00c72125f5fa051155ccb4a29 (patch)
tree16af08958977f24dc9b563bca5bb7a003da0f040
parentMerge pull request #322 from qlyoung/fix-distance-commands (diff)
parentvtysh: handle "show modules" like "show memory" (diff)
downloadfrr-b3cfe637a66a5de00c72125f5fa051155ccb4a29.tar.xz
frr-b3cfe637a66a5de00c72125f5fa051155ccb4a29.zip
Merge pull request #294 from opensourcerouting/modules
Loadable module support
-rw-r--r--bgpd/Makefile.am13
-rw-r--r--bgpd/bgp_fsm.c14
-rw-r--r--bgpd/bgp_fsm.h4
-rw-r--r--bgpd/bgp_snmp.c39
-rw-r--r--bgpd/bgp_snmp.h28
-rw-r--r--bgpd/bgpd.c9
-rwxr-xr-xconfigure.ac68
-rw-r--r--doc/basic.texi46
-rw-r--r--doc/bgpd.8.in8
-rw-r--r--doc/defines.texi.in1
-rw-r--r--doc/dev-modules.md119
-rw-r--r--doc/isisd.8.in8
-rw-r--r--doc/ldpd.8.in8
-rw-r--r--doc/main.texi9
-rw-r--r--doc/nhrpd.8.in8
-rw-r--r--doc/ospf6d.8.in8
-rw-r--r--doc/ospfd.8.in8
-rw-r--r--doc/pimd.8.in8
-rw-r--r--doc/ripd.8.in8
-rw-r--r--doc/ripngd.8.in8
-rw-r--r--doc/snmp.texi4
-rw-r--r--doc/watchfrr.8.in4
-rw-r--r--doc/zebra.8.in11
-rw-r--r--lib/Makefile.am22
-rw-r--r--lib/agentx.c4
-rw-r--r--lib/hook.c56
-rw-r--r--lib/hook.h187
-rw-r--r--lib/libfrr.c38
-rw-r--r--lib/libfrr.h15
-rw-r--r--lib/memory_vty.c77
-rw-r--r--lib/module.c159
-rw-r--r--lib/module.h104
-rw-r--r--lib/smux.c4
-rw-r--r--lib/snmp.c2
-rw-r--r--lib/thread.c22
-rw-r--r--ospf6d/Makefile.am12
-rw-r--r--ospf6d/ospf6_interface.c15
-rw-r--r--ospf6d/ospf6_interface.h5
-rw-r--r--ospf6d/ospf6_neighbor.c13
-rw-r--r--ospf6d/ospf6_neighbor.h6
-rw-r--r--ospf6d/ospf6_snmp.c49
-rw-r--r--ospf6d/ospf6_snmp.h31
-rw-r--r--ospf6d/ospf6d.c8
-rw-r--r--ospfd/Makefile.am12
-rw-r--r--ospfd/ospf_interface.c13
-rw-r--r--ospfd/ospf_interface.h4
-rw-r--r--ospfd/ospf_ism.c19
-rw-r--r--ospfd/ospf_ism.h10
-rw-r--r--ospfd/ospf_main.c3
-rw-r--r--ospfd/ospf_nsm.c34
-rw-r--r--ospfd/ospf_nsm.h6
-rw-r--r--ospfd/ospf_snmp.c103
-rw-r--r--ospfd/ospf_snmp.h38
-rw-r--r--ospfd/ospf_zebra.c22
-rw-r--r--ospfd/ospf_zebra.h4
-rw-r--r--ospfd/ospfd.h1
-rw-r--r--ripd/Makefile.am10
-rw-r--r--ripd/rip_interface.c11
-rw-r--r--ripd/rip_snmp.c45
-rw-r--r--ripd/ripd.c5
-rw-r--r--ripd/ripd.h8
-rw-r--r--vtysh/vtysh.c35
-rw-r--r--zebra/Makefile.am53
-rw-r--r--zebra/main.c20
-rw-r--r--zebra/misc_null.c7
-rw-r--r--zebra/rib.h3
-rw-r--r--zebra/rtread_getmsg.c4
-rw-r--r--zebra/zebra_fpm.c71
-rw-r--r--zebra/zebra_fpm.h36
-rw-r--r--zebra/zebra_fpm_protobuf.c4
-rw-r--r--zebra/zebra_rib.c17
-rw-r--r--zebra/zebra_snmp.c26
-rw-r--r--zebra/zserv.c23
-rw-r--r--zebra/zserv.h1
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 *);