]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge remote-tracking branch 'origin/master' into EIGRP
authorDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 00:52:32 +0000 (20:52 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 00:52:32 +0000 (20:52 -0400)
258 files changed:
COMMUNITY.md
ChangeLog
Makefile.am
REPORTING-BUGS
bgpd/Makefile.am
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_network.c
bgpd/bgp_nexthop.c
bgpd/bgp_snmp.c
bgpd/bgp_snmp.h [deleted file]
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
configure.ac
debian/README.Debian
debian/copyright
defaults.h [new file with mode: 0644]
doc/Building_FRR_on_CentOS6.md
doc/Building_FRR_on_CentOS7.md
doc/Building_FRR_on_Debian8.md
doc/Building_FRR_on_Fedora24.md
doc/Building_FRR_on_FreeBSD10.md
doc/Building_FRR_on_FreeBSD11.md
doc/Building_FRR_on_FreeBSD9.md
doc/Building_FRR_on_NetBSD6.md
doc/Building_FRR_on_NetBSD7.md
doc/Building_FRR_on_OmniOS.md
doc/Building_FRR_on_OpenBSD6.md
doc/Building_FRR_on_Ubuntu1204.md
doc/Building_FRR_on_Ubuntu1404.md
doc/Building_FRR_on_Ubuntu1604.md
doc/basic.texi
doc/bgpd.8.in
doc/defines.texi.in
doc/dev-modules.md [new file with mode: 0644]
doc/frr.texi
doc/git_branches.svg
doc/isisd.8.in
doc/ldpd.8.in
doc/main.texi
doc/nhrpd.8.in
doc/ospf6d.8.in
doc/ospfd.8.in
doc/overview.texi
doc/pimd.8.in
doc/ripd.8.in
doc/ripngd.8.in
doc/snmp.texi
doc/watchfrr.8.in
doc/zebra.8.in
isisd/isis_pfpacket.c
isisd/isis_spf.c
isisd/isis_te.c
isisd/isisd.c
ldpd/Makefile.am
ldpd/address.c
ldpd/adjacency.c
ldpd/control.c
ldpd/hello.c
ldpd/init.c
ldpd/interface.c
ldpd/keepalive.c
ldpd/l2vpn.c
ldpd/labelmapping.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_vty.h
ldpd/ldp_vty.xml
ldpd/ldp_vty_conf.c
ldpd/ldp_vty_exec.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h
ldpd/neighbor.c
ldpd/notification.c
ldpd/packet.c
ldpd/pfkey.c
lib/Makefile.am
lib/agentx.c
lib/bfd.c
lib/command.c
lib/distribute.c
lib/frratomic.h [new file with mode: 0644]
lib/grammar_sandbox.c
lib/hook.c [new file with mode: 0644]
lib/hook.h [new file with mode: 0644]
lib/if.c
lib/if.h
lib/keychain.c
lib/libfrr.c
lib/libfrr.h
lib/log.c
lib/memory.c
lib/memory.h
lib/memory_vty.c
lib/module.c [new file with mode: 0644]
lib/module.h [new file with mode: 0644]
lib/mpls.h
lib/ns.c
lib/privs.c
lib/routemap.c
lib/sigevent.c
lib/smux.c
lib/snmp.c
lib/thread.c
lib/version.h.in
lib/vrf.c
lib/vty.c
lib/zclient.c
lib/zclient.h
m4/.gitignore
m4/ax_pthread.m4 [new file with mode: 0644]
nhrpd/.gitignore [new file with mode: 0644]
nhrpd/netlink_arp.c
nhrpd/nhrp_interface.c
nhrpd/nhrp_packet.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_route.c
ospf6d/Makefile.am
ospf6d/ospf6_asbr.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_neighbor.h
ospf6d/ospf6_route.c
ospf6d/ospf6_snmp.c
ospf6d/ospf6_snmp.h [deleted file]
ospf6d/ospf6_top.c
ospf6d/ospf6d.c
ospfd/Makefile.am
ospfd/ospf_dump_api.c
ospfd/ospf_dump_api.h
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_ism.c
ospfd/ospf_ism.h
ospfd/ospf_main.c
ospfd/ospf_nsm.c
ospfd/ospf_nsm.h
ospfd/ospf_packet.c
ospfd/ospf_routemap.c
ospfd/ospf_snmp.c
ospfd/ospf_snmp.h [deleted file]
ospfd/ospf_spf.c
ospfd/ospf_te.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospf_zebra.h
ospfd/ospfd.c
ospfd/ospfd.h
pimd/Makefile.am
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.c
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmp_join.h
pimd/pim_join.c
pimd/pim_jp_agg.c
pimd/pim_jp_agg.h
pimd/pim_main.c
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_mroute.c
pimd/pim_msg.c
pimd/pim_msg.h
pimd/pim_nht.c [new file with mode: 0644]
pimd/pim_nht.h [new file with mode: 0644]
pimd/pim_pim.c
pimd/pim_register.c
pimd/pim_register.h
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_rpf.c
pimd/pim_rpf.h
pimd/pim_ssm.c [new file with mode: 0644]
pimd/pim_ssm.h [new file with mode: 0644]
pimd/pim_ssmpingd.c
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_vty.c
pimd/pim_zebra.c
pimd/pim_zebra.h
pimd/pim_zlookup.c
pimd/pimd.c
pimd/pimd.h
redhat/README.rpm_build.md
redhat/frr.spec.in
ripd/Makefile.am
ripd/rip_interface.c
ripd/rip_routemap.c
ripd/rip_snmp.c
ripd/ripd.c
ripd/ripd.h
ripngd/ripng_routemap.c
ripngd/ripngd.c
snapcraft/Makefile.am
snapcraft/README.snap_build.md
snapcraft/README.usage.md
snapcraft/setup/gui/icon.png [deleted file]
snapcraft/snap/gui/icon.png [new file with mode: 0644]
snapcraft/snapcraft.yaml.in
solaris/README.txt
solaris/depend.daemons.in
solaris/depend.dev.in
solaris/depend.libs.in
solaris/depend.smf.in
solaris/frr.init.in
solaris/frr.xml.in
solaris/pkginfo.tmpl.in
tests/helpers/python/frrtest.py
tests/lib/cli/.gitignore [new file with mode: 0644]
tests/lib/cli/test_cli.refout [deleted file]
tests/lib/cli/test_cli.refout.in [new file with mode: 0644]
tests/test_lblmgr.c [new file with mode: 0644]
tools/frr-reload.py
vtysh/Makefile.am
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
zebra/Makefile.am
zebra/debug.c
zebra/if_ioctl.c
zebra/if_ioctl_solaris.c
zebra/if_netlink.c
zebra/if_sysctl.c
zebra/interface.c
zebra/irdp_packet.c
zebra/kernel_socket.c
zebra/label_manager.c [new file with mode: 0644]
zebra/label_manager.h [new file with mode: 0644]
zebra/main.c
zebra/misc_null.c
zebra/rib.h
zebra/rt_netlink.c
zebra/rtread_getmsg.c
zebra/zebra_fpm.c
zebra/zebra_fpm.h [deleted file]
zebra/zebra_fpm_dt.c
zebra/zebra_fpm_protobuf.c
zebra/zebra_mpls.c
zebra/zebra_mpls_openbsd.c
zebra/zebra_rib.c
zebra/zebra_routemap.c
zebra/zebra_snmp.c
zebra/zebra_vrf.c
zebra/zebra_vty.c
zebra/zserv.c
zebra/zserv.h

index 52777da968810928ee2e13247beac7613bb87782..704c47a95e6e6417d48264179c4da49daf8e3090 100644 (file)
@@ -2,6 +2,16 @@
 
 [TOC]
 
+## General note on this document
+
+This document is "descriptive/post-factual" in that it documents pratices that
+are in use; it is not "definitive/pre-factual" in prescribing practices.
+
+This means that when a procedure changes, it is agreed upon, then put into
+practice, and then documented here.  If this document doesn't match reality,
+it's the document that needs to be updated, not reality.
+
+
 ## Git Structure
 
 The master Git for PROJECT resides on Github at
@@ -10,20 +20,21 @@ The master Git for PROJECT resides on Github at
 ![git branches continually merging to the left from 3 lanes; float-right](doc/git_branches.svg
 "git branch mechanics")
 
-There are 3 main branches for development and a release branch for each
+There is one main branch for development and a release branch for each
 major release.
 
-New contributions are done against the head of the Develop branch. The CI
+New contributions are done against the head of the master branch. The CI
 systems will pick up the Github Pull Requests or the new patch from
-Patchwork, run some basic build and functional tests and will merge them
-into the branch automatically on success.
-
-Code on the develop branch will then be further tested and reviewed by the
-community and merged to master on a regular interval.
+Patchwork, run some basic build and functional tests.
 
 For each major release (1.0, 1.1 etc) a new release branch is created based
 on the master.
 
+There was an attempt to use a "develop" branch automatically maintained by
+the CI system.  This is not currently in active use, though the system is
+operational.  If the "develop" branch is in active use and this paragraph
+is still here, this document obviously wasn't updated.
+
 
 ## Programming language, Tools and Libraries
 
@@ -250,16 +261,72 @@ Portions:
 
 ### Code styling / format
 
-GNU coding standards apply. Indentation follows the result of invoking GNU
-indent (as of 2.2.8a) with the `-nut -nfc1` arguments.
+Coding style standards in FRR vary depending on location.  Pre-existing
+code uses GNU coding standards.  New code may use Linux kernel coding style.
+
+GNU coding style apply to the following parts:
+
+* lib/
+* zebra/
+* bgpd/
+* ospfd/
+* ospf6d/
+* isisd/
+* ripd/
+* ripngd/
+* vtysh/
+
+Linux kernel coding style applies to:
+
+* nhrpd/
+* watchfrr/
+* pimd/
+* lib/{checksum,hook,imsg-buffer,imsg,libfrr,md5,module,monotime,queue}.[ch]
+
+BSD coding style applies to:
+
+* ldpd/
+
+**Whitespace changes in untouched parts of the code are not acceptable in
+patches that change actual code.**  To change/fix formatting issues, please
+create a separate patch that only does formatting changes and nothing else.
+
+It is acceptable to rewrap entire files to Linux kernel style, but this
+**MUST** come as a separate patch that does nothing other than this
+reformatting.
+
+
+#### GNU style
+
+For GNU coding style, Indentation follows the result of invoking GNU indent:
 
 ```
 indent -nut -nfc1 file_for_submission.c
 ```
 
-Please don’t reformat existing files (or only sections modified by your
-changes), even if they don’t follow the standard. This makes it very hard to
-highlight the changes
+Originally, tabs were used instead of spaces, with tabs are every 8 columns.
+However, tab interoperability issues mean space characters are now preferred for
+new changes. We generally only clean up whitespace when code is unmaintainable
+due to whitespace issues, to minimise merging conflicts.
+
+
+#### Linux kernel & BSD style
+
+These styles are documented externally:
+
+* [https://www.kernel.org/doc/Documentation/CodingStyle](https://www.kernel.org/doc/Documentation/CodingStyle).
+* [http://man.openbsd.org/style](http://man.openbsd.org/style)
+
+They are relatively similar but differ in details.
+
+pimd deviates from Linux kernel style in using 2 spaces for indentation, with
+Tabs replacing 8 spaces, as well as adding a line break between `}` and `else`.
+It is acceptable to convert indentation in pimd/ to Linux kernel style, but
+please convert an entire file at a time.  (Rationale: apart from 2-space
+indentation, the styles are sufficiently close to not upset when mixed.)
+
+Unlike GNU style, these styles use tabs, not spaces.
+
 
 ### Compile-Time conditional code
 
@@ -307,4 +374,4 @@ of their debugs.
 CLI's are a complicated ugly beast.  Additions or changes to the CLI
 should use a DEFUN to encapsulate one setting as much as is possible.
 Additionally as new DEFUN's are added to the system, documentation
-should be provided for the new commands.
\ No newline at end of file
+should be provided for the new commands.
index a201bb681916a680975d80daebbd33e3391caaaf..ec7e6cdde849cbfc64391d8d5bfaddcba840b351 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,4 @@
-ChangeLog information for FreeRangeRouting is for now recorded in source-code
+ChangeLog information for FRRouting is for now recorded in source-code
 management system. Please see:
 
-       http://www.freerangerouting.org/
+       http://www.frrouting.org/
index aeacd4c3ce2ecd8827920d6cc095435a2d4b7bf1..c0efa1925a16762e310f1423613bacec11af70eb 100644 (file)
@@ -18,3 +18,5 @@ EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \
        tools/zebra.el tools/multiple-bgpd.sh
 
 ACLOCAL_AMFLAGS = -I m4
+
+noinst_HEADERS = defaults.h
index ea36ff5eed8d69eb2283e6d4a3743d1804862941..01f25a2051ac34989d5a4f4bc6d5564810ec77aa 100644 (file)
@@ -1,5 +1,5 @@
-This file describes the procedure for reporting FreeRangeRouting bugs. You are not
-obliged to follow this format, but it would be great help for FreeRangeRouting developers
+This file describes the procedure for reporting FRRouting bugs. You are not
+obliged to follow this format, but it would be great help for FRRouting developers
 if you report a bug as described below.
 
 Bugs submitted with woefully incomplete information may be summarily
@@ -10,10 +10,10 @@ non-response to requests to reconfirm or supply additional
 information.
 
 Report bugs on Github Issue Tracker at 
-    https://github.com/freerangerouting/frr/issues
+    https://github.com/frrouting/frr/issues
 
 Please supply the following information:
-1. Your FreeRangeRouting version or if it is from git then the  commit reference.
+1. Your FRRouting version or if it is from git then the  commit reference.
    Please try to report bugs against git master or the latest release.
 2. FRR daemons you run e.g. bgpd or ripd and full name of your OS. Any
    specific options you compiled Quagga with. 
index 50afc7ed64edd00c1a8108801fbc1b95ce0280cf..b6ed9a4d6db726e6d18ce453e901ce57ef2eef81 100644 (file)
@@ -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,15 @@ 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_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+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
index 7dc7f053d60efaf0f59962654f44fb21e38eb312..2bbdca595c512cd22909bfc938f7217871d5ff0a 100644 (file)
@@ -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 ();
index e47d07702ba8b9a7c845f82e88624a3daa150760..4d0b48f5296e8f47c6788e4a0e4dc0ae88ccd9ee 100644 (file)
@@ -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 */
index 1358ebc5ef8c3c685b5ee43c0581e2548fcf85e3..46ae882b2ec59e7cd40dd5e545c4fa50eed4c404 100644 (file)
@@ -262,7 +262,7 @@ bgp_get_instance_for_inc_conn (int sock, struct bgp **bgp_inst)
       if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
         continue;
 
-      ifp = if_lookup_by_name_vrf (name, bgp->vrf_id);
+      ifp = if_lookup_by_name (name, bgp->vrf_id);
       if (ifp)
         {
           *bgp_inst = bgp;
@@ -544,7 +544,7 @@ bgp_update_source (struct peer *peer)
   /* Source is specified with interface name.  */
   if (peer->update_if)
     {
-      ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
+      ifp = if_lookup_by_name (peer->update_if, peer->bgp->vrf_id);
       if (! ifp)
        return -1;
 
@@ -617,7 +617,7 @@ bgp_connect (struct peer *peer)
     }
 
   if (peer->conf_if || peer->ifname)
-    ifindex = ifname2ifindex (peer->conf_if ? peer->conf_if : peer->ifname);
+    ifindex = ifname2ifindex (peer->conf_if ? peer->conf_if : peer->ifname, peer->bgp->vrf_id);
 
   if (bgp_debug_neighbor_events(peer))
     zlog_debug ("%s [Event] Connect start to %s fd %d",
index 0cf96101c2142f3bf9b8a4784b8f6e3b95aa373f..9300345899523b32c140df5392e11561667e1202 100644 (file)
@@ -415,7 +415,7 @@ bgp_show_nexthops (struct vty *vty, struct bgp *bgp, int detail)
                          vty_out(vty, "  gate %s, if %s%s",
                                  inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
                                            sizeof (buf)),
-                                 ifindex2ifname(nexthop->ifindex),
+                                 ifindex2ifname(nexthop->ifindex, bgp->vrf_id),
                                  VTY_NEWLINE);
                          break;
                        case NEXTHOP_TYPE_IPV4:
@@ -425,13 +425,13 @@ bgp_show_nexthops (struct vty *vty, struct bgp *bgp, int detail)
                          break;
                        case NEXTHOP_TYPE_IFINDEX:
                          vty_out (vty, "  if %s%s",
-                                  ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
+                                  ifindex2ifname(nexthop->ifindex, bgp->vrf_id), VTY_NEWLINE);
                          break;
                        case NEXTHOP_TYPE_IPV4_IFINDEX:
                          vty_out (vty, "  gate %s, if %s%s",
                                   inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
                                             sizeof (buf)),
-                                  ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
+                                  ifindex2ifname(nexthop->ifindex, bgp->vrf_id), VTY_NEWLINE);
                          break;
                        default:
                          vty_out (vty, "  invalid nexthop type %u%s",
index 5e6218e8a34eb6a13e7014f4d866b6bfa0491f43..f45d68384886ac378fdafe606ab1c3eb2fbdfdd3 100644 (file)
@@ -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 (file)
index 7a0d9dd..0000000
+++ /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 */
index dba336051acabb87154e82e0541b3761f48753c8..e94de682d58af1feea9f0ad2b0c3130e64e24efa 100644 (file)
@@ -806,7 +806,7 @@ DEFUN (no_auto_summary,
 }
 
 /* "router bgp" commands. */
-DEFUN (router_bgp,
+DEFUN_NOSH (router_bgp,
        router_bgp_cmd,
        "router bgp [(1-4294967295) [<view|vrf> WORD]]",
        ROUTER_STR
@@ -5647,7 +5647,7 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
                                 PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
 }
 
-DEFUN (address_family_ipv4_safi,
+DEFUN_NOSH (address_family_ipv4_safi,
        address_family_ipv4_safi_cmd,
        "address-family ipv4 [<unicast|multicast|vpn|encap>]",
        "Enter Address Family command mode\n"
@@ -5680,7 +5680,7 @@ DEFUN (address_family_ipv4_safi,
   return CMD_SUCCESS;
 }
 
-DEFUN (address_family_ipv6_safi,
+DEFUN_NOSH (address_family_ipv6_safi,
        address_family_ipv6_safi_cmd,
        "address-family ipv6 [<unicast|multicast|vpn|encap>]",
        "Enter Address Family command mode\n"
@@ -5714,7 +5714,7 @@ DEFUN (address_family_ipv6_safi,
 }
 
 #ifdef KEEP_OLD_VPN_COMMANDS
-DEFUN (address_family_vpnv4,
+DEFUN_NOSH (address_family_vpnv4,
        address_family_vpnv4_cmd,
        "address-family vpnv4 [unicast]",
        "Enter Address Family command mode\n"
@@ -5725,7 +5725,7 @@ DEFUN (address_family_vpnv4,
   return CMD_SUCCESS;
 }
 
-DEFUN (address_family_vpnv6,
+DEFUN_NOSH (address_family_vpnv6,
        address_family_vpnv6_cmd,
        "address-family vpnv6 [unicast]",
        "Enter Address Family command mode\n"
@@ -5737,7 +5737,7 @@ DEFUN (address_family_vpnv6,
 }
 #endif
 
-DEFUN (address_family_encap,
+DEFUN_NOSH (address_family_encap,
        address_family_encap_cmd,
        "address-family <encap|encapv4>",
        "Enter Address Family command mode\n"
@@ -5749,7 +5749,7 @@ DEFUN (address_family_encap,
 }
 
 
-DEFUN (address_family_encapv6,
+DEFUN_NOSH (address_family_encapv6,
        address_family_encapv6_cmd,
        "address-family encapv6",
        "Enter Address Family command mode\n"
@@ -5759,7 +5759,7 @@ DEFUN (address_family_encapv6,
   return CMD_SUCCESS;
 }
 
-DEFUN (address_family_evpn,
+DEFUN_NOSH (address_family_evpn,
        address_family_evpn_cmd,
        "address-family <l2vpn evpn>",
        "Enter Address Family command mode\n"
@@ -5771,7 +5771,7 @@ DEFUN (address_family_evpn,
   return CMD_SUCCESS;
 }
 
-DEFUN (exit_address_family,
+DEFUN_NOSH (exit_address_family,
        exit_address_family_cmd,
        "exit-address-family",
        "Exit from Address Family configuration mode\n")
index 2a513dda25619c60cc43e18f7bf46e3583c50190..72bd081a7e75c4480dbd92d037538c7fbf4f15bd 100644 (file)
@@ -570,7 +570,7 @@ bgp_interface_vrf_update (int command, struct zclient *zclient, zebra_size_t len
       }
   }
 
-  if_update_vrf (ifp, ifp->name, strlen (ifp->name), new_vrf_id);
+  if_update (ifp, ifp->name, strlen (ifp->name), new_vrf_id);
 
   bgp = bgp_lookup_by_vrf_id (new_vrf_id);
   if (!bgp)
@@ -1026,7 +1026,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
     {
       nexthop->v4 = local->sin.sin_addr;
       if (peer->update_if)
-        ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
+        ifp = if_lookup_by_name (peer->update_if, peer->bgp->vrf_id);
       else
         ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr, peer->bgp->vrf_id);
     }
@@ -1035,10 +1035,10 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
       if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
        {
          if (peer->conf_if || peer->ifname)
-           ifp = if_lookup_by_name_vrf (peer->conf_if ? peer->conf_if : peer->ifname, peer->bgp->vrf_id);
+           ifp = if_lookup_by_name (peer->conf_if ? peer->conf_if : peer->ifname, peer->bgp->vrf_id);
        }
       else if (peer->update_if)
-        ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
+        ifp = if_lookup_by_name (peer->update_if, peer->bgp->vrf_id);
       else
         ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr,
                                       local->sin6.sin6_scope_id,
@@ -1509,7 +1509,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (!ifindex)
            {
              if (mpinfo->peer->conf_if || mpinfo->peer->ifname)
-               ifindex = ifname2ifindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname);
+               ifindex = ifname2ifindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname, bgp->vrf_id);
              else if (mpinfo->peer->nexthop.ifp)
                ifindex = mpinfo->peer->nexthop.ifp->ifindex;
            }
index ce0718df5a43aa1426cc22135600b108f3088cd0..3f81c1c50ce4b5d8088faeaba81c4f67d56b4a88 100644 (file)
@@ -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"
@@ -1435,7 +1432,7 @@ bgp_peer_conf_if_to_su_update (struct peer *peer)
     return;
 
   prev_family = peer->su.sa.sa_family;
-  if ((ifp = if_lookup_by_name_vrf (peer->conf_if, peer->bgp->vrf_id)))
+  if ((ifp = if_lookup_by_name (peer->conf_if, peer->bgp->vrf_id)))
     {
       peer->ifp = ifp;
       /* If BGP unnumbered is not "v6only", we first see if we can derive the
@@ -2937,10 +2934,18 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
   bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
   bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
   bgp->dynamic_neighbors_count = 0;
+#if DFLT_BGP_IMPORT_CHECK
   bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
+#endif
+#if DFLT_BGP_SHOW_HOSTNAME
   bgp_flag_set (bgp, BGP_FLAG_SHOW_HOSTNAME);
+#endif
+#if DFLT_BGP_LOG_NEIGHBOR_CHANGES
   bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
+#endif
+#if DFLT_BGP_DETERMINISTIC_MED
   bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
+#endif
   bgp->addpath_tx_id = BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE;
 
   bgp->as = *as;
@@ -5016,8 +5021,28 @@ int
 peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
 {
   struct peer_group *group;
+  struct peer *tmp_peer;
   struct listnode *node, *nnode;
 
+  /* If this is a peer-group we must first clear the flags for all of the
+   * peer-group members
+   */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      group = peer->group;
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
+        {
+          if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
+              CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
+            {
+              tmp_peer->allowas_in[afi][safi] = 0;
+              peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+              peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
+              peer_on_policy_change (tmp_peer, afi, safi, 0);
+            }
+        }
+    }
+
   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
       CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
     {
@@ -5027,21 +5052,6 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
       peer_on_policy_change (peer, afi, safi, 0);
     }
 
-  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
-    return 0;
-
-  group = peer->group;
-  for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
-    {
-      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
-          CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
-       {
-         peer->allowas_in[afi][safi] = 0;
-         peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
-         peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
-          peer_on_policy_change (peer, afi, safi, 0);
-       }
-    }
   return 0;
 }
 
@@ -7379,8 +7389,11 @@ bgp_config_write (struct vty *vty)
                  inet_ntoa (bgp->router_id_static), VTY_NEWLINE);
 
       /* BGP log-neighbor-changes. */
-      if (!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
-       vty_out (vty, " no bgp log-neighbor-changes%s", VTY_NEWLINE);
+      if (!!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)
+          != DFLT_BGP_LOG_NEIGHBOR_CHANGES)
+        vty_out (vty, " %sbgp log-neighbor-changes%s",
+                 bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES) ? "" : "no ",
+                 VTY_NEWLINE);
 
       /* BGP configuration. */
       if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
@@ -7396,8 +7409,11 @@ bgp_config_write (struct vty *vty)
                 bgp->default_local_pref, VTY_NEWLINE);
 
       /* BGP default show-hostname */
-      if (!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME))
-       vty_out (vty, " no bgp default show-hostname%s", VTY_NEWLINE);
+      if (!!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME)
+          != DFLT_BGP_SHOW_HOSTNAME)
+        vty_out (vty, " %sbgp default show-hostname%s",
+                 bgp_flag_check (bgp, BGP_FLAG_SHOW_HOSTNAME) ? "" : "no ",
+                 VTY_NEWLINE);
 
       /* BGP default subgroup-pkt-queue-max. */
       if (bgp->default_subgroup_pkt_queue_max != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
@@ -7440,8 +7456,11 @@ bgp_config_write (struct vty *vty)
        vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE);
 
       /* BGP deterministic-med. */
-      if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
-        vty_out (vty, " no bgp deterministic-med%s", VTY_NEWLINE);
+      if (!!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
+          != DFLT_BGP_DETERMINISTIC_MED)
+        vty_out (vty, " %sbgp deterministic-med%s",
+                 bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) ? "" : "no ",
+                 VTY_NEWLINE);
 
       /* BGP update-delay. */
       bgp_config_write_update_delay (vty, bgp);
@@ -7517,8 +7536,11 @@ bgp_config_write (struct vty *vty)
        }
 
       /* BGP network import check. */
-      if (!bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
-       vty_out (vty, " no bgp network import-check%s", VTY_NEWLINE);
+      if (!!bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)
+          != DFLT_BGP_IMPORT_CHECK)
+        vty_out (vty, " %sbgp network import-check%s",
+                 bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) ? "" : "no ",
+                 VTY_NEWLINE);
 
       /* BGP flag dampening. */
       if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
@@ -7647,6 +7669,8 @@ bgp_if_finish (struct bgp *bgp)
     }
 }
 
+extern void bgp_snmp_init (void);
+
 void
 bgp_init (void)
 {
@@ -7695,10 +7719,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();
 }
index 9ccc0e39dee548c12183431f8e08f3d11b62a6b2..a72974bc1d6e9c866df009c02a8313df3d34062b 100644 (file)
@@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "sockunion.h"
 #include "routemap.h"
 #include "linklist.h"
+#include "defaults.h"
 #include "bgp_memory.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
@@ -1068,12 +1069,13 @@ struct bgp_nlri
 #define BGP_EVENTS_MAX                          15
 
 /* BGP timers default value.  */
+/* note: the DFLT_ ones depend on compile-time "defaults" selection */
 #define BGP_INIT_START_TIMER                     1
-#define BGP_DEFAULT_HOLDTIME                     9
-#define BGP_DEFAULT_KEEPALIVE                    3
+#define BGP_DEFAULT_HOLDTIME                      DFLT_BGP_HOLDTIME
+#define BGP_DEFAULT_KEEPALIVE                     DFLT_BGP_KEEPALIVE
 #define BGP_DEFAULT_EBGP_ROUTEADV                0
 #define BGP_DEFAULT_IBGP_ROUTEADV                0
-#define BGP_DEFAULT_CONNECT_RETRY               10
+#define BGP_DEFAULT_CONNECT_RETRY                 DFLT_BGP_TIMERS_CONNECT
 
 /* BGP default local preference.  */
 #define BGP_DEFAULT_LOCAL_PREF                 100
index 71086c875871882468e162e88dd2dba88fdb4ee5..aa48b4924afed9927fa40dfba5c4d73c3bf30a54 100644 (file)
@@ -323,7 +323,7 @@ DEFUN (vnc_advertise_un_method,
  *-----------------------------------------------------------------------*/
 
 
-DEFUN (vnc_defaults,
+DEFUN_NOSH (vnc_defaults,
        vnc_defaults_cmd,
        "vnc defaults", VNC_CONFIG_STR "Configure default NVE group\n")
 {
@@ -2419,7 +2419,7 @@ vnc_routemap_event (route_map_event_t type,     /* ignored */
  *-----------------------------------------------------------------------*/
 
 
-DEFUN (vnc_nve_group,
+DEFUN_NOSH (vnc_nve_group,
        vnc_nve_group_cmd,
        "vnc nve-group NAME",
        VNC_CONFIG_STR "Configure a NVE group\n" "Group name\n")
@@ -3223,7 +3223,7 @@ DEFUN (vnc_nve_group_responselifetime,
  * with the lack of rigorous level control in the command handler. 
  * TBD fix command handler.
  */
-DEFUN (exit_vnc,
+DEFUN_NOSH (exit_vnc,
        exit_vnc_cmd,
        "exit-vnc",
        "Exit VNC configuration mode\n")
@@ -3255,7 +3255,7 @@ static struct cmd_node bgp_vnc_nve_group_node = {
  * Note there are two types of NVEs, one for VPNs one for RFP NVEs
  *-----------------------------------------------------------------------*/
 
-DEFUN (vnc_vrf_policy,
+DEFUN_NOSH (vnc_vrf_policy,
        vnc_vrf_policy_cmd,
        "vrf-policy NAME",
        "Configure a VRF policy group\n"
@@ -3720,7 +3720,7 @@ DEFUN (vnc_vrf_policy_rd,
   return CMD_SUCCESS;
 }
 
-DEFUN (exit_vrf_policy,
+DEFUN_NOSH (exit_vrf_policy,
        exit_vrf_policy_cmd,
        "exit-vrf-policy",
        "Exit VRF policy configuration mode\n")
@@ -3743,7 +3743,7 @@ static struct cmd_node bgp_vrf_policy_node = {
  *-----------------------------------------------------------------------*/
 
 
-DEFUN (vnc_l2_group,
+DEFUN_NOSH (vnc_l2_group,
        vnc_l2_group_cmd,
        "vnc l2-group NAME",
        VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")
index 821e0e230bdd0b2f8e50ac899e4187820c0e9bd9..ec5442d06596abf09d595330f826b267d316270b 100755 (executable)
@@ -1,5 +1,5 @@
 ##
-## Configure template file for FreeRangeRouting.
+## Configure template file for FRRouting.
 ## autoconf will generate configure script.
 ##
 ##  Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
@@ -7,9 +7,9 @@
 ##
 AC_PREREQ(2.60)
 
-AC_INIT(frr, 2.1-dev, [https://github.com/freerangerouting/frr/issues])
-PACKAGE_URL="https://freerangerouting.org/"
-PACKAGE_FULLNAME="FreeRangeRouting"
+AC_INIT(frr, 2.1-dev, [https://github.com/frrouting/frr/issues])
+PACKAGE_URL="https://frrouting.org/"
+PACKAGE_FULLNAME="FRRouting"
 AC_SUBST(PACKAGE_FULLNAME)
 
 CONFIG_ARGS="$ac_configure_args"
@@ -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
@@ -66,6 +73,10 @@ LIBS="$LIBS -ltcmalloc_minimal"
 esac],[tcmalloc_enabled=false])
 
 
+dnl Thanks autoconf, but we don't want a default -g -O2.  We have our own
+dnl flag determination logic.
+CFLAGS="${CFLAGS:-}"
+
 dnl --------------------
 dnl Check CC and friends
 dnl --------------------
@@ -78,6 +89,7 @@ AM_PROG_CC_C_O
 dnl remove autoconf default "-g -O2"
 CFLAGS="$orig_cflags"
 AC_PROG_CC_C99
+dnl NB: see C11 below
 
 AC_PROG_EGREP
 PKG_PROG_PKG_CONFIG
@@ -89,7 +101,7 @@ AC_CHECK_PROG([SED],[sed],[sed],[/bin/false])
 dnl try and enable CFLAGS that are useful for Quagga
 dnl - specifically, options to control warnings
 
-AC_USE_SYSTEM_EXTENSIONS()
+AC_USE_SYSTEM_EXTENSIONS
 AC_DEFUN([AC_C_FLAG], [{
        AC_LANG_PUSH(C)
        ac_c_flag_save="$CFLAGS"
@@ -115,6 +127,13 @@ dnl ICC won't bail on unknown options without -diag-error 10006
 dnl need to do this first so we get useful results for the other options
 AC_C_FLAG([-diag-error 10006])
 
+dnl AC_PROG_CC_C99 may change CC to include -std=gnu99 or something
+ac_cc="$CC"
+CC="${CC% -std=gnu99}"
+CC="${CC% -std=c99}"
+
+AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"])
+
 dnl if the user specified any CFLAGS, we don't add "-g -Os/-O2" here
 if test "z$orig_cflags" = "z"; then
   AC_C_FLAG([-g])
@@ -170,6 +189,18 @@ AC_LINK_IFELSE(
        ])
 AC_LANG_POP(C)
 
+dnl ----------
+dnl Essentials
+dnl ----------
+
+AX_PTHREAD([
+  CC="$PTHREAD_CC"
+  CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+  LIBS="$PTHREAD_LIBS $LIBS"
+], [
+  AC_MSG_FAILURE([This Quagga version needs pthreads])
+])
+
 dnl --------------
 dnl Check programs
 dnl --------------
@@ -354,15 +385,18 @@ AC_SUBST(MPLS_METHOD)
 
 if test "${enable_cumulus}" = "yes" ; then
   AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in)
+  DFLT_NAME="datacenter"
+else
+  DFLT_NAME="traditional"
 fi
+AC_SUBST(DFLT_NAME)
+AC_DEFINE_UNQUOTED(DFLT_NAME,["$DFLT_NAME"], Name of the configuration default set)
 
 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)
@@ -531,6 +565,72 @@ AC_CHECK_HEADERS([stropts.h sys/ksym.h \
        linux/version.h asm/types.h \
        sys/cdefs.h])
 
+ac_stdatomic_ok=false
+AC_DEFINE(FRR_AUTOCONF_ATOMIC, 1, [did autoconf checks for atomic funcs])
+AC_CHECK_HEADER([stdatomic.h],[
+
+  AC_MSG_CHECKING([whether _Atomic qualifier works])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+#include <stdatomic.h>
+int main(int argc, char **argv) {
+  _Atomic int i = 0;
+  return i;
+}
+]])], [
+    AC_DEFINE(HAVE_STDATOMIC_H, 1, [found stdatomic.h])
+    AC_MSG_RESULT([yes])
+    ac_stdatomic_ok=true
+  ], [
+    AC_MSG_RESULT([no])
+  ])
+])
+
+AS_IF([$ac_stdatomic_ok], [true], [
+  AC_MSG_CHECKING([for __atomic_* builtins])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __atomic_store_n (&i, 0, __ATOMIC_RELEASE);
+  return __atomic_load_n (&i, __ATOMIC_ACQUIRE);
+}
+]])], [
+    AC_DEFINE(HAVE___ATOMIC, 1, [found __atomic builtins])
+    AC_MSG_RESULT([yes])
+  ], [
+    AC_MSG_RESULT([no])
+
+    dnl FreeBSD 9 has a broken stdatomic.h where _Atomic doesn't work
+    AC_MSG_CHECKING([for __sync_* builtins])
+    AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __sync_fetch_and_sub (&i, 1);
+  return __sync_val_compare_and_swap (&i, 0, 1);
+}
+]])], [
+      AC_DEFINE(HAVE___SYNC, 1, [found __sync builtins])
+      AC_MSG_RESULT([yes])
+
+      AC_MSG_CHECKING([for __sync_swap builtin])
+      AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  return __sync_swap (&i, 2);
+}
+]])], [
+        AC_DEFINE(HAVE___SYNC_SWAP, 1, [found __sync_swap builtin])
+        AC_MSG_RESULT([yes])
+      ], [
+        AC_MSG_RESULT([no])
+      ])
+
+    ], [
+      AC_MSG_RESULT([no])
+      AC_MSG_FAILURE([stdatomic.h unavailable and $CC has neither __atomic nor __sync builtins])
+    ])
+  ])
+])
+
 dnl Utility macro to avoid retyping includes all the time
 m4_define([FRR_INCLUDES],
 [#ifdef SUNOS_5
@@ -1327,8 +1427,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);
@@ -1340,7 +1440,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
@@ -1356,6 +1455,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
@@ -1656,14 +1802,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
@@ -1692,6 +1842,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
          snapcraft/Makefile
          snapcraft/snapcraft.yaml
          lib/version.h
+         tests/lib/cli/test_cli.refout
          doc/defines.texi
          doc/bgpd.8
          doc/isisd.8
@@ -1728,7 +1879,7 @@ AC_CONFIG_FILES([vtysh/extract.pl],[chmod +x vtysh/extract.pl])
 AC_OUTPUT
 
 echo "
-FreeRangeRouting configuration
+FRRouting configuration
 ------------------------------
 FRR version             : ${PACKAGE_VERSION}
 host operating system   : ${host_os}
@@ -1740,6 +1891,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}
index caded52075820c61dcc6f62db9802b3501cfd214..4cf35d7e325aefd91291159f4d8281fc4e9831fa 100644 (file)
@@ -14,7 +14,7 @@ available forcing you to explicitly type "apt-get install frr" to upgrade it.
 * What is frr?
 =================
 
-http://www.freerangerouting.org/
+http://www.frrouting.org/
 FRR is a routing software suite, providing implementations of OSPFv2,
 OSPFv3, RIP v1 and v2, RIPng, ISIS, PIM, BGP and LDP for Unix platforms, particularly
 FreeBSD and Linux and also NetBSD, to mention a few. FRR is a fork of Quagga
index 6a5ed98f916b7cdabf5f94004957c24f72c99ccc..7b873abd311f49c38a59e2b758142080eeb1bd66 100644 (file)
@@ -1,7 +1,7 @@
 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: Frr
-Upstream-Contact: maintainers@freerangerouting.org, security@freerangerouting.org
-Source: http://www.freerangerouting.org/
+Upstream-Contact: maintainers@frrouting.org, security@frrouting.org
+Source: http://www.frrouting.org/
 
 Files: *
 Copyright: 1996-2003 by the original Zebra authors:
diff --git a/defaults.h b/defaults.h
new file mode 100644 (file)
index 0000000..57e35f3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * FRR switchable defaults.
+ * Copyright (C) 2017  David Lamparter for NetDEF, Inc.
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FRR_DEFAULTS_H
+#define _FRR_DEFAULTS_H
+
+#include "config.h"
+
+#ifdef HAVE_CUMULUS
+
+#define DFLT_BGP_IMPORT_CHECK                  1
+#define DFLT_BGP_TIMERS_CONNECT                        10
+#define DFLT_BGP_HOLDTIME                      9
+#define DFLT_BGP_KEEPALIVE                     3
+#define DFLT_BGP_LOG_NEIGHBOR_CHANGES          1
+#define DFLT_BGP_SHOW_HOSTNAME                 1
+#define DFLT_BGP_DETERMINISTIC_MED             1
+
+#define DFLT_OSPF_LOG_ADJACENCY_CHANGES                1
+#define DFLT_OSPF6_LOG_ADJACENCY_CHANGES       1
+
+#else /* !HAVE_CUMULUS */
+
+#define DFLT_BGP_IMPORT_CHECK                  0
+#define DFLT_BGP_TIMERS_CONNECT                        120
+#define DFLT_BGP_HOLDTIME                      180
+#define DFLT_BGP_KEEPALIVE                     60
+#define DFLT_BGP_LOG_NEIGHBOR_CHANGES          0
+#define DFLT_BGP_SHOW_HOSTNAME                 0
+#define DFLT_BGP_DETERMINISTIC_MED             0
+
+#define DFLT_OSPF_LOG_ADJACENCY_CHANGES                0
+#define DFLT_OSPF6_LOG_ADJACENCY_CHANGES       0
+
+#endif /* !HAVE_CUMULUS */
+
+#endif /* _FRR_DEFAULTS_H */
index ccb07fb2acf7157a970dc7ff50354e75a78e5af5..9f40418fffdceec52e1d5c7a42a527a5d379f63c 100644 (file)
@@ -18,7 +18,7 @@ Add packages:
 
     sudo yum install git autoconf automake libtool make gawk readline-devel \
       texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
-      flex pytest
+      flex c-ares-devel epel-release rpm-build libcap-devel texi2html
 
 Install newer version of bison (CentOS 6 package source is too old) from 
 CentOS 7
@@ -48,16 +48,16 @@ Install newer version of autoconf and automake (Package versions are too old)
 
 Install `Python 2.7` in parallel to default 2.6 (needed for `make check` to 
 run unittests). 
-Pick correct EPEL based on CentOS version used. Then install current `pytest`
+Make sure you've install EPEL (`epel-release` as above). Then install current 
+`python2.7` and `pytest`
 
-    rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
     rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
-    yum install python27 python27-pip
+    yum install python27 python27-devel python27-pip 
     pip2.7 install pytest
 
 Please note that `CentOS 6` needs to keep python pointing to version 2.6 
 for `yum` to keep working, so don't create a symlink for python2.7 to python
-    
+
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
 
@@ -69,7 +69,7 @@ any packages**
     sudo groupadd -g 92 frr
     sudo groupadd -r -g 85 frrvt
     sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
-      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+      -c "FRR FRRouting suite" -d /var/run/frr frr
 
 ### Download Source, configure and compile it
 (You may prefer different options on configure statement. These are just 
@@ -78,9 +78,8 @@ an example.)
 You may want to pay special attention to `/usr/lib64` paths and change 
 them if you are not building on a x86_64 architecture
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --sysconfdir=/etc/frr \
index cd10a91ed74fefad7b367a6060261e988ed52955..0ab5c0ff548ebdf6f8f59b68e3998ae95620437f 100644 (file)
@@ -10,12 +10,16 @@ CentOS 7 restrictions:
   
 Install required packages
 -------------------------
-        
+
 Add packages:
 
     sudo yum install git autoconf automake libtool make gawk readline-devel \
       texinfo net-snmp-devel groff pkgconfig json-c-devel pam-devel \
-      bison flex pytest
+      bison flex pytest c-ares-devel python-devel rpm-build
+
+To build from git (in difference to building from distribution tar.gz as created by `make dist`), the python development libraries are needed. (Make sure you've installed EPEL libraries as shown above for this to work)
+
+    yum install python34-devel
 
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
@@ -28,7 +32,7 @@ any packages**
     sudo groupadd -g 92 frr
     sudo groupadd -r -g 85 frrvt
     sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
-      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+      -c "FRR FRRouting suite" -d /var/run/frr frr
 
 ### Download Source, configure and compile it
 (You may prefer different options on configure statement. These are just 
@@ -37,9 +41,8 @@ an example.)
 You may want to pay special attention to `/usr/lib64` paths and change 
 them if you are not building on a x86_64 architecture
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --sysconfdir=/etc/frr \
index 902f8c623ae63a00760488df29c8420905b4c93c..b902033d5edef7cac392d6dc09112018904af9ae 100644 (file)
@@ -10,12 +10,12 @@ Debian 8 restrictions:
 
 Install required packages
 -------------------------
-        
+
 Add packages:
 
     sudo apt-get install git autoconf automake libtool make gawk \
        libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
-       python-pip
+       python-pip libc-ares-dev python3-dev
 
 Install newer pytest (>3.0) from pip    
 
@@ -32,16 +32,15 @@ any packages**
     sudo addgroup --system --gid 92 frr
     sudo addgroup --system --gid 85 frrvty
     sudo adduser --system --ingroup frr --groups frrvty --home /var/run/frr/ \
-       --gecos "FRR FreeRangeRouting suite" --shell /bin/false frr
+       --gecos "FRR FRRouting suite" --shell /bin/false frr
     sudo usermode
 
 ### Download Source, configure and compile it
 (You may prefer different options on configure statement. These are just
 an example.)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
index 9617afc733e37959cf44fbd45c8e3aef5a2ce3b3..941126da420997c4aaa8fba3b9de00613edd1f83 100644 (file)
@@ -8,7 +8,8 @@ Add packages:
 
     sudo dnf install git autoconf automake libtool make gawk \
        readline-devel texinfo net-snmp-devel groff pkgconfig \
-       json-c-devel pam-devel perl-XML-LibXML pytest
+       json-c-devel pam-devel perl-XML-LibXML c-ares-devel \
+       python3-devel
 
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
@@ -21,7 +22,7 @@ using any packages**
     sudo groupadd -g 92 frr
     sudo groupadd -r -g 85 frrvt
     sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
-      -c "FRR FreeRangeRouting suite" -d /var/run/frr frr
+      -c "FRR FRRouting suite" -d /var/run/frr frr
 
 ### Download Source, configure and compile it
 (You may prefer different options on configure statement. These are just 
@@ -30,9 +31,8 @@ an example.)
 You may want to pay special attention to `/usr/lib64` paths and change 
 them if you are not building on a x86_64 architecture
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --sysconfdir=/etc/frr \
index 696b7d5d2e85ac35bb02bd48b2f9aecc00ff7504..36ef573bb0ce4f983ccfbe8b5c429233d1fb058f 100644 (file)
@@ -16,7 +16,7 @@ Add packages:
 install and asked)  
 
     pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
-        bison flex py27-pytest
+        bison flex py27-pytest c-ares python3
 
 Make sure there is no /usr/bin/flex preinstalled (and use the newly 
 installed in /usr/local/bin):
@@ -41,9 +41,8 @@ using any packages**
 (You may prefer different options on configure statement. These are just 
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     export MAKE=gmake
     export LDFLAGS="-L/usr/local/lib"
index d0b8a7bf8832c37d8dd86bdfc4e7dbd4dc0d171b..d6affd688bcefed339429b260296ba940aa13b13 100644 (file)
@@ -16,7 +16,7 @@ Add packages:
 install and asked)  
 
     pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
-        bison flex py27-pytest
+        bison flex py27-pytest c-ares python3
 
 Make sure there is no /usr/bin/flex preinstalled (and use the newly 
 installed in /usr/local/bin):
@@ -41,9 +41,8 @@ using any packages**
 (You may prefer different options on configure statement. These are just
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     export MAKE=gmake
     export LDFLAGS="-L/usr/local/lib"
index d470d0046afbbf4ef3e800c1e24fed2e3a418fb2..41d3148ad72887284c8130a2824a825ae8f8d790 100644 (file)
@@ -16,7 +16,8 @@ Add packages:
 install and asked)  
 
     pkg install -y git autoconf automake libtool gmake gawk \
-        pkgconf texinfo json-c bison flex py27-pytest
+        pkgconf texinfo json-c bison flex py27-pytest c-ares \
+        python3
 
 Make sure there is no /usr/bin/flex preinstalled (and use the newly
 installed in /usr/local/bin):
@@ -25,6 +26,13 @@ takes preference in path)
 
     rm -f /usr/bin/flex
 
+For building with clang (instead of gcc), upgrade clang from 3.4 default to 3.6 *This is needed to build FreeBSD packages as well - for packages clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during compile)
+
+    pkg install clang36
+    pkg delete clang34
+    mv /usr/bin/clang /usr/bin/clang34
+    ln -s /usr/local/bin/clang36 /usr/bin/clang
+
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
 
@@ -41,9 +49,8 @@ using any packages**
 (You may prefer different options on configure statement. These are just
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     export MAKE=gmake
     export LDFLAGS="-L/usr/local/lib"
index 03d04ce954e4bf3cf51492328cbef2084d98ea5b..542a7f489e742b2aed2e26b5f40cfb4490769747 100644 (file)
@@ -18,7 +18,7 @@ Configure Package location:
 Add packages:
 
     sudo pkg_add git autoconf automake libtool gmake gawk openssl \
-       pkg-config json-c p5-XML-LibXML python27 py27-test
+       pkg-config json-c p5-XML-LibXML python27 py27-test python35
 
 Install SSL Root Certificates (for git https access):
 
@@ -45,9 +45,8 @@ Get FRR, compile it and install it (from Git)
 (You may prefer different options on configure statement. These are just 
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     MAKE=gmake
     export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
index d9b4b47ea60e809ecdc2045482dce7abb2c59c3a..821a6109f2d191ecfaab1a1a60044f9ec87503a9 100644 (file)
@@ -12,7 +12,7 @@ Install required packages
 -------------------------
 
     sudo pkgin install git autoconf automake libtool gmake gawk openssl \
-       pkg-config json-c p5-XML-LibXML python27 py27-test
+       pkg-config json-c p5-XML-LibXML python27 py27-test python35
 
 Install SSL Root Certificates (for git https access):
 
@@ -39,9 +39,8 @@ Get FRR, compile it and install it (from Git)
 (You may prefer different options on configure statement. These are just
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     MAKE=gmake
     export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib"
index f158c80a7544ed30eaff1f8a203d76d1fa592c31..2e9871467bf6445dc2849a205791f3ca71244ae7 100644 (file)
@@ -41,7 +41,7 @@ Add additional Solaris packages:
     /opt/csw/bin/pkgutil -y -i texinfo
     /opt/csw/bin/pkgutil -y -i perl
     /opt/csw/bin/pkgutil -y -i libjson_c_dev
-    /opt/csw/bin/pkgutil -y -i python27 py_pip
+    /opt/csw/bin/pkgutil -y -i python27 py_pip python27_dev
 
 Add libjson to Solaris equivalent of ld.so.conf
 
@@ -61,7 +61,7 @@ Select Python 2.7 as default (required for pytest)
 
     rm -f /usr/bin/python
     ln -s /opt/csw/bin/python2.7 /usr/bin/python
-        
+
 Fix PATH for all users and non-interactive sessions. Edit `/etc/default/login`
 and add the following default PATH:
 
@@ -87,13 +87,13 @@ any packages**
 (You may prefer different options on configure statement. These are just
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     export MAKE=gmake
     export LDFLAGS="-L/opt/csw/lib"
     export CPPFLAGS="-I/opt/csw/include"
+    export PKG_CONFIG_PATH=/opt/csw/lib/pkgconfig
     ./configure \
         --sysconfdir=/etc/frr \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
index 9e13d5ce458d0bca2a668443e86510f81dee9407..a59452a72b178a7f92e08bdd9f7c59d0c7a6dee3 100644 (file)
@@ -1,12 +1,6 @@
 Building FRR on OpenBSD 6 from Git Source
 =========================================
 
-OpenBSD restrictions:
----------------------
-
-- MPLS is not tested on `OpenBSD`. It may work as it shares the
-  sources with the LDPd on OpenBSD. Bug reports and fixes are welcome
-
 Install required packages
 -------------------------
 
@@ -40,9 +34,8 @@ any packages**
 (You may prefer different options on configure statement. These are just 
 an example)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     export LDFLAGS="-L/usr/local/lib"
     export CPPFLAGS="-I/usr/local/include"
@@ -61,7 +54,6 @@ an example)
         --enable-rtadv \
         --enable-tcp-zebra \
         --enable-fpm \
-        --enable-ldpd \
         --with-pkg-git-version \
         --with-pkg-extra-version=-MyOwnFRRVersion   
     gmake
@@ -99,6 +91,18 @@ Add the following lines to the end of `/etc/rc.conf`:
 
 **Reboot** to apply the config to the system
 
+### Enable MPLS Forwarding
+
+To enable MPLS forwarding on a given interface, use the following command:
+
+    sudo ifconfig em0 mpls
+
+Alternatively, to make MPLS forwarding persistent across reboots, add the "mpls"
+keyword in the hostname.* files of the desired interfaces. Example:
+
+    cat /etc/hostname.em0
+    inet 10.0.1.1 255.255.255.0 mpls
+
 ### Install rc.d init files
 (create them in /etc/rc.d - no example are included at this time with 
 FRR source)
index 3312a2c9c89dfc5e684988454ba26dda69044fe2..154907d9df39ba6f06f8e7d7b9765a7744620ed4 100644 (file)
@@ -12,8 +12,8 @@ Install required packages
 Add packages:
 
     apt-get install git autoconf automake libtool make gawk libreadline-dev \
-       texinfo libpam0g-dev dejagnu libjson0 pkg-config libpam0g-dev \
-       libjson0-dev flex python-pip
+       texinfo libpam0g-dev dejagnu libjson0-dev pkg-config libpam0g-dev \
+       libjson0-dev flex python-pip libc-ares-dev python3-dev
 
 Install newer bison from 14.04 package source (Ubuntu 12.04 package source
 is too old)
@@ -72,9 +72,8 @@ any packages**
 (You may prefer different options on configure statement. These are just
 an example.)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
@@ -94,7 +93,6 @@ an example.)
         --enable-rtadv \
         --enable-tcp-zebra \
         --enable-fpm \
-        --enable-ldpd \
         --with-pkg-git-version \
         --with-pkg-extra-version=-MyOwnFRRVersion   
     make
@@ -104,20 +102,20 @@ an example.)
 ### Create empty FRR configuration files
 
     sudo mkdir /var/log/frr
-    sudo chown frr:fee /var/log/frr
+    sudo chown frr:frr /var/log/frr
     sudo mkdir /etc/frr
-    sudo touch /etc/frr/etc/zebra.conf
-    sudo touch /etc/frr/etc/bgpd.conf
-    sudo touch /etc/frr/etc/ospfd.conf
-    sudo touch /etc/frr/etc/ospf6d.conf
-    sudo touch /etc/frr/etc/isisd.conf
-    sudo touch /etc/frr/etc/ripd.conf
-    sudo touch /etc/frr/etc/ripngd.conf
-    sudo touch /etc/frr/etc/pimd.conf
-    sudo touch /etc/frr/etc/ldpd.conf
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
+    sudo touch /etc/frr/ldpd.conf
     sudo chown frr:frr /etc/frr/
-    sudo touch /etc/frr/etc/vtysh.conf
-    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/vtysh.conf
     sudo chmod 640 /etc/frr/*.conf
 
 ### Enable IP & IPv6 forwarding
index ac0a45acdfcaa5a7c85c60529ecdff7942562804..33ef896a9ad68e73f7684c5ca5866d0b61fac096 100644 (file)
@@ -8,12 +8,12 @@ Building FRR on Ubuntu 14.04LTS from Git Source
 
 Install required packages
 -------------------------
-        
+
 Add packages:
 
     apt-get install git autoconf automake libtool make gawk libreadline-dev \
        texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
-       python-pytest
+       python-pytest libc-ares-dev python3-dev
 
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
@@ -32,9 +32,8 @@ any packages**
 (You may prefer different options on configure statement. These are just 
 an example.)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
@@ -63,19 +62,19 @@ an example.)
 ### Create empty FRR configuration files
 
     sudo mkdir /var/log/frr
-    sudo chown frr:fee /var/log/frr
+    sudo chown frr:frr /var/log/frr
     sudo mkdir /etc/frr
-    sudo touch /etc/frr/etc/zebra.conf
-    sudo touch /etc/frr/etc/bgpd.conf
-    sudo touch /etc/frr/etc/ospfd.conf
-    sudo touch /etc/frr/etc/ospf6d.conf
-    sudo touch /etc/frr/etc/isisd.conf
-    sudo touch /etc/frr/etc/ripd.conf
-    sudo touch /etc/frr/etc/ripngd.conf
-    sudo touch /etc/frr/etc/pimd.conf
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
     sudo chown frr:frr /etc/frr/
-    sudo touch /etc/frr/etc/vtysh.conf
-    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/vtysh.conf
     sudo chmod 640 /etc/frr/*.conf
 
 ### Enable IP & IPv6 forwarding
index d1e1a377d07d37b59e84e4831a6012af9d8bd325..18724859fb0a5422547da9dcf328b09613e05c3c 100644 (file)
@@ -14,7 +14,7 @@ Add packages:
 
     apt-get install git autoconf automake libtool make gawk libreadline-dev \
        texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
-       python-pytest
+       python-pytest libc-ares-dev python3-dev
 
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
@@ -33,9 +33,8 @@ any packages**
 (You may prefer different options on configure statement. These are just 
 an example.)
 
-    git clone https://github.com/freerangerouting/frr.git frr
+    git clone https://github.com/frrouting/frr.git frr
     cd frr
-    git checkout stable/2.0
     ./bootstrap.sh
     ./configure \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
@@ -55,7 +54,6 @@ an example.)
         --enable-rtadv \
         --enable-tcp-zebra \
         --enable-fpm \
-        --enable-ldpd \
         --with-pkg-git-version \
         --with-pkg-extra-version=-MyOwnFRRVersion   
     make
@@ -65,20 +63,20 @@ an example.)
 ### Create empty FRR configuration files
 
     sudo mkdir /var/log/frr
-    sudo chown frr:fee /var/log/frr
+    sudo chown frr:frr /var/log/frr
     sudo mkdir /etc/frr
-    sudo touch /etc/frr/etc/zebra.conf
-    sudo touch /etc/frr/etc/bgpd.conf
-    sudo touch /etc/frr/etc/ospfd.conf
-    sudo touch /etc/frr/etc/ospf6d.conf
-    sudo touch /etc/frr/etc/isisd.conf
-    sudo touch /etc/frr/etc/ripd.conf
-    sudo touch /etc/frr/etc/ripngd.conf
-    sudo touch /etc/frr/etc/pimd.conf
-    sudo touch /etc/frr/etc/ldpd.conf
+    sudo touch /etc/frr/zebra.conf
+    sudo touch /etc/frr/bgpd.conf
+    sudo touch /etc/frr/ospfd.conf
+    sudo touch /etc/frr/ospf6d.conf
+    sudo touch /etc/frr/isisd.conf
+    sudo touch /etc/frr/ripd.conf
+    sudo touch /etc/frr/ripngd.conf
+    sudo touch /etc/frr/pimd.conf
+    sudo touch /etc/frr/ldpd.conf
     sudo chown frr:frr /etc/frr/
-    sudo touch /etc/frr/etc/vtysh.conf
-    sudo chown frr:frrvty /etc/frr/etc/vtysh.conf
+    sudo touch /etc/frr/vtysh.conf
+    sudo chown frr:frrvty /etc/frr/vtysh.conf
     sudo chmod 640 /etc/frr/*.conf
 
 ### Enable IP & IPv6 forwarding
index cea33eaa81f35dfffa2e06c4714ea993bb5f7634..05d72bc80f6e26155c8cb002acc7393528e8d3ee 100644 (file)
@@ -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
index 9026f2cdee0aa792a8aaa535464c3610fa34e507..0df1b1dcea2f0cb711de2035c0e98b89d4d89880 100644 (file)
@@ -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
index 43d7442939674bb444fde535eac3daf46c9c4cb5..0fadba964afb85c549b7cbd89f15ff6c4f50bdb4 100644 (file)
@@ -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 (file)
index 0000000..87bc963
--- /dev/null
@@ -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.
index a64dc9e72962cb959c2fa1b05f1a4d9609c7b073..b08bb6fd04445d34096a1a91323d95871d0ae615 100644 (file)
@@ -7,7 +7,7 @@
 @setfilename frr.info
 @c Set variables - sourced from defines.texi
 @include defines.texi
-@settitle @uref{http://www.freerangerouting.org,,@value{PACKAGE_NAME}}
+@settitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}}
 @c %**end of header
 
 @c automake will automatically generate version.texi
@@ -48,16 +48,16 @@ This file documents the Frr Software Routing Suite which manages common
 TCP/IP routing protocols.
 
 This is Edition @value{EDITION}, last updated @value{UPDATED} of
-@cite{The Frr Manual}, for @uref{http://www.freerangerouting.org/,,@value{PACKAGE_NAME}}
+@cite{The Frr Manual}, for @uref{http://www.frrouting.org/,,@value{PACKAGE_NAME}}
 Version @value{VERSION}.
 
 @insertcopying
 @end ifinfo
 
 @titlepage
-@title @uref{http://www.freerangerouting.org,,Frr}
+@title @uref{http://www.frrouting.org,,Frr}
 @subtitle A routing software package for TCP/IP networks
-@subtitle @uref{http://www.freerangerouting.org,,@value{PACKAGE_NAME}} @value{VERSION}
+@subtitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}} @value{VERSION}
 @subtitle @value{UPDATED-MONTH}
 @author @value{AUTHORS}
 
@@ -72,9 +72,9 @@ Version @value{VERSION}.
 @node Top
 @top Frr -- With Virtual Network Control
                     
-@uref{http://www.freerangerouting.org,,Frr} is an advanced routing software package
+@uref{http://www.frrouting.org,,Frr} is an advanced routing software package
 that provides a suite of TCP/IP based routing protocols.  This is the Manual
-for @value{PACKAGE_STRING}. @uref{http://www.freerangerouting.org,,Frr} is a fork of 
+for @value{PACKAGE_STRING}. @uref{http://www.frrouting.org,,Frr} is a fork of 
 @uref{http://www.quagga.net,,Quagga}.
 
 @insertcopying
index 3943eeacc885b7353c852a0966bde22eabc214e1..0c2c96e39ed185c78515d75daaa9de2946dfbd1c 100644 (file)
@@ -1,3 +1,720 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" viewBox="52,37,407,656" width="407" height="656" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path fill="none" stroke="#008000" stroke-width="8" d="M288,252 L288,98.125"/><path fill="#008000" d="M277,99.5 L288,72 L299,99.5"/></g><path fill="none" stroke="#008000" stroke-width="8" d="M288.084,324 L216,288"/><g><path fill="none" stroke="#000100" stroke-width="8" d="M216,98.125 L216,684"/><path fill="#000100" d="M205,99.5 L216,72 L227,99.5"/><path fill="#000100" d="M225.625,692.25 L216,684 L206.375,692.25 L206.375,662 L216,653.75 L225.625,662"/></g><path fill="none" stroke="#f00" stroke-width="8" d="M216,648 L144,612"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,432 L144,396"/><path fill="none" stroke="#008000" stroke-width="8" d="M216,612 L288.084,648"/><path fill="none" stroke="#008000" stroke-width="8" d="M216,468 L288.084,504"/><path fill="none" stroke="#008000" stroke-width="8" d="M288.084,180 L216,144"/><text fill="#f00" font-family="Helvetica" font-weight="bold" font-size="12" text-anchor="middle" transform="matrix(1,0,0,1,146.988,431.607)" xml:space="preserve"><tspan>1.0</tspan><tspan x="0" y="16">Release</tspan><tspan x="0" y="32">Branch</tspan></text><path fill="none" stroke="#008000" stroke-width="8" d="M288.084,396 L216,360"/><path fill="none" stroke="#008000" stroke-width="8" d="M288.084,432 L216,396"/><path fill="none" stroke="#f00" stroke-width="8" d="M216.832,396 L144,360"/><path fill="none" stroke="#f00" stroke-width="8" d="M215.832,360 L144,324"/><path fill="#fffffe" stroke="#000100" d="M224,648 C224,652.418,220.418,656,216,656 C211.582,656,208,652.418,208,648 C208,643.582,211.582,640,216,640 C220.418,640,224,643.582,224,648 Z"/><path fill="#fffffe" stroke="#000100" d="M224,468 C224,472.418,220.418,476,216,476 C211.582,476,208,472.418,208,468 C208,463.582,211.582,460,216,460 C220.418,460,224,463.582,224,468 Z"/><path fill="#fffffe" stroke="#000100" d="M224,432 C224,436.418,220.418,440,216,440 C211.582,440,208,436.418,208,432 C208,427.582,211.582,424,216,424 C220.418,424,224,427.582,224,432 Z"/><path fill="#fffffe" stroke="#000100" d="M224,612 C224,616.418,220.418,620,216,620 C211.582,620,208,616.418,208,612 C208,607.582,211.582,604,216,604 C220.418,604,224,607.582,224,612 Z"/><path fill="#fffffe" stroke="#000100" d="M224,144 C224,148.418,220.418,152,216,152 C211.582,152,208,148.418,208,144 C208,139.582,211.582,136,216,136 C220.418,136,224,139.582,224,144 Z"/><path fill="#fffffe" stroke="#000100" d="M296,144 C296,148.418,292.418,152,288,152 C283.582,152,280,148.418,280,144 C280,139.582,283.582,136,288,136 C292.418,136,296,139.582,296,144 Z"/><path fill="#fffffe" stroke="#000100" d="M224,360 C224,364.418,220.418,368,216,368 C211.582,368,208,364.418,208,360 C208,355.582,211.582,352,216,352 C220.418,352,224,355.582,224,360 Z"/><path fill="#fffffe" stroke="#000100" d="M224,396 C224,400.418,220.418,404,216,404 C211.582,404,208,400.418,208,396 C208,391.582,211.582,388,216,388 C220.418,388,224,391.582,224,396 Z"/><text fill="#000100" font-family="Helvetica" font-weight="bold" font-size="12" text-anchor="middle" transform="matrix(1,0,0,1,216.312,49.5293)" xml:space="preserve"><tspan>Master</tspan><tspan x="0" y="16">(Stable)</tspan></text><g><path fill="none" stroke="#008000" stroke-width="8" d="M288,684 L288,432"/><path fill="#008000" d="M297.625,692.25 L288,684 L278.375,692.25 L278.375,662 L288,653.75 L297.625,662"/></g><path fill="none" stroke="#008000" stroke-width="8" d="M288,432 L288,252"/><path fill="#fffffe" stroke="#000100" d="M296,648 C296,652.418,292.418,656,288,656 C283.582,656,280,652.418,280,648 C280,643.582,283.582,640,288,640 C292.418,640,296,643.582,296,648 Z"/><text fill="#008000" font-family="Helvetica" font-weight="bold" font-size="12" text-anchor="middle" transform="matrix(1,0,0,1,287.841,62.2383)" xml:space="preserve"><tspan>Develop</tspan></text><g><path fill="none" stroke="#f00" stroke-width="8" d="M144.832,612 L144.832,494.125"/><path fill="#f00" d="M133.832,495.5 L144.832,468 L155.832,495.5"/></g><g><path fill="none" stroke="#f00" stroke-width="8" d="M144.832,396 L144.832,206.125"/><path fill="#f00" d="M133.832,207.5 L144.832,180 L155.832,207.5"/></g><text fill="#f00" font-family="Helvetica" font-weight="bold" font-size="12" text-anchor="middle" transform="matrix(1,0,0,1,146.988,142.607)" xml:space="preserve"><tspan>1.1</tspan><tspan x="0" y="16">Release</tspan><tspan x="0" y="32">Branch</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55,615.76)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>0.a1</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55.7734,399.76)" xml:space="preserve"><tspan>Version 1.1.a1</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55,363.76)" xml:space="preserve"><tspan>Version 1.1.a2</tspan></text><path fill="#fffffe" stroke="#000100" d="M152,612 C152,616.418,148.418,620,144,620 C139.582,620,136,616.418,136,612 C136,607.582,139.582,604,144,604 C148.418,604,152,607.582,152,612 Z"/><path fill="#fffffe" stroke="#000100" d="M152,396 C152,400.418,148.418,404,144,404 C139.582,404,136,400.418,136,396 C136,391.582,139.582,388,144,388 C148.418,388,152,391.582,152,396 Z"/><path fill="#fffffe" stroke="#000100" d="M152,360 C152,364.418,148.418,368,144,368 C139.582,368,136,364.418,136,360 C136,355.582,139.582,352,144,352 C148.418,352,152,355.582,152,360 Z"/><path fill="#fffffe" stroke="#000100" d="M152,324 C152,328.418,148.418,332,144,332 C139.582,332,136,328.418,136,324 C136,319.582,139.582,316,144,316 C148.418,316,152,319.582,152,324 Z"/><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55.7734,327.76)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>1.b1</tspan></text><path fill="#fffffe" stroke="#000100" d="M296,612 C296,616.418,292.418,620,288,620 C283.582,620,280,616.418,280,612 C280,607.582,283.582,604,288,604 C292.418,604,296,607.582,296,612 Z"/><path fill="#fffffe" stroke="#000100" d="M296,540 C296,544.418,292.418,548,288,548 C283.582,548,280,544.418,280,540 C280,535.582,283.582,532,288,532 C292.418,532,296,535.582,296,540 Z"/><path fill="#fffffe" stroke="#000100" d="M296,576 C296,580.418,292.418,584,288,584 C283.582,584,280,580.418,280,576 C280,571.582,283.582,568,288,568 C292.418,568,296,571.582,296,576 Z"/><path fill="#fffffe" stroke="#000100" d="M296,467 C296,471.418,292.418,475,288,475 C283.582,475,280,471.418,280,467 C280,462.582,283.582,459,288,459 C292.418,459,296,462.582,296,467 Z"/><path fill="#fffffe" stroke="#000100" d="M296,503 C296,507.418,292.418,511,288,511 C283.582,511,280,507.418,280,503 C280,498.582,283.582,495,288,495 C292.418,495,296,498.582,296,503 Z"/><path fill="#fffffe" stroke="#000100" d="M296,396 C296,400.418,292.418,404,288,404 C283.582,404,280,400.418,280,396 C280,391.582,283.582,388,288,388 C292.418,388,296,391.582,296,396 Z"/><path fill="#fffffe" stroke="#000100" d="M296,432 C296,436.418,292.418,440,288,440 C283.582,440,280,436.418,280,432 C280,427.582,283.582,424,288,424 C292.418,424,296,427.582,296,432 Z"/><path fill="#fffffe" stroke="#000100" d="M296,324 C296,328.418,292.418,332,288,332 C283.582,332,280,328.418,280,324 C280,319.582,283.582,316,288,316 C292.418,316,296,319.582,296,324 Z"/><path fill="#fffffe" stroke="#000100" d="M296,360 C296,364.418,292.418,368,288,368 C283.582,368,280,364.418,280,360 C280,355.582,283.582,352,288,352 C292.418,352,296,355.582,296,360 Z"/><path fill="#fffffe" stroke="#000100" d="M296,251 C296,255.418,292.418,259,288,259 C283.582,259,280,255.418,280,251 C280,246.582,283.582,243,288,243 C292.418,243,296,246.582,296,251 Z"/><path fill="#fffffe" stroke="#000100" d="M296,287 C296,291.418,292.418,295,288,295 C283.582,295,280,291.418,280,287 C280,282.582,283.582,279,288,279 C292.418,279,296,282.582,296,287 Z"/><path fill="#fffffe" stroke="#000100" d="M296,179 C296,183.418,292.418,187,288,187 C283.582,187,280,183.418,280,179 C280,174.582,283.582,171,288,171 C292.418,171,296,174.582,296,179 Z"/><path fill="#fffffe" stroke="#000100" d="M296,215 C296,219.418,292.418,223,288,223 C283.582,223,280,219.418,280,215 C280,210.582,283.582,207,288,207 C292.418,207,296,210.582,296,215 Z"/><g><path fill="none" stroke="#666" stroke-width="4" d="M432,540 L304.625,540"/><path fill="#666" d="M305.5,547 L288,540 L305.5,533"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,504 L304.625,504"/><path fill="#666" d="M305.5,511 L288,504 L305.5,497"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,468 L304.625,468"/><path fill="#666" d="M305.5,475 L288,468 L305.5,461"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,432 L304.625,432"/><path fill="#666" d="M305.5,439 L288,432 L305.5,425"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,396 L304.625,396"/><path fill="#666" d="M305.5,403 L288,396 L305.5,389"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,360 L304.625,360"/><path fill="#666" d="M305.5,367 L288,360 L305.5,353"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,324 L304.625,324"/><path fill="#666" d="M305.5,331 L288,324 L305.5,317"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,288 L304.625,288"/><path fill="#666" d="M305.5,295 L288,288 L305.5,281"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,252 L304.625,252"/><path fill="#666" d="M305.5,259 L288,252 L305.5,245"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,216 L304.625,216"/><path fill="#666" d="M305.5,223 L288,216 L305.5,209"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M404,180 L304.625,180"/><path fill="#666" d="M305.5,187 L288,180 L305.5,173"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,180 L304.625,180"/><path fill="#666" d="M305.5,187 L288,180 L305.5,173"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,144 L304.625,144"/><path fill="#666" d="M305.5,151 L288,144 L305.5,137"/></g><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,535)" xml:space="preserve"><tspan>Patch Email (Patchwork)</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,499)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,463)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,427)" xml:space="preserve"><tspan>Patch Email (Patchwork)</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,391)" xml:space="preserve"><tspan>Patch Email (Patchwork)</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,355)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,319)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,283)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,247)" xml:space="preserve"><tspan>Patch Email (Patchwork)</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,211)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,175)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,139)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,607)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,571)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,324,571)" xml:space="preserve"><tspan>Github Pull Request</tspan></text><g><path fill="none" stroke="#666" stroke-width="4" d="M432,612 L304.28,612"/><path fill="#666" d="M305.155,619 L287.655,612 L305.155,605"/></g><g><path fill="none" stroke="#666" stroke-width="4" d="M432,576 L304.625,576"/><path fill="#666" d="M305.5,583 L288,576 L305.5,569"/></g><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,56,581)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>0.a2</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,56,545)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>0.b1</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,56,509)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>0.0</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55.7734,292.76)" xml:space="preserve"><tspan>Version 1.1.0</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55,256.76)" xml:space="preserve"><tspan>Version 1.1.1</tspan></text><text fill="#000100" font-family="Helvetica" font-size="12" transform="matrix(1,0,0,1,55.7734,220.76)" xml:space="preserve"><tspan>Version 1.</tspan><tspan>1.2</tspan></text><path fill="none" stroke="#f00" stroke-width="8" d="M216,612 L144,576"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,576 L144,540"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,540 L144,504"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,324 L144,288"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,288 L144,252"/><path fill="none" stroke="#f00" stroke-width="8" d="M216,252 L144,216"/><path fill="#fffffe" stroke="#000100" d="M152,575 C152,579.418,148.418,583,144,583 C139.582,583,136,579.418,136,575 C136,570.582,139.582,567,144,567 C148.418,567,152,570.582,152,575 Z"/><path fill="#fffffe" stroke="#000100" d="M152,539 C152,543.418,148.418,547,144,547 C139.582,547,136,543.418,136,539 C136,534.582,139.582,531,144,531 C148.418,531,152,534.582,152,539 Z"/><path fill="#fffffe" stroke="#000100" d="M152,503 C152,507.418,148.418,511,144,511 C139.582,511,136,507.418,136,503 C136,498.582,139.582,495,144,495 C148.418,495,152,498.582,152,503 Z"/><path fill="#fffffe" stroke="#000100" d="M152,288 C152,292.418,148.418,296,144,296 C139.582,296,136,292.418,136,288 C136,283.582,139.582,280,144,280 C148.418,280,152,283.582,152,288 Z"/><path fill="#fffffe" stroke="#000100" d="M152,252 C152,256.418,148.418,260,144,260 C139.582,260,136,256.418,136,252 C136,247.582,139.582,244,144,244 C148.418,244,152,247.582,152,252 Z"/><path fill="#fffffe" stroke="#000100" d="M152,216 C152,220.418,148.418,224,144,224 C139.582,224,136,220.418,136,216 C136,211.582,139.582,208,144,208 C148.418,208,152,211.582,152,216 Z"/><path fill="#fffffe" stroke="#000100" d="M224,576 C224,580.418,220.418,584,216,584 C211.582,584,208,580.418,208,576 C208,571.582,211.582,568,216,568 C220.418,568,224,571.582,224,576 Z"/><path fill="#fffffe" stroke="#000100" d="M224,540 C224,544.418,220.418,548,216,548 C211.582,548,208,544.418,208,540 C208,535.582,211.582,532,216,532 C220.418,532,224,535.582,224,540 Z"/><path fill="#fffffe" stroke="#000100" d="M224,324 C224,328.418,220.418,332,216,332 C211.582,332,208,328.418,208,324 C208,319.582,211.582,316,216,316 C220.418,316,224,319.582,224,324 Z"/><path fill="#fffffe" stroke="#000100" d="M224,252 C224,256.418,220.418,260,216,260 C211.582,260,208,256.418,208,252 C208,247.582,211.582,244,216,244 C220.418,244,224,247.582,224,252 Z"/><path fill="#fffffe" stroke="#000100" d="M224,288 C224,292.418,220.418,296,216,296 C211.582,296,208,292.418,208,288 C208,283.582,211.582,280,216,280 C220.418,280,224,283.582,224,288 Z"/></svg>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   viewBox="52 37 349.25195 651.46875"
+   width="349.25195"
+   height="651.46875"
+   id="svg2"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="git_branches.svg">
+  <metadata
+     id="metadata376">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs374" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1596"
+     inkscape:window-height="848"
+     id="namedview372"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:zoom="0.89517435"
+     inkscape:cx="53.149337"
+     inkscape:cy="353.95197"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <g
+     id="g12"
+     transform="translate(-3.09375,-3.7812531)">
+    <path
+       d="M 216,98.125 216,684"
+       id="path14"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#000100;stroke-width:8" />
+    <path
+       d="M 205,99.5 216,72 227,99.5"
+       id="path16"
+       inkscape:connector-curvature="0"
+       style="fill:#000100" />
+    <path
+       d="M 225.625,692.25 216,684 l -9.625,8.25 0,-30.25 9.625,-8.25 9.625,8.25"
+       id="path18"
+       inkscape:connector-curvature="0"
+       style="fill:#000100" />
+  </g>
+  <path
+     d="m 212.90625,644.21875 -72,-36"
+     id="path20"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,428.21875 -72,-36"
+     id="path22"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <text
+     font-weight="bold"
+     font-size="12"
+     xml:space="preserve"
+     id="text30"
+     style="font-weight:bold;font-size:12px;font-family:Helvetica;text-anchor:middle;fill:#ff0000"
+     x="143.89426"
+     y="427.82574"><tspan
+       id="tspan32">1.0</tspan><tspan
+       x="143.89426"
+       y="443.82574"
+       id="tspan34">Release</tspan><tspan
+       x="143.89426"
+       y="459.82574"
+       id="tspan36">Branch</tspan></text>
+  <path
+     d="m 213.73825,392.21875 -72.832,-36"
+     id="path42"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.73825,356.21875 -71.832,-36"
+     id="path44"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 220.90625,644.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path46"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,464.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path48"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,428.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path50"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,608.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path52"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,140.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path54"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,356.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path58"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,392.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path60"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <text
+     font-weight="bold"
+     font-size="12"
+     xml:space="preserve"
+     id="text62"
+     style="font-weight:bold;font-size:12px;font-family:Helvetica;text-anchor:middle;fill:#000100"
+     x="213.21825"
+     y="45.748047"><tspan
+       id="tspan64">Master</tspan><tspan
+       x="213.21825"
+       y="61.748047"
+       id="tspan66">(Stable)</tspan></text>
+  <g
+     id="g82"
+     transform="translate(-3.09375,-3.7812531)">
+    <path
+       d="m 144.832,612 0,-117.875"
+       id="path84"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#ff0000;stroke-width:8" />
+    <path
+       d="m 133.832,495.5 11,-27.5 11,27.5"
+       id="path86"
+       inkscape:connector-curvature="0"
+       style="fill:#ff0000" />
+  </g>
+  <g
+     id="g88"
+     transform="translate(-3.09375,-3.7812531)">
+    <path
+       d="m 144.832,396 0,-189.875"
+       id="path90"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#ff0000;stroke-width:8" />
+    <path
+       d="m 133.832,207.5 11,-27.5 11,27.5"
+       id="path92"
+       inkscape:connector-curvature="0"
+       style="fill:#ff0000" />
+  </g>
+  <text
+     font-weight="bold"
+     font-size="12"
+     xml:space="preserve"
+     id="text94"
+     style="font-weight:bold;font-size:12px;font-family:Helvetica;text-anchor:middle;fill:#ff0000"
+     x="143.89426"
+     y="138.82574"><tspan
+       id="tspan96">1.1</tspan><tspan
+       x="143.89426"
+       y="154.82574"
+       id="tspan98">Release</tspan><tspan
+       x="143.89426"
+       y="170.82574"
+       id="tspan100">Branch</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text102"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="51.90625"
+     y="611.97876"><tspan
+       id="tspan104">Version 1.</tspan><tspan
+       id="tspan106">0.a1</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text108"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.679649"
+     y="395.97876"><tspan
+       id="tspan110">Version 1.1.a1</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text112"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="51.90625"
+     y="359.97876"><tspan
+       id="tspan114">Version 1.1.a2</tspan></text>
+  <path
+     d="m 148.90625,608.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path116"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,392.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path118"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,356.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path120"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,320.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path122"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text124"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.679649"
+     y="323.97876"><tspan
+       id="tspan126">Version 1.</tspan><tspan
+       id="tspan128">1.b1</tspan></text>
+  <g
+     id="g156"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,540 -127.375,0"
+       id="path158"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,547 -17.5,-7 17.5,-7"
+       id="path160"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g162"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,504 -127.375,0"
+       id="path164"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,511 -17.5,-7 17.5,-7"
+       id="path166"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g168"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,468 -127.375,0"
+       id="path170"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,475 -17.5,-7 17.5,-7"
+       id="path172"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g174"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,432 -127.375,0"
+       id="path176"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,439 -17.5,-7 17.5,-7"
+       id="path178"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g180"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,396 -127.375,0"
+       id="path182"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,403 -17.5,-7 17.5,-7"
+       id="path184"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g186"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,360 -127.375,0"
+       id="path188"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,367 -17.5,-7 17.5,-7"
+       id="path190"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g192"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,324 -127.375,0"
+       id="path194"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,331 -17.5,-7 17.5,-7"
+       id="path196"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g198"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,288 -127.375,0"
+       id="path200"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,295 -17.5,-7 17.5,-7"
+       id="path202"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g204"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,252 -127.375,0"
+       id="path206"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,259 -17.5,-7 17.5,-7"
+       id="path208"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g210"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,216 -127.375,0"
+       id="path212"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,223 -17.5,-7 17.5,-7"
+       id="path214"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g216"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 404,180 -99.375,0"
+       id="path218"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,187 -17.5,-7 17.5,-7"
+       id="path220"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g222"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,180 -127.375,0"
+       id="path224"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,187 -17.5,-7 17.5,-7"
+       id="path226"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g228"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,144 -127.375,0"
+       id="path230"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,151 -17.5,-7 17.5,-7"
+       id="path232"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text234"
+     x="256.90625"
+     y="531.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan236">Patch Email (Patchwork)</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text238"
+     x="256.90625"
+     y="495.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan240">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text242"
+     x="256.90625"
+     y="459.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan244">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text246"
+     x="256.90625"
+     y="423.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan248">Patch Email (Patchwork)</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text250"
+     x="256.90625"
+     y="387.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan252">Patch Email (Patchwork)</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text254"
+     x="256.90625"
+     y="351.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan256">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text258"
+     x="256.90625"
+     y="315.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan260">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text262"
+     x="256.90625"
+     y="279.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan264">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text266"
+     x="256.90625"
+     y="243.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan268">Patch Email (Patchwork)</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text270"
+     x="256.90625"
+     y="207.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan272">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text274"
+     x="256.90625"
+     y="171.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan276">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text278"
+     x="256.90625"
+     y="135.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan280">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text282"
+     x="256.90625"
+     y="603.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan284">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text286"
+     x="256.90625"
+     y="567.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan288">Github Pull Request</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text290"
+     x="256.90625"
+     y="567.21875"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"><tspan
+       id="tspan292">Github Pull Request</tspan></text>
+  <g
+     id="g294"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,612 -127.72,0"
+       id="path296"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.155,619 -17.5,-7 17.5,-7"
+       id="path298"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <g
+     id="g300"
+     transform="translate(-67.09375,-3.7812531)">
+    <path
+       d="m 432,576 -127.375,0"
+       id="path302"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#666666;stroke-width:4" />
+    <path
+       d="m 305.5,583 -17.5,-7 17.5,-7"
+       id="path304"
+       inkscape:connector-curvature="0"
+       style="fill:#666666" />
+  </g>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text306"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.90625"
+     y="577.21875"><tspan
+       id="tspan308">Version 1.</tspan><tspan
+       id="tspan310">0.a2</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text312"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.90625"
+     y="541.21875"><tspan
+       id="tspan314">Version 1.</tspan><tspan
+       id="tspan316">0.b1</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text318"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.90625"
+     y="505.21875"><tspan
+       id="tspan320">Version 1.</tspan><tspan
+       id="tspan322">0.0</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text324"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.679649"
+     y="288.97876"><tspan
+       id="tspan326">Version 1.1.0</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text328"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="51.90625"
+     y="252.97874"><tspan
+       id="tspan330">Version 1.1.1</tspan></text>
+  <text
+     font-size="12"
+     xml:space="preserve"
+     id="text332"
+     style="font-size:12px;font-family:Helvetica;fill:#000100"
+     x="52.679649"
+     y="216.97874"><tspan
+       id="tspan334">Version 1.</tspan><tspan
+       id="tspan336">1.2</tspan></text>
+  <path
+     d="m 212.90625,608.21875 -72,-36"
+     id="path338"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,572.21875 -72,-36"
+     id="path340"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,536.21875 -72,-36"
+     id="path342"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,320.21875 -72,-36"
+     id="path344"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,284.21875 -72,-36"
+     id="path346"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 212.90625,248.21875 -72,-36"
+     id="path348"
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#ff0000;stroke-width:8" />
+  <path
+     d="m 148.90625,571.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path350"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,535.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path352"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,499.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path354"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,284.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path356"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,248.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path358"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 148.90625,212.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path360"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,572.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path362"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,536.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path364"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,320.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path366"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,248.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path368"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+  <path
+     d="m 220.90625,284.21875 c 0,4.418 -3.582,8 -8,8 -4.418,0 -8,-3.582 -8,-8 0,-4.418 3.582,-8 8,-8 4.418,0 8,3.582 8,8 z"
+     id="path370"
+     inkscape:connector-curvature="0"
+     style="fill:#fffffe;stroke:#000100" />
+</svg>
index 9ffcbc618d95ca46f485619c7183fa26df1f9161..542c28993584ec4272ad58f14863cd08eac74288 100644 (file)
@@ -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
index 1683de46ca39598dc58ad70e407ba53158289532..2d68a31a5056be2dbfc57b5ce2458765b05821d2 100644 (file)
@@ -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
index dfe02e1b5da4bd2b382b5b2536f33431f3bbe8ed..706baa25f7d18e138601e6098f9b54b46da5ba96 100644 (file)
@@ -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,
index c5e4f7e324b385501af34de2f0fedab16723e0c0..09b662ae7c8e72152d5934615a186b61b6d79b57 100644 (file)
@@ -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
index 7f94782bea9e2fdd64570b6e9e80f07e8118b9cf..02d9d8083deadbd980a5f4f11ca9d7153b8528a0 100644 (file)
@@ -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
index 1b86551ca527d6833d2dd1f68b67f922b0dfcba2..6bad777711888100c3d19256e36b462d6afa742a 100644 (file)
@@ -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
index 370ada3f8a2442d2b67ac25868b60c9291d8c7b0..7ecf3d95c39162b7332c24df8dc8580436dbcafd 100644 (file)
@@ -2,7 +2,7 @@
 @chapter Overview
 @cindex Overview
 
-  @uref{http://www.freerangerouting.org,,Frr} is a routing software package that
+  @uref{http://www.frrouting.org,,Frr} is a routing software package that
 provides TCP/IP based routing services with routing protocols support such
 as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported
 RFCs}). Frr also supports special BGP Route Reflector and Route Server
@@ -275,12 +275,12 @@ November 1995.}
 
 The official Frr web-site is located at:
 
-@uref{http://www.freerangerouting.org/}
+@uref{http://www.frrouting.org/}
 
 and contains further information, as well as links to additional
 resources. 
 
-@uref{http://www.freerangerouting.org/,Frr} is a fork of Quagga, whose
+@uref{http://www.frrouting.org/,Frr} is a fork of Quagga, whose
 web-site is located at:
 
 @uref{http://www.quagga.net/}.
@@ -298,7 +298,7 @@ comments or suggestions to Frr, please subscribe to:
 
 @uref{http://lists.nox.tf/listinfo/frr-users}.
 
-The @uref{http://www.freerangerouting.org/,,Frr} site has further information on
+The @uref{http://www.frrouting.org/,,Frr} site has further information on
 the available mailing lists, see:
 
        @uref{http://lists.nox.tf/lists.php}
@@ -315,7 +315,7 @@ the available mailing lists, see:
 
 If you think you have found a bug, please send a bug report to:
 
-@uref{http://github.com/freerangerouting/frr/issues}
+@uref{http://github.com/frrouting/frr/issues}
 
 When you send a bug report, please be careful about the points below.
 
@@ -334,4 +334,4 @@ arguments to the configure script please note that too.
 
   Bug reports are very important for us to improve the quality of Frr.
 Frr is still in the development stage, but please don't hesitate to
-send a bug report to @uref{http://github.com/freerangerouting/frr/issues}.
+send a bug report to @uref{http://github.com/frrouting/frr/issues}.
index 60b844b1e7db0c6444fca1502f5b460857cafbc3..3fb060e5647531e5007b8b52396ea9abe59c543a 100644 (file)
@@ -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
index 6db5ac3649b1426f3475a1ff37da78d70d809afd..a84668e6dd9167b8f629049b5b456d0c1160efa4 100644 (file)
@@ -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
index 4c5f2bb1149bd23ccaff5e6ee5404202ff015976..98039219a70db8836b8adb2f50f57dd75170f351 100644 (file)
@@ -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
index c2c889de76546244b7c3aa4921a8120615244f8e..d9656941d0b335e0276d8c23eddb0963f8fb8773 100644 (file)
@@ -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::
index 813f87abd34a0c509aeaf09854f773752d9a868f..82098e1b0d6419f9f480948b51704f07b5b520c7 100644 (file)
@@ -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
index 4599a85635604ebb1f4d7f4dfdd9f29aef17fc24..f5b8bd4d80893e60ec2840926302ab00c0c36da2 100644 (file)
@@ -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
index 6ec7771ec2fd156bae48631292370dadbc3e1cc8..dd07a9c6f5758758178ce6a4c43167f7d7c0f96c 100644 (file)
@@ -279,6 +279,10 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
       bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
                             MSG_DONTWAIT, (struct sockaddr *) &s_addr,
                             (socklen_t *) &addr_len);
+
+      if (bytesread < 0)
+        zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
+
       return ISIS_WARNING;
     }
   /*
@@ -322,10 +326,10 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
   addr_len = sizeof (s_addr);
 
   /* we can read directly to the stream */
-  bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
-                               circuit->interface->mtu, 0,
-                               (struct sockaddr *) &s_addr, 
-                               (socklen_t *) &addr_len);
+  stream_recvfrom (circuit->rcv_stream, circuit->fd,
+                   circuit->interface->mtu, 0,
+                   (struct sockaddr *) &s_addr,
+                   (socklen_t *) &addr_len);
 
   if (s_addr.sll_pkttype == PACKET_OUTGOING)
     {
index db46078f20c5ce06ed6c9d9f3752a3509ec56f83..554fa563ad774c201250d765f06a88b39e1f809b 100644 (file)
@@ -68,7 +68,6 @@ remove_excess_adjs (struct list *adjs)
       if (candidate->sys_type < adj->sys_type)
        {
          excess = node;
-         candidate = adj;
          continue;
        }
       if (candidate->sys_type > adj->sys_type)
@@ -78,7 +77,6 @@ remove_excess_adjs (struct list *adjs)
       if (comp > 0)
        {
          excess = node;
-         candidate = adj;
          continue;
        }
       if (comp < 0)
@@ -87,7 +85,6 @@ remove_excess_adjs (struct list *adjs)
       if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
        {
          excess = node;
-         candidate = adj;
          continue;
        }
 
@@ -98,7 +95,6 @@ remove_excess_adjs (struct list *adjs)
       if (comp > 0)
        {
          excess = node;
-         candidate = adj;
          continue;
        }
     }
index 830ccb37c6d2cf8a673628fbbd56f3697b6417a4..b04d0db3cadef0df068dbab5cf982c79520edef8 100644 (file)
@@ -1323,7 +1323,7 @@ DEFUN (show_isis_mpls_te_interface,
   /* Interface name is specified. */
   else
     {
-      if ((ifp = if_lookup_by_name (argv[idx_interface]->arg)) == NULL)
+      if ((ifp = if_lookup_by_name (argv[idx_interface]->arg, VRF_DEFAULT)) == NULL)
         vty_out (vty, "No such interface name%s", VTY_NEWLINE);
       else
         show_mpls_te_sub (vty, ifp);
index 2863d2f67885cbd0c7bd81a3289292d834204bad..f226c4a1f3cdea0679c3235c24dae8f7fc7583f6 100644 (file)
@@ -1576,7 +1576,7 @@ DEFUN (show_database,
 /* 
  * 'router isis' command 
  */
-DEFUN (router_isis,
+DEFUN_NOSH (router_isis,
        router_isis_cmd,
        "router isis WORD",
        ROUTER_STR
index 42e54138aaa453a3dac83f0faa886a9f80790ebe..19f819ae365d00fc3559a7d6d192cfca91da2afe 100644 (file)
@@ -24,7 +24,9 @@ noinst_HEADERS = \
        control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h
 
 ldp_vty_cmds.c: $(srcdir)/ldp_vty.xml $(srcdir)/../tools/xml2cli.pl
-       @PERL@ $(srcdir)/../tools/xml2cli.pl $(srcdir)/ldp_vty.xml > $@
+       @PERL@ $(srcdir)/../tools/xml2cli.pl $(srcdir)/ldp_vty.xml | \
+               sed -e 's%DEFUN \((ldp_\(interface_\|mpls_ldp\|address_family\|l2vpn_word\|member_pseudo\)\)%DEFUN_NOSH \1%' \
+               > $@
 
 ldpd_SOURCES = ldpd.c
 ldpd_LDADD = libldp.a ../lib/libfrr.la @LIBCAP@
index ad23ca690bf5eacdee4249932063d0ebd719f29e..584240de8495514150703b1029a9f3e21810307a 100644 (file)
@@ -104,6 +104,18 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
                }
 
                evbuf_enqueue(&nbr->tcp->wbuf, buf);
+
+               /* no errors - update per neighbor message counters */
+               switch (msg_type) {
+               case MSG_TYPE_ADDR:
+                       nbr->stats.addr_sent++;
+                       break;
+               case MSG_TYPE_ADDRWITHDRAW:
+                       nbr->stats.addrwdraw_sent++;
+                       break;
+               default:
+                       break;
+               }
        }
 
        nbr_fsm(nbr, NBR_EVT_PDU_SENT);
index 2e7b43296a2d4d1e9f5edc25678b14bd3e1c42af..8659202ee4e5c14bf7fbaec47fb7dc2b575c86f1 100644 (file)
@@ -41,6 +41,16 @@ RB_GENERATE(tnbr_head, tnbr, entry, tnbr_compare)
 static __inline int
 adj_compare(struct adj *a, struct adj *b)
 {
+       if (adj_get_af(a) < adj_get_af(b))
+               return (-1);
+       if (adj_get_af(a) > adj_get_af(b))
+               return (1);
+
+       if (ntohl(a->lsr_id.s_addr) < ntohl(b->lsr_id.s_addr))
+               return (-1);
+       if (ntohl(a->lsr_id.s_addr) > ntohl(b->lsr_id.s_addr))
+               return (1);
+
        if (a->source.type < b->source.type)
                return (-1);
        if (a->source.type > b->source.type)
@@ -54,21 +64,13 @@ adj_compare(struct adj *a, struct adj *b)
                if (strcmp(a->source.link.ia->iface->name,
                    b->source.link.ia->iface->name) > 0)
                        return (1);
-               if (a->source.link.ia->af < b->source.link.ia->af)
-                       return (-1);
-               if (a->source.link.ia->af > b->source.link.ia->af)
-                       return (1);
                return (ldp_addrcmp(a->source.link.ia->af,
                    &a->source.link.src_addr, &b->source.link.src_addr));
        case HELLO_TARGETED:
-               if (a->source.target->af < b->source.target->af)
-                       return (-1);
-               if (a->source.target->af > b->source.target->af)
-                       return (1);
                return (ldp_addrcmp(a->source.target->af,
                    &a->source.target->addr, &b->source.target->addr));
        default:
-               fatalx("adj_get_af: unknown hello type");
+               fatalx("adj_compare: unknown hello type");
        }
 
        return (0);
@@ -150,9 +152,10 @@ adj_del(struct adj *adj, uint32_t notif_status)
 }
 
 struct adj *
-adj_find(struct hello_source *source)
+adj_find(struct in_addr lsr_id, struct hello_source *source)
 {
        struct adj       adj;
+       adj.lsr_id = lsr_id;
        adj.source = *source;
        return (RB_FIND(global_adj_head, &global.adj_tree, &adj));
 }
@@ -372,13 +375,17 @@ adj_to_ctl(struct adj *adj)
        case HELLO_LINK:
                memcpy(actl.ifname, adj->source.link.ia->iface->name,
                    sizeof(actl.ifname));
+               actl.src_addr = adj->source.link.src_addr;
                break;
        case HELLO_TARGETED:
                actl.src_addr = adj->source.target->addr;
                break;
        }
        actl.holdtime = adj->holdtime;
+       actl.holdtime_remaining =
+           thread_timer_remain_second(adj->inactivity_timer);
        actl.trans_addr = adj->trans_addr;
+       actl.ds_tlv = adj->ds_tlv;
 
        return (&actl);
 }
index 0bfe0abc9de56bba7c67adeb2e879e40d63e03d6..5c530e1b701163736f876a63206e7deccfb1f9dd 100644 (file)
@@ -242,6 +242,9 @@ control_dispatch_imsg(struct thread *thread)
                case IMSG_CTL_SHOW_DISCOVERY:
                        ldpe_adj_ctl(c);
                        break;
+               case IMSG_CTL_SHOW_DISCOVERY_DTL:
+                       ldpe_adj_detail_ctl(c);
+                       break;
                case IMSG_CTL_SHOW_LIB:
                case IMSG_CTL_SHOW_L2VPN_PW:
                case IMSG_CTL_SHOW_L2VPN_BINDING:
index e7935899b71fe8e96763188f516ff0056ca2ff71..dd67f68f70bd8f9b4094444e9301e0481dffa7a8 100644 (file)
@@ -291,7 +291,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                source.link.src_addr = *src;
        }
 
-       adj = adj_find(&source);
+       adj = adj_find(lsr_id, &source);
        nbr = nbr_find_ldpid(lsr_id.s_addr);
 
        /* check dual-stack tlv */
@@ -373,6 +373,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                        RB_INSERT(nbr_adj_head, &nbr->adj_tree, adj);
                }
        }
+       adj->ds_tlv = ds_tlv;
 
        /*
         * If the hello adjacency's address-family doesn't match the local
index bc3a69edc7c032b57d7004be409ae769c9731a5e..8b2abe85e596f7f91926e56672fdceb97a71d45b 100644 (file)
@@ -261,6 +261,7 @@ send_capability(struct nbr *nbr, uint16_t capability, int enable)
 
        evbuf_enqueue(&nbr->tcp->wbuf, buf);
        nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+       nbr->stats.capability_sent++;
 }
 
 int
index 8fea91b878579ed9fb67b7b5c7ac2e2723dce4a1..b7f473d3960762d05632e66b9cb08a01dfb94f91 100644 (file)
@@ -49,37 +49,48 @@ iface_compare(struct iface *a, struct iface *b)
 }
 
 struct iface *
-if_new(struct kif *kif)
+if_new(const char *name)
 {
        struct iface            *iface;
 
        if ((iface = calloc(1, sizeof(*iface))) == NULL)
                fatal("if_new: calloc");
 
-       strlcpy(iface->name, kif->ifname, sizeof(iface->name));
-       LIST_INIT(&iface->addr_list);
-       if (kif->ifindex)
-               if_update_info(iface, kif);
+       strlcpy(iface->name, name, sizeof(iface->name));
 
        /* ipv4 */
        iface->ipv4.af = AF_INET;
        iface->ipv4.iface = iface;
        iface->ipv4.enabled = 0;
-       iface->ipv4.state = IF_STA_DOWN;
-       RB_INIT(&iface->ipv4.adj_tree);
 
        /* ipv6 */
        iface->ipv6.af = AF_INET6;
        iface->ipv6.iface = iface;
        iface->ipv6.enabled = 0;
-       iface->ipv6.state = IF_STA_DOWN;
-       RB_INIT(&iface->ipv6.adj_tree);
 
        return (iface);
 }
 
 void
-if_exit(struct iface *iface)
+ldpe_if_init(struct iface *iface)
+{
+       log_debug("%s: interface %s", __func__, iface->name);
+
+       LIST_INIT(&iface->addr_list);
+
+       /* ipv4 */
+       iface->ipv4.iface = iface;
+       iface->ipv4.state = IF_STA_DOWN;
+       RB_INIT(&iface->ipv4.adj_tree);
+
+       /* ipv6 */
+       iface->ipv6.iface = iface;
+       iface->ipv6.state = IF_STA_DOWN;
+       RB_INIT(&iface->ipv6.adj_tree);
+}
+
+void
+ldpe_if_exit(struct iface *iface)
 {
        struct if_addr          *if_addr;
 
@@ -206,7 +217,7 @@ if_addr_add(struct kaddr *ka)
                if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
                        if_addr = if_addr_new(ka);
                        LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
-                       if_update(iface, if_addr->af);
+                       ldp_if_update(iface, if_addr->af);
                }
        }
 }
@@ -227,7 +238,7 @@ if_addr_del(struct kaddr *ka)
                if_addr = if_addr_lookup(&iface->addr_list, ka);
                if (if_addr) {
                        LIST_REMOVE(if_addr, entry);
-                       if_update(iface, if_addr->af);
+                       ldp_if_update(iface, if_addr->af);
                        free(if_addr);
                }
        }
@@ -368,7 +379,7 @@ if_update_af(struct iface_af *ia, int link_ok)
 }
 
 void
-if_update(struct iface *iface, int af)
+ldp_if_update(struct iface *iface, int af)
 {
        int                      link_ok;
 
@@ -386,7 +397,7 @@ if_update_all(int af)
        struct iface            *iface;
 
        RB_FOREACH(iface, iface_head, &leconf->iface_tree)
-               if_update(iface, af);
+               ldp_if_update(iface, af);
 }
 
 uint16_t
index f9a7d850fd2cbf1a7a6f2ade78b5d6e2e6c6d5c1..ba5f2233162da9637c3def43eeee0a09beb679df 100644 (file)
@@ -40,6 +40,7 @@ send_keepalive(struct nbr *nbr)
        debug_kalive_send("keepalive: lsr-id %s", inet_ntoa(nbr->id));
 
        evbuf_enqueue(&nbr->tcp->wbuf, buf);
+       nbr->stats.kalive_sent++;
 }
 
 int
index 3f4e21e68556857b4aca49d0040d6840bc78baaa..92d865210a32c5e330c7bc8cb2d90521f3af448e 100644 (file)
@@ -117,7 +117,7 @@ l2vpn_if_compare(struct l2vpn_if *a, struct l2vpn_if *b)
 }
 
 struct l2vpn_if *
-l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
+l2vpn_if_new(struct l2vpn *l2vpn, const char *ifname)
 {
        struct l2vpn_if *lif;
 
@@ -125,33 +125,27 @@ l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
                fatal("l2vpn_if_new: calloc");
 
        lif->l2vpn = l2vpn;
-       strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
-       lif->ifindex = kif->ifindex;
-       lif->flags = kif->flags;
+       strlcpy(lif->ifname, ifname, sizeof(lif->ifname));
 
        return (lif);
 }
 
 struct l2vpn_if *
-l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
-{
-       struct l2vpn_if *lif;
-
-       RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
-               if (lif->ifindex == ifindex)
-                       return (lif);
-
-       return (NULL);
-}
-
-struct l2vpn_if *
-l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
+l2vpn_if_find(struct l2vpn *l2vpn, const char *ifname)
 {
        struct l2vpn_if  lif;
        strlcpy(lif.ifname, ifname, sizeof(lif.ifname));
        return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
 }
 
+void
+l2vpn_if_update_info(struct l2vpn_if *lif, struct kif *kif)
+{
+       lif->ifindex = kif->ifindex;
+       lif->flags = kif->flags;
+       memcpy(lif->mac, kif->mac, sizeof(lif->mac));
+}
+
 void
 l2vpn_if_update(struct l2vpn_if *lif)
 {
@@ -186,7 +180,7 @@ l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b)
 }
 
 struct l2vpn_pw *
-l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
+l2vpn_pw_new(struct l2vpn *l2vpn, const char *ifname)
 {
        struct l2vpn_pw *pw;
 
@@ -194,40 +188,48 @@ l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
                fatal("l2vpn_pw_new: calloc");
 
        pw->l2vpn = l2vpn;
-       strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname));
-       pw->ifindex = kif->ifindex;
+       strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
 
        return (pw);
 }
 
 struct l2vpn_pw *
-l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
+l2vpn_pw_find(struct l2vpn *l2vpn, const char *ifname)
 {
        struct l2vpn_pw *pw;
+       struct l2vpn_pw  s;
 
-       RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
-               if (pw->ifindex == ifindex)
-                       return (pw);
-       RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree)
-               if (pw->ifindex == ifindex)
-                       return (pw);
+       strlcpy(s.ifname, ifname, sizeof(s.ifname));
+       pw = RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s);
+       if (pw)
+               return (pw);
+       return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
+}
 
-       return (NULL);
+struct l2vpn_pw *
+l2vpn_pw_find_active(struct l2vpn *l2vpn, const char *ifname)
+{
+       struct l2vpn_pw  s;
+
+       strlcpy(s.ifname, ifname, sizeof(s.ifname));
+       return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s));
 }
 
 struct l2vpn_pw *
-l2vpn_pw_find_name(struct l2vpn *l2vpn, const char *ifname)
+l2vpn_pw_find_inactive(struct l2vpn *l2vpn, const char *ifname)
 {
-       struct l2vpn_pw *pw;
        struct l2vpn_pw  s;
 
        strlcpy(s.ifname, ifname, sizeof(s.ifname));
-       pw = RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s);
-       if (pw)
-               return (pw);
        return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
 }
 
+void
+l2vpn_pw_update_info(struct l2vpn_pw *pw, struct kif *kif)
+{
+       pw->ifindex = kif->ifindex;
+}
+
 void
 l2vpn_pw_init(struct l2vpn_pw *pw)
 {
@@ -282,9 +284,6 @@ l2vpn_pw_reset(struct l2vpn_pw *pw)
 int
 l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
 {
-       struct fec               fec;
-       struct fec_node         *fn;
-
        /* check for a remote label */
        if (fnh->remote_label == NO_LABEL)
                return (0);
@@ -298,34 +297,6 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
            pw->remote_status != PW_FORWARDING)
                return (0);
 
-       /* check for a working lsp to the nexthop */
-       memset(&fec, 0, sizeof(fec));
-       switch (pw->af) {
-       case AF_INET:
-               fec.type = FEC_TYPE_IPV4;
-               fec.u.ipv4.prefix = pw->addr.v4;
-               fec.u.ipv4.prefixlen = 32;
-               break;
-       case AF_INET6:
-               fec.type = FEC_TYPE_IPV6;
-               fec.u.ipv6.prefix = pw->addr.v6;
-               fec.u.ipv6.prefixlen = 128;
-               break;
-       default:
-               fatalx("l2vpn_pw_ok: unknown af");
-       }
-
-       fn = (struct fec_node *)fec_find(&ft, &fec);
-       if (fn == NULL || fn->local_label == NO_LABEL)
-               return (0);
-       /*
-        * Need to ensure that there's a label binding for all nexthops.
-        * Otherwise, ECMP for this route could render the pseudowire unusable.
-        */
-       LIST_FOREACH(fnh, &fn->nexthops, entry)
-               if (fnh->remote_label == NO_LABEL)
-                       return (0);
-
        return (1);
 }
 
@@ -503,37 +474,6 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
        }
 }
 
-void
-l2vpn_sync_pws(int af, union ldpd_addr *addr)
-{
-       struct l2vpn            *l2vpn;
-       struct l2vpn_pw         *pw;
-       struct fec               fec;
-       struct fec_node         *fn;
-       struct fec_nh           *fnh;
-
-       RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
-                       if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
-                               continue;
-
-                       l2vpn_pw_fec(pw, &fec);
-                       fn = (struct fec_node *)fec_find(&ft, &fec);
-                       if (fn == NULL)
-                               continue;
-                       fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)
-                           &pw->lsr_id, 0, 0);
-                       if (fnh == NULL)
-                               continue;
-
-                       if (l2vpn_pw_ok(pw, fnh))
-                               lde_send_change_klabel(fn, fnh);
-                       else
-                               lde_send_delete_klabel(fn, fnh);
-               }
-       }
-}
-
 void
 l2vpn_pw_ctl(pid_t pid)
 {
index e8ce7fbdf534e34851905838951de5fda8344fd1..f53bc8333d7cbd81deb9a9919bff72b38926f4dd 100644 (file)
 
 #include "mpls.h"
 
-static void     enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
+static void     enqueue_pdu(struct nbr *, uint16_t, struct ibuf *, uint16_t);
 static int      gen_label_tlv(struct ibuf *, uint32_t);
 static int      gen_reqid_tlv(struct ibuf *, uint32_t);
 static void     log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
 
 static void
-enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
+enqueue_pdu(struct nbr *nbr, uint16_t type, struct ibuf *buf, uint16_t size)
 {
        struct ldp_hdr          *ldp_hdr;
 
@@ -81,7 +81,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
 
                /* maximum pdu length exceeded, we need a new ldp pdu */
                if (size + msg_size > nbr->max_pdu_len) {
-                       enqueue_pdu(nbr, buf, size);
+                       enqueue_pdu(nbr, type, buf, size);
                        first = 1;
                        continue;
                }
@@ -108,11 +108,32 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
 
                log_msg_mapping(1, type, nbr, &me->map);
 
+               /* no errors - update per neighbor message counters */
+               switch (type) {
+               case MSG_TYPE_LABELMAPPING:
+                       nbr->stats.labelmap_sent++;
+                       break;
+                       case MSG_TYPE_LABELREQUEST:
+                       nbr->stats.labelreq_sent++;
+                       break;
+               case MSG_TYPE_LABELWITHDRAW:
+                       nbr->stats.labelwdraw_sent++;
+                       break;
+               case MSG_TYPE_LABELRELEASE:
+                       nbr->stats.labelrel_sent++;
+                       break;
+               case MSG_TYPE_LABELABORTREQ:
+                       nbr->stats.labelabreq_sent++;
+                       break;
+               default:
+                       break;
+               }
+
                TAILQ_REMOVE(mh, me, entry);
                free(me);
        }
 
-       enqueue_pdu(nbr, buf, size);
+       enqueue_pdu(nbr, type, buf, size);
 
        nbr_fsm(nbr, NBR_EVT_PDU_SENT);
 }
index 08339c720ad7038f6de5f90602272d0f990e3b12..d8a2924b31c9fdd4ee60c6628b01182ac59df5c1 100644 (file)
 #include "privs.h"
 #include "sigevent.h"
 #include "mpls.h"
+#include <lib/linklist.h>
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
 
 static void             lde_shutdown(void);
 static int              lde_dispatch_imsg(struct thread *);
@@ -50,6 +54,11 @@ static void           lde_map_free(void *);
 static int              lde_address_add(struct lde_nbr *, struct lde_addr *);
 static int              lde_address_del(struct lde_nbr *, struct lde_addr *);
 static void             lde_address_list_free(struct lde_nbr *);
+static void             zclient_sync_init (u_short instance);
+static void             lde_label_list_init(void);
+static int              lde_get_label_chunk (void);
+static void             on_get_label_chunk_response(uint32_t start, uint32_t end);
+static uint32_t                 lde_get_next_label(void);
 
 RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare)
 RB_GENERATE(lde_map_head, lde_map, entry, lde_map_compare)
@@ -83,6 +92,10 @@ static struct zebra_privs_t lde_privs =
        .cap_num_i = 0
 };
 
+/* List of chunks of labels externally assigned by Zebra */
+struct list *label_chunk_list;
+struct listnode *current_label_chunk;
+
 /* SIGINT / SIGTERM handler. */
 static void
 sigint(void)
@@ -92,6 +105,10 @@ sigint(void)
 
 static struct quagga_signal_t lde_signals[] =
 {
+       {
+               .signal = SIGHUP,
+               /* ignore */
+       },
        {
                .signal = SIGINT,
                .handler = &sigint,
@@ -102,9 +119,38 @@ static struct quagga_signal_t lde_signals[] =
        },
 };
 
+static void
+lde_sleep (void)
+{
+       sleep(1);
+       if (lde_signals[0].caught || lde_signals[1].caught)
+               lde_shutdown();
+}
+struct zclient *zclient_sync = NULL;
+static void
+zclient_sync_init(u_short instance)
+{
+       /* Initialize special zclient for synchronous message exchanges. */
+       log_debug("Initializing synchronous zclient for label manager");
+       zclient_sync = zclient_new(master);
+       zclient_sync->sock = -1;
+       zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
+       zclient_sync->instance = instance;
+       while (zclient_socket_connect (zclient_sync) < 0) {
+               fprintf(stderr, "Error connecting synchronous zclient!\n");
+               lde_sleep();
+       }
+
+       /* Connect to label manager */
+       while (lm_label_manager_connect (zclient_sync) != 0) {
+               fprintf(stderr, "Error connecting to label manager!\n");
+               lde_sleep();
+       }
+}
+
 /* label decision engine */
 void
-lde(const char *user, const char *group)
+lde(const char *user, const char *group, u_short instance)
 {
        struct thread            thread;
        struct timeval           now;
@@ -124,7 +170,7 @@ lde(const char *user, const char *group)
        zprivs_init(&lde_privs);
 
 #ifdef HAVE_PLEDGE
-       if (pledge("stdio recvfd", NULL) == -1)
+       if (pledge("stdio recvfd unix", NULL) == -1)
                fatal("pledge");
 #endif
 
@@ -152,6 +198,10 @@ lde(const char *user, const char *group)
        gettimeofday(&now, NULL);
        global.uptime = now.tv_sec;
 
+       /* Init synchronous zclient and label list */
+       zclient_sync_init(instance);
+       lde_label_list_init();
+
        /* Fetch next active thread. */
        while (thread_fetch(master, &thread))
                thread_call(&thread);
@@ -389,13 +439,14 @@ static int
 lde_dispatch_parent(struct thread *thread)
 {
        static struct ldpd_conf *nconf;
-       struct iface            *niface;
+       struct iface            *iface, *niface;
        struct tnbr             *ntnbr;
        struct nbr_params       *nnbrp;
-       static struct l2vpn     *nl2vpn;
-       struct l2vpn_if         *nlif;
-       struct l2vpn_pw         *npw;
+       static struct l2vpn     *l2vpn, *nl2vpn;
+       struct l2vpn_if         *lif, *nlif;
+       struct l2vpn_pw         *pw, *npw;
        struct imsg              imsg;
+       struct kif              *kif;
        struct kroute           *kr;
        int                      fd = THREAD_FD(thread);
        struct imsgev           *iev = THREAD_ARG(thread);
@@ -418,6 +469,31 @@ lde_dispatch_parent(struct thread *thread)
                        break;
 
                switch (imsg.hdr.type) {
+               case IMSG_IFSTATUS:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct kif))
+                               fatalx("IFSTATUS imsg with wrong len");
+                       kif = imsg.data;
+
+                       iface = if_lookup_name(ldeconf, kif->ifname);
+                       if (iface) {
+                               if_update_info(iface, kif);
+                               break;
+                       }
+
+                       RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
+                               lif = l2vpn_if_find(l2vpn, kif->ifname);
+                               if (lif) {
+                                       l2vpn_if_update_info(lif, kif);
+                                       break;
+                               }
+                               pw = l2vpn_pw_find(l2vpn, kif->ifname);
+                               if (pw) {
+                                       l2vpn_pw_update_info(pw, kif);
+                                       break;
+                               }
+                       }
+                       break;
                case IMSG_NETWORK_ADD:
                case IMSG_NETWORK_UPDATE:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -490,12 +566,6 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(niface, imsg.data, sizeof(struct iface));
 
-                       LIST_INIT(&niface->addr_list);
-                       RB_INIT(&niface->ipv4.adj_tree);
-                       RB_INIT(&niface->ipv6.adj_tree);
-                       niface->ipv4.iface = niface;
-                       niface->ipv6.iface = niface;
-
                        RB_INSERT(iface_head, &nconf->iface_tree, niface);
                        break;
                case IMSG_RECONF_TNBR:
@@ -528,7 +598,6 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
 
-                       nlif->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_if_head, &nl2vpn->if_tree, nlif);
                        break;
                case IMSG_RECONF_L2VPN_PW:
@@ -536,7 +605,6 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
 
-                       npw->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_tree, npw);
                        break;
                case IMSG_RECONF_L2VPN_IPW:
@@ -544,11 +612,11 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
 
-                       npw->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_inactive_tree, npw);
                        break;
                case IMSG_RECONF_END:
                        merge_config(ldeconf, nconf);
+                       ldp_clear_config(nconf);
                        nconf = NULL;
                        break;
                case IMSG_DEBUG_UPDATE:
@@ -587,7 +655,6 @@ lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen)
 uint32_t
 lde_update_label(struct fec_node *fn)
 {
-       static uint32_t  label = MPLS_LABEL_RESERVED_MAX;
        struct fec_nh   *fnh;
        int              connected = 0;
 
@@ -652,12 +719,7 @@ lde_update_label(struct fec_node *fn)
            fn->local_label > MPLS_LABEL_RESERVED_MAX)
                return (fn->local_label);
 
-       /*
-        * TODO: request label to zebra or define a range of labels for ldpd.
-        */
-
-       label++;
-       return (label);
+       return lde_get_next_label ();
 }
 
 void
@@ -681,10 +743,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
 
                lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
                    sizeof(kr));
-
-               if (fn->fec.u.ipv4.prefixlen == 32)
-                       l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
-                           &fn->fec.u.ipv4.prefix);
                break;
        case FEC_TYPE_IPV6:
                memset(&kr, 0, sizeof(kr));
@@ -699,10 +757,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
 
                lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
                    sizeof(kr));
-
-               if (fn->fec.u.ipv6.prefixlen == 128)
-                       l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
-                           &fn->fec.u.ipv6.prefix);
                break;
        case FEC_TYPE_PWID:
                if (fn->local_label == NO_LABEL ||
@@ -748,10 +802,6 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
 
                lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
                    sizeof(kr));
-
-               if (fn->fec.u.ipv4.prefixlen == 32)
-                       l2vpn_sync_pws(AF_INET, (union ldpd_addr *)
-                           &fn->fec.u.ipv4.prefix);
                break;
        case FEC_TYPE_IPV6:
                memset(&kr, 0, sizeof(kr));
@@ -766,10 +816,6 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
 
                lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
                    sizeof(kr));
-
-               if (fn->fec.u.ipv6.prefixlen == 128)
-                       l2vpn_sync_pws(AF_INET6, (union ldpd_addr *)
-                           &fn->fec.u.ipv6.prefix);
                break;
        case FEC_TYPE_PWID:
                pw = (struct l2vpn_pw *) fn->data;
@@ -1533,3 +1579,102 @@ lde_address_list_free(struct lde_nbr *ln)
                free(lde_addr);
        }
 }
+
+static void
+lde_del_label_chunk(void *val)
+{
+       free(val);
+}
+static int
+lde_get_label_chunk(void)
+{
+       int ret;
+       uint32_t start, end;
+
+       log_debug("Getting label chunk");
+       ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
+       if (ret < 0)
+       {
+               log_warnx("Error getting label chunk!");
+               close(zclient_sync->sock);
+               zclient_sync->sock = -1;
+               return -1;
+       }
+
+       on_get_label_chunk_response(start, end);
+
+       return 0;
+}
+static void
+lde_label_list_init(void)
+{
+       label_chunk_list = list_new();
+       label_chunk_list->del = lde_del_label_chunk;
+
+       /* get first chunk */
+       while (lde_get_label_chunk () != 0) {
+               fprintf(stderr, "Error getting first label chunk!\n");
+               lde_sleep();
+       }
+}
+
+static void
+on_get_label_chunk_response(uint32_t start, uint32_t end)
+{
+       struct label_chunk *new_label_chunk;
+
+       log_debug("Label Chunk assign: %u - %u", start, end);
+
+       new_label_chunk = calloc(1, sizeof(struct label_chunk));
+       if (!new_label_chunk) {
+               log_warn("Error trying to allocate label chunk %u - %u", start, end);
+               return;
+       }
+
+       new_label_chunk->start = start;
+       new_label_chunk->end = end;
+       new_label_chunk->used_mask = 0;
+
+       listnode_add(label_chunk_list, (void *)new_label_chunk);
+
+       /* let's update current if needed */
+       if (!current_label_chunk)
+               current_label_chunk = listtail(label_chunk_list);
+}
+
+static uint32_t
+lde_get_next_label(void)
+{
+       struct label_chunk *label_chunk;
+       uint32_t i, pos, size;
+       uint32_t label = NO_LABEL;
+
+       while (current_label_chunk) {
+               label_chunk = listgetdata(current_label_chunk);
+               if (!label_chunk)
+                       goto end;
+
+               /* try to get next free label in currently used label chunk */
+               size = label_chunk->end - label_chunk->start + 1;
+               for (i = 0, pos = 1; i < size; i++, pos <<= 1) {
+                       if (!(pos & label_chunk->used_mask)) {
+                               label_chunk->used_mask |= pos;
+                               label = label_chunk->start + i;
+                               goto end;
+                       }
+               }
+               current_label_chunk = listnextnode(current_label_chunk);
+       }
+
+end:
+       /* we moved till the last chunk, or were not able to find a label,
+          so let's ask for another one */
+       if (!current_label_chunk || current_label_chunk == listtail(label_chunk_list)
+               || label == NO_LABEL) {
+               if (lde_get_label_chunk() != 0)
+                       log_warn("%s: Error getting label chunk!", __func__);
+
+       }
+
+       return label;
+}
index b5bcb42c8b561d98e44b5c66f36eedb865174688..57791cd1b0c64ea5a033e349dd188c97736ee65a 100644 (file)
@@ -124,6 +124,13 @@ struct fec_node {
        void                    *data;          /* fec specific data */
 };
 
+#define CHUNK_SIZE             64
+struct label_chunk {
+       uint32_t                 start;
+       uint32_t                 end;
+       uint64_t                 used_mask;
+};
+
 #define LDE_GC_INTERVAL 300
 
 extern struct ldpd_conf        *ldeconf;
@@ -132,7 +139,7 @@ extern struct nbr_tree       lde_nbrs;
 extern struct thread   *gc_timer;
 
 /* lde.c */
-void            lde(const char *, const char *);
+void            lde(const char *, const char *, u_short instance);
 int             lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
 int             lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
 int             lde_acl_check(char *, int, union ldpd_addr *, uint8_t);
@@ -205,13 +212,15 @@ struct l2vpn      *l2vpn_find(struct ldpd_conf *, const char *);
 void            l2vpn_del(struct l2vpn *);
 void            l2vpn_init(struct l2vpn *);
 void            l2vpn_exit(struct l2vpn *);
-struct l2vpn_if        *l2vpn_if_new(struct l2vpn *, struct kif *);
-struct l2vpn_if        *l2vpn_if_find(struct l2vpn *, unsigned int);
-struct l2vpn_if        *l2vpn_if_find_name(struct l2vpn *, const char *);
+struct l2vpn_if        *l2vpn_if_new(struct l2vpn *, const char *);
+struct l2vpn_if        *l2vpn_if_find(struct l2vpn *, const char *);
+void            l2vpn_if_update_info(struct l2vpn_if *, struct kif *);
 void            l2vpn_if_update(struct l2vpn_if *);
-struct l2vpn_pw        *l2vpn_pw_new(struct l2vpn *, struct kif *);
-struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
-struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
+struct l2vpn_pw        *l2vpn_pw_new(struct l2vpn *, const char *);
+struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, const char *);
+struct l2vpn_pw        *l2vpn_pw_find_active(struct l2vpn *, const char *);
+struct l2vpn_pw        *l2vpn_pw_find_inactive(struct l2vpn *, const char *);
+void            l2vpn_pw_update_info(struct l2vpn_pw *, struct kif *);
 void            l2vpn_pw_init(struct l2vpn_pw *);
 void            l2vpn_pw_exit(struct l2vpn_pw *);
 void            l2vpn_pw_reset(struct l2vpn_pw *);
@@ -224,7 +233,6 @@ void                 l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
 void            l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
 void            l2vpn_recv_pw_status_wcard(struct lde_nbr *,
                    struct notify_msg *);
-void            l2vpn_sync_pws(int, union ldpd_addr *);
 void            l2vpn_pw_ctl(pid_t);
 void            l2vpn_binding_ctl(pid_t);
 
index 4444a1e1ac38e2fcafd20d553aa41305455764e1..db2682a173698a65c357ee0d6e37779e9965cdd3 100644 (file)
@@ -162,7 +162,7 @@ rt_dump(pid_t pid)
                    RB_EMPTY(&fn->downstream))
                        continue;
 
-               rtctl.first = 1;
+               memset(&rtctl, 0, sizeof(rtctl));
                switch (fn->fec.type) {
                case FEC_TYPE_IPV4:
                        rtctl.af = AF_INET;
@@ -179,23 +179,30 @@ rt_dump(pid_t pid)
                }
 
                rtctl.local_label = fn->local_label;
-               RB_FOREACH(me, lde_map_head, &fn->downstream) {
-                       rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop);
-                       rtctl.nexthop = me->nexthop->id;
-                       rtctl.remote_label = me->map.label;
-
-                       lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
-                           &rtctl, sizeof(rtctl));
-                       rtctl.first = 0;
-               }
                if (RB_EMPTY(&fn->downstream)) {
                        rtctl.in_use = 0;
                        rtctl.nexthop.s_addr = INADDR_ANY;
                        rtctl.remote_label = NO_LABEL;
+                       rtctl.no_downstream = 1;
+               }
+               lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_BEGIN, 0, pid, &rtctl,
+                   sizeof(rtctl));
 
-                       lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
+               RB_FOREACH(me, lde_map_head, &fn->upstream) {
+                       rtctl.nexthop = me->nexthop->id;
+                       lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_SENT, 0, pid,
+                           &rtctl, sizeof(rtctl));
+               }
+
+               RB_FOREACH(me, lde_map_head, &fn->downstream) {
+                       rtctl.in_use = lde_nbr_is_nexthop(fn, me->nexthop);
+                       rtctl.nexthop = me->nexthop->id;
+                       rtctl.remote_label = me->map.label;
+                       lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_RCVD, 0, pid,
                            &rtctl, sizeof(rtctl));
                }
+               lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB_END, 0, pid, &rtctl,
+                   sizeof(rtctl));
        }
 }
 
index b0dc2914344c8e03b988459a7c34ca1193245c89..8510a394ec28c49e0d8e76898a5f0f6daf6e4a44 100644 (file)
@@ -71,6 +71,7 @@ int    ldp_vty_l2vpn_pw_pwstatus(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_binding(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_discovery(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_interface(struct vty *, struct vty_arg *[]);
+int     ldp_vty_show_capabilities(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_neighbor(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_atom_binding(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_atom_vc(struct vty *, struct vty_arg *[]);
@@ -79,6 +80,5 @@ int    ldp_vty_debug(struct vty *, struct vty_arg *[]);
 int     ldp_vty_show_debugging(struct vty *, struct vty_arg *[]);
 
 void    ldp_vty_init(void);
-void    ldp_vty_if_init(void);
 
 #endif /* _LDP_VTY_H_ */
index 966b634c2724cc5dc3466fe3be440015b174882a..cd5c92c7b12bb38f75803b50a5c2168eb410ed8c 100644 (file)
 
   <!-- exec mode commands -->
   <subtree name="ldp_show_af">
-    <option name="binding" help="Label Information Base (LIB) information">
-      <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_binding"/>
+    <option name="binding" help="Label Information Base (LIB) information" function="ldp_vty_show_binding">
+      <option name="json" arg="json" help="JavaScript Object Notation" function="ldp_vty_show_binding"/>
+      <option name="detail" arg="detail" help="Show detailed information">
+        <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_binding"/>
+      </option>
     </option>
-    <option name="discovery" help="Discovery Hello Information">
-      <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_discovery"/>
+    <option name="discovery" help="Discovery Hello Information" function="ldp_vty_show_discovery">
+      <option name="json" arg="json" help="JavaScript Object Notation" function="ldp_vty_show_discovery"/>
+      <option name="detail" arg="detail" help="Show detailed information">
+        <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_discovery"/>
+      </option>
     </option>
     <option name="interface" help="interface information">
       <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_interface"/>
     <option name="show" help="Show running system information">
       <option name="mpls" help="MPLS information">
         <option name="ldp" help="Label Distribution Protocol">
-          <option name="neighbor" help="Neighbor information">
-            <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_neighbor"/>
+          <option name="capabilities" help="Display LDP Capabilities information">
+            <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_capabilities"/>
+          </option>
+          <option name="neighbor" help="Neighbor information" function="ldp_vty_show_neighbor">
+            <option name="capabilities" arg="capabilities" help="Display neighbor capability information">
+              <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_neighbor"/>
+            </option>
+            <option name="json" arg="json" help="JavaScript Object Notation" function="ldp_vty_show_neighbor"/>
+            <option name="detail" arg="detail" help="Show detailed information">
+              <option name="json" arg="json" optional="true" help="JavaScript Object Notation" function="ldp_vty_show_neighbor"/>
+            </option>
           </option>
           <include subtree="ldp_show_af"/>
           <select options="address-family" arg="address-family">
index 4d1af62146c720b1a9e12acaf87f13c6cf8f5280..e4fc7b00545fc281f34edc8651bc9bf2bcc655f2 100644 (file)
@@ -32,7 +32,6 @@
 #include "vty.h"
 #include "ldp_vty.h"
 
-static int      interface_config_write(struct vty *);
 static void     ldp_af_iface_config_write(struct vty *, int);
 static void     ldp_af_config_write(struct vty *, int, struct ldpd_conf *,
                    struct ldpd_af_conf *);
@@ -42,13 +41,6 @@ static int    ldp_iface_is_configured(struct ldpd_conf *, const char *);
 static int      ldp_vty_nbr_session_holdtime(struct vty *, struct vty_arg *[]);
 static int      ldp_vty_af_session_holdtime(struct vty *, struct vty_arg *[]);
 
-static struct cmd_node interface_node =
-{
-       INTERFACE_NODE,
-       "%s(config-if)# ",
-       1
-};
-
 struct cmd_node ldp_node =
 {
        LDP_NODE,
@@ -116,26 +108,6 @@ ldp_get_address(const char *str, int *af, union ldpd_addr *addr)
        return (-1);
 }
 
-static int
-interface_config_write(struct vty *vty)
-{
-       struct listnode         *node;
-       struct interface        *ifp;
-       int                      write = 0;
-
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), node, ifp)) {
-               vty_out(vty, "!%s", VTY_NEWLINE);
-               vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE);
-               if (ifp->desc)
-                       vty_out(vty, " description %s%s", ifp->desc,
-                           VTY_NEWLINE);
-
-               write++;
-       }
-
-       return (write);
-}
-
 static void
 ldp_af_iface_config_write(struct vty *vty, int af)
 {
@@ -437,9 +409,9 @@ ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname)
                return (1);
 
        RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
-               if (l2vpn_if_find_name(l2vpn, ifname))
+               if (l2vpn_if_find(l2vpn, ifname))
                        return (1);
-               if (l2vpn_pw_find_name(l2vpn, ifname))
+               if (l2vpn_pw_find(l2vpn, ifname))
                        return (1);
        }
 
@@ -449,11 +421,8 @@ ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname)
 int
 ldp_vty_mpls_ldp(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        int                      disable;
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
 
        if (disable)
@@ -471,7 +440,6 @@ ldp_vty_mpls_ldp(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_address_family(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *af_str;
@@ -480,17 +448,14 @@ ldp_vty_address_family(struct vty *vty, struct vty_arg *args[])
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        af_str = vty_get_arg_value(args, "address-family");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        if (strcmp(af_str, "ipv4") == 0) {
                af = AF_INET;
                af_conf = &vty_conf->ipv4;
        } else if (strcmp(af_str, "ipv6") == 0) {
                af = AF_INET6;
                af_conf = &vty_conf->ipv6;
-       } else {
-               ldp_clear_config(vty_conf);
+       } else
                return (CMD_WARNING);
-       }
 
        if (disable) {
                af_conf->flags &= ~F_LDPD_AF_ENABLED;
@@ -518,7 +483,6 @@ ldp_vty_address_family(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        struct iface            *iface;
        struct iface_af         *ia;
@@ -547,7 +511,6 @@ ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
 
        switch (vty->node) {
        case LDP_NODE:
-               vty_conf = ldp_dup_config(ldpd_conf);
                if (disable) {
                        switch (hello_type) {
                        case HELLO_LINK:
@@ -572,7 +535,6 @@ ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
                break;
        case LDP_IPV4_NODE:
        case LDP_IPV6_NODE:
-               vty_conf = ldp_dup_config(ldpd_conf);
                af = ldp_vty_get_af(vty);
                af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -601,14 +563,15 @@ ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
        case LDP_IPV6_IFACE_NODE:
                af = ldp_vty_get_af(vty);
                iface = VTY_GET_CONTEXT(iface);
-               vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&iface);
+               VTY_CHECK_CONTEXT(iface);
 
                ia = iface_af_get(iface, af);
                if (disable)
                        ia->hello_holdtime = 0;
                else
                        ia->hello_holdtime = secs;
-               ldp_reload_ref(vty_conf, (void **)&iface);
+
+               ldp_reload(vty_conf);
                break;
        default:
                fatalx("ldp_vty_disc_holdtime: unexpected node");
@@ -620,7 +583,6 @@ ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        struct iface            *iface;
        struct iface_af         *ia;
@@ -650,7 +612,6 @@ ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
 
        switch (vty->node) {
        case LDP_NODE:
-               vty_conf = ldp_dup_config(ldpd_conf);
                if (disable) {
                        switch (hello_type) {
                        case HELLO_LINK:
@@ -675,7 +636,6 @@ ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
                break;
        case LDP_IPV4_NODE:
        case LDP_IPV6_NODE:
-               vty_conf = ldp_dup_config(ldpd_conf);
                af = ldp_vty_get_af(vty);
                af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -704,14 +664,15 @@ ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
        case LDP_IPV6_IFACE_NODE:
                af = ldp_vty_get_af(vty);
                iface = VTY_GET_CONTEXT(iface);
-               vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&iface);
+               VTY_CHECK_CONTEXT(iface);
 
                ia = iface_af_get(iface, af);
                if (disable)
                        ia->hello_interval = 0;
                else
                        ia->hello_interval = secs;
-               ldp_reload_ref(vty_conf, (void **)&iface);
+
+               ldp_reload(vty_conf);
                break;
        default:
                fatalx("ldp_vty_disc_interval: unexpected node");
@@ -723,14 +684,11 @@ ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *acl_from_str;
        int                      disable;
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        acl_from_str = vty_get_arg_value(args, "from_acl");
 
@@ -757,7 +715,6 @@ ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[])
 static int
 ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        char                    *ep;
        long int                 secs;
        struct in_addr           lsr_id;
@@ -776,18 +733,17 @@ ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-       nbrp = nbr_params_find(vty_conf, lsr_id);
-
        secs = strtol(seconds_str, &ep, 10);
        if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) {
                vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE);
-               goto cancel;
+               return (CMD_SUCCESS);
        }
 
+       nbrp = nbr_params_find(vty_conf, lsr_id);
+
        if (disable) {
                if (nbrp == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                nbrp->keepalive = 0;
                nbrp->flags &= ~F_NBRP_KEEPALIVE;
@@ -795,8 +751,9 @@ ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[])
                if (nbrp == NULL) {
                        nbrp = nbr_params_new(lsr_id);
                        RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp);
+                       QOBJ_REG(nbrp, nbr_params);
                } else if (nbrp->keepalive == secs)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                nbrp->keepalive = secs;
                nbrp->flags |= F_NBRP_KEEPALIVE;
@@ -805,16 +762,11 @@ ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[])
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 static int
 ldp_vty_af_session_holdtime(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        char                    *ep;
@@ -831,7 +783,6 @@ ldp_vty_af_session_holdtime(struct vty *vty, struct vty_arg *args[])
                return (CMD_SUCCESS);
        }
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -862,34 +813,32 @@ ldp_vty_session_holdtime(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_interface(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        int                      af;
        struct iface            *iface;
        struct iface_af         *ia;
-       struct interface        *ifp;
-       struct kif               kif;
        const char              *ifname;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        ifname = vty_get_arg_value(args, "ifname");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        iface = if_lookup_name(vty_conf, ifname);
 
        if (disable) {
                if (iface == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                ia = iface_af_get(iface, af);
                if (ia->enabled == 0)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                ia->enabled = 0;
                ia->hello_holdtime = 0;
                ia->hello_interval = 0;
+
                ldp_reload(vty_conf);
+
                return (CMD_SUCCESS);
        }
 
@@ -897,32 +846,22 @@ ldp_vty_interface(struct vty *vty, struct vty_arg *args[])
                if (ldp_iface_is_configured(vty_conf, ifname)) {
                        vty_out(vty, "%% Interface is already in use%s",
                            VTY_NEWLINE);
-                       goto cancel;
-               }
-
-               ifp = if_lookup_by_name(ifname);
-               memset(&kif, 0, sizeof(kif));
-               strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-               if (ifp) {
-                       kif.ifindex = ifp->ifindex;
-                       kif.flags = ifp->flags;
+                       return (CMD_SUCCESS);
                }
-               iface = if_new(&kif);
 
+               iface = if_new(ifname);
                ia = iface_af_get(iface, af);
                ia->enabled = 1;
                RB_INSERT(iface_head, &vty_conf->iface_tree, iface);
-               ldp_reload_ref(vty_conf, (void **)&iface);
-       } else {
-               memset(&kif, 0, sizeof(kif));
-               strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
+               QOBJ_REG(iface, iface);
 
+               ldp_reload(vty_conf);
+       } else {
                ia = iface_af_get(iface, af);
                if (!ia->enabled) {
                        ia->enabled = 1;
-                       ldp_reload_ref(vty_conf, (void **)&iface);
-               } else
-                       ldp_clear_config(vty_conf);
+                       ldp_reload(vty_conf);
+               }
        }
 
        switch (af) {
@@ -937,16 +876,11 @@ ldp_vty_interface(struct vty *vty, struct vty_arg *args[])
        }
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *addr_str;
@@ -955,7 +889,6 @@ ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[])
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        addr_str = vty_get_arg_value(args, "addr");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -965,23 +898,18 @@ ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[])
                if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 ||
                    bad_addr(af, &af_conf->trans_addr)) {
                        vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
-                       goto cancel;
+                       return (CMD_SUCCESS);
                }
        }
 
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        int                      af;
        union ldpd_addr          addr;
        struct tnbr             *tnbr;
@@ -1003,39 +931,37 @@ ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        tnbr = tnbr_find(vty_conf, af, &addr);
 
        if (disable) {
                if (tnbr == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
+               QOBJ_UNREG(tnbr);
                RB_REMOVE(tnbr_head, &vty_conf->tnbr_tree, tnbr);
                free(tnbr);
+
                ldp_reload(vty_conf);
+
                return (CMD_SUCCESS);
        }
 
        if (tnbr)
-               goto cancel;
+               return (CMD_SUCCESS);
 
        tnbr = tnbr_new(af, &addr);
        tnbr->flags |= F_TNBR_CONFIGURED;
        RB_INSERT(tnbr_head, &vty_conf->tnbr_tree, tnbr);
+       QOBJ_REG(tnbr, tnbr);
 
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_label_advertise(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *acl_to_str;
@@ -1046,7 +972,6 @@ ldp_vty_label_advertise(struct vty *vty, struct vty_arg *args[])
        acl_to_str = vty_get_arg_value(args, "to_acl");
        acl_for_str = vty_get_arg_value(args, "for_acl");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -1074,7 +999,6 @@ ldp_vty_label_advertise(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_label_allocate(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *acl_for_str;
@@ -1085,7 +1009,6 @@ ldp_vty_label_allocate(struct vty *vty, struct vty_arg *args[])
        acl_for_str = vty_get_arg_value(args, "for_acl");
        host_routes_str = vty_get_arg_value(args, "host-routes");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -1107,7 +1030,6 @@ ldp_vty_label_allocate(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_label_expnull(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *acl_for_str;
@@ -1116,7 +1038,6 @@ ldp_vty_label_expnull(struct vty *vty, struct vty_arg *args[])
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        acl_for_str = vty_get_arg_value(args, "for_acl");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -1140,7 +1061,6 @@ ldp_vty_label_expnull(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_label_accept(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        const char              *acl_from_str;
@@ -1151,7 +1071,6 @@ ldp_vty_label_accept(struct vty *vty, struct vty_arg *args[])
        acl_from_str = vty_get_arg_value(args, "from_acl");
        acl_for_str = vty_get_arg_value(args, "for_acl");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -1179,14 +1098,12 @@ ldp_vty_label_accept(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_ttl_security(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct ldpd_af_conf     *af_conf;
        int                      af;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        af = ldp_vty_get_af(vty);
        af_conf = ldp_af_conf_get(vty_conf, af);
 
@@ -1203,44 +1120,34 @@ ldp_vty_ttl_security(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_router_id(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        const char              *addr_str;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        addr_str = vty_get_arg_value(args, "addr");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        if (disable)
                vty_conf->rtr_id.s_addr = INADDR_ANY;
        else {
                if (inet_pton(AF_INET, addr_str, &vty_conf->rtr_id) != 1 ||
                    bad_addr_v4(vty_conf->rtr_id)) {
                        vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
-                       goto cancel;
+                       return (CMD_SUCCESS);
                }
        }
 
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_ds_cisco_interop(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        if (disable)
                vty_conf->flags &= ~F_LDPD_DS_CISCO_INTEROP;
        else
@@ -1254,13 +1161,10 @@ ldp_vty_ds_cisco_interop(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_trans_pref_ipv4(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
 
-       vty_conf = ldp_dup_config(ldpd_conf);
-
        if (disable)
                vty_conf->trans_pref = DUAL_STACK_LDPOV6;
        else
@@ -1274,7 +1178,6 @@ ldp_vty_trans_pref_ipv4(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct in_addr           lsr_id;
        size_t                   password_len;
        struct nbr_params       *nbrp;
@@ -1292,12 +1195,11 @@ ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        nbrp = nbr_params_find(vty_conf, lsr_id);
 
        if (disable) {
                if (nbrp == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                memset(&nbrp->auth, 0, sizeof(nbrp->auth));
                nbrp->auth.method = AUTH_NONE;
@@ -1305,9 +1207,10 @@ ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[])
                if (nbrp == NULL) {
                        nbrp = nbr_params_new(lsr_id);
                        RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp);
+                       QOBJ_REG(nbrp, nbr_params);
                } else if (nbrp->auth.method == AUTH_MD5SIG &&
                    strcmp(nbrp->auth.md5key, password_str) == 0)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                password_len = strlcpy(nbrp->auth.md5key, password_str,
                    sizeof(nbrp->auth.md5key));
@@ -1321,16 +1224,11 @@ ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[])
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct in_addr           lsr_id;
        struct nbr_params       *nbrp;
        long int                 hops = 0;
@@ -1357,12 +1255,11 @@ ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[])
                }
        }
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        nbrp = nbr_params_find(vty_conf, lsr_id);
 
        if (disable) {
                if (nbrp == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
                nbrp->flags &= ~(F_NBRP_GTSM|F_NBRP_GTSM_HOPS);
                nbrp->gtsm_enabled = 0;
@@ -1371,6 +1268,7 @@ ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[])
                if (nbrp == NULL) {
                        nbrp = nbr_params_new(lsr_id);
                        RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp);
+                       QOBJ_REG(nbrp, nbr_params);
                }
 
                nbrp->flags |= F_NBRP_GTSM;
@@ -1386,75 +1284,74 @@ ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[])
        ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
-
-cancel:
-       ldp_clear_config(vty_conf);
-       return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
        struct l2vpn            *l2vpn;
+       struct l2vpn_if         *lif;
+       struct l2vpn_pw         *pw;
        const char              *name_str;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        name_str = vty_get_arg_value(args, "name");
 
-       vty_conf = ldp_dup_config(ldpd_conf);
        l2vpn = l2vpn_find(vty_conf, name_str);
 
        if (disable) {
                if (l2vpn == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
+               RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
+                       QOBJ_UNREG(lif);
+               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
+                       QOBJ_UNREG(pw);
+               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree)
+                       QOBJ_UNREG(pw);
+               QOBJ_UNREG(l2vpn);
                RB_REMOVE(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn);
                l2vpn_del(l2vpn);
+
                ldp_reload(vty_conf);
+
                return (CMD_SUCCESS);
        }
 
        if (l2vpn) {
                VTY_PUSH_CONTEXT(LDP_L2VPN_NODE, l2vpn);
-               goto cancel;
+               return (CMD_SUCCESS);
        }
 
        l2vpn = l2vpn_new(name_str);
        l2vpn->type = L2VPN_TYPE_VPLS;
        RB_INSERT(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn);
+       QOBJ_REG(l2vpn, l2vpn);
 
-       ldp_reload_ref(vty_conf, (void **)&l2vpn);
        VTY_PUSH_CONTEXT(LDP_L2VPN_NODE, l2vpn);
 
-       return (CMD_SUCCESS);
+       ldp_reload(vty_conf);
 
-cancel:
-       ldp_clear_config(vty_conf);
        return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_l2vpn_bridge(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn            *l2vpn;
+       VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        const char              *ifname;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        ifname = vty_get_arg_value(args, "ifname");
 
-       l2vpn = VTY_GET_CONTEXT(l2vpn);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&l2vpn);
-
        if (disable)
                memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname));
        else
                strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname));
 
-       ldp_reload_ref(vty_conf, (void **)&l2vpn);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1462,8 +1359,7 @@ ldp_vty_l2vpn_bridge(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn            *l2vpn;
+       VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        char                    *ep;
        int                      mtu;
        const char              *mtu_str;
@@ -1478,15 +1374,12 @@ ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       l2vpn = VTY_GET_CONTEXT(l2vpn);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&l2vpn);
-
        if (disable)
                l2vpn->mtu = DEFAULT_L2VPN_MTU;
        else
                l2vpn->mtu = mtu;
 
-       ldp_reload_ref(vty_conf, (void **)&l2vpn);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1494,8 +1387,7 @@ ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn            *l2vpn;
+       VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        int                      pw_type;
        const char              *type_str;
        int                      disable;
@@ -1508,15 +1400,12 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[])
        else
                pw_type = PW_TYPE_ETHERNET_TAGGED;
 
-       l2vpn = VTY_GET_CONTEXT(l2vpn);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&l2vpn);
-
        if (disable)
                l2vpn->pw_type = DEFAULT_PW_TYPE;
        else
                l2vpn->pw_type = pw_type;
 
-       ldp_reload_ref(vty_conf, (void **)&l2vpn);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1524,134 +1413,107 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn            *l2vpn;
+       VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        struct l2vpn_if         *lif;
-       struct interface        *ifp;
-       struct kif               kif;
        const char              *ifname;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        ifname = vty_get_arg_value(args, "ifname");
 
-       l2vpn = VTY_GET_CONTEXT(l2vpn);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&l2vpn);
-       l2vpn = l2vpn_find(vty_conf, l2vpn->name);
-       lif = l2vpn_if_find_name(l2vpn, ifname);
+       lif = l2vpn_if_find(l2vpn, ifname);
 
        if (disable) {
                if (lif == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
+               QOBJ_UNREG(lif);
                RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
                free(lif);
+
                ldp_reload(vty_conf);
+
                return (CMD_SUCCESS);
        }
 
        if (lif)
-               goto cancel;
+               return (CMD_SUCCESS);
 
        if (ldp_iface_is_configured(vty_conf, ifname)) {
                vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE);
-               goto cancel;
-       }
-
-       ifp = if_lookup_by_name(ifname);
-       memset(&kif, 0, sizeof(kif));
-       strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-       if (ifp) {
-               kif.ifindex = ifp->ifindex;
-               kif.flags = ifp->flags;
+               return (CMD_SUCCESS);
        }
 
-       lif = l2vpn_if_new(l2vpn, &kif);
+       lif = l2vpn_if_new(l2vpn, ifname);
        RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
+       QOBJ_REG(lif, l2vpn_if);
 
-       ldp_reload_ref(vty_conf, (void **)&l2vpn);
-
-       return (CMD_SUCCESS);
+       ldp_reload(vty_conf);
 
-cancel:
-       ldp_clear_config(vty_conf);
        return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_l2vpn_pseudowire(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn            *l2vpn;
+       VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
        struct l2vpn_pw         *pw;
-       struct interface        *ifp;
-       struct kif               kif;
        const char              *ifname;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        ifname = vty_get_arg_value(args, "ifname");
 
-       l2vpn = VTY_GET_CONTEXT(l2vpn);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&l2vpn);
-       pw = l2vpn_pw_find_name(l2vpn, ifname);
+       pw = l2vpn_pw_find(l2vpn, ifname);
 
        if (disable) {
                if (pw == NULL)
-                       goto cancel;
+                       return (CMD_SUCCESS);
 
-               RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+               QOBJ_UNREG(pw);
+               if (pw->lsr_id.s_addr == INADDR_ANY || pw->pwid == 0)
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+               else
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
                free(pw);
+
                ldp_reload(vty_conf);
+
                return (CMD_SUCCESS);
        }
 
        if (pw) {
                VTY_PUSH_CONTEXT_SUB(LDP_PSEUDOWIRE_NODE, pw);
-               goto cancel;
+               return (CMD_SUCCESS);
        }
 
        if (ldp_iface_is_configured(vty_conf, ifname)) {
                vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE);
-               goto cancel;
-       }
-
-       ifp = if_lookup_by_name(ifname);
-       memset(&kif, 0, sizeof(kif));
-       strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-       if (ifp) {
-               kif.ifindex = ifp->ifindex;
-               kif.flags = ifp->flags;
+               return (CMD_SUCCESS);
        }
 
-       pw = l2vpn_pw_new(l2vpn, &kif);
+       pw = l2vpn_pw_new(l2vpn, ifname);
        pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
        RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+       QOBJ_REG(pw, l2vpn_pw);
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
        VTY_PUSH_CONTEXT_SUB(LDP_PSEUDOWIRE_NODE, pw);
 
-       return (CMD_SUCCESS);
+       ldp_reload(vty_conf);
 
-cancel:
-       ldp_clear_config(vty_conf);
        return (CMD_SUCCESS);
 }
 
 int
 ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn_pw         *pw;
+       VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw);
        const char              *preference_str;
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
        preference_str = vty_get_arg_value(args, "preference");
 
-       pw = VTY_GET_CONTEXT_SUB(l2vpn_pw);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&pw);
-
        if (disable)
                pw->flags |= F_PW_CWORD_CONF;
        else {
@@ -1661,7 +1523,7 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[])
                        pw->flags |= F_PW_CWORD_CONF;
        }
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1669,8 +1531,7 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn_pw         *pw;
+       VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw);
        int                      af;
        union ldpd_addr          addr;
        const char              *addr_str;
@@ -1685,9 +1546,6 @@ ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       pw = VTY_GET_CONTEXT_SUB(l2vpn_pw);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&pw);
-
        if (disable) {
                pw->af = AF_UNSPEC;
                memset(&pw->addr, 0, sizeof(pw->addr));
@@ -1698,7 +1556,7 @@ ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[])
                pw->flags |= F_PW_STATIC_NBR_ADDR;
        }
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1706,8 +1564,7 @@ ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn_pw         *pw;
+       VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw);
        struct in_addr           lsr_id;
        const char              *lsr_id_str;
        int                      disable;
@@ -1721,15 +1578,12 @@ ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       pw = VTY_GET_CONTEXT_SUB(l2vpn_pw);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&pw);
-
        if (disable)
                pw->lsr_id.s_addr = INADDR_ANY;
        else
                pw->lsr_id = lsr_id;
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1737,8 +1591,7 @@ ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn_pw         *pw;
+       VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw);
        char                    *ep;
        uint32_t                 pwid;
        const char              *pwid_str;
@@ -1753,15 +1606,12 @@ ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
        }
 
-       pw = VTY_GET_CONTEXT_SUB(l2vpn_pw);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&pw);
-
        if (disable)
                pw->pwid = 0;
        else
                pw->pwid = pwid;
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
@@ -1769,60 +1619,40 @@ ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[])
 int
 ldp_vty_l2vpn_pw_pwstatus(struct vty *vty, struct vty_arg *args[])
 {
-       struct ldpd_conf        *vty_conf;
-       struct l2vpn_pw         *pw;
+       VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw);
        int                      disable;
 
        disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
 
-       pw = VTY_GET_CONTEXT_SUB(l2vpn_pw);
-       vty_conf = ldp_dup_config_ref(ldpd_conf, (void **)&pw);
-
        if (disable)
                pw->flags |= F_PW_STATUSTLV_CONF;
        else
                pw->flags &= ~F_PW_STATUSTLV_CONF;
 
-       ldp_reload_ref(vty_conf, (void **)&pw);
+       ldp_reload(vty_conf);
 
        return (CMD_SUCCESS);
 }
 
-void
-ldp_vty_if_init(void)
-{
-       /* Install interface node. */
-       install_node (&interface_node, interface_config_write);
-       if_cmd_init ();
-}
-
 struct iface *
 iface_new_api(struct ldpd_conf *conf, const char *name)
 {
        const char              *ifname = name;
        struct iface            *iface;
-       struct interface        *ifp;
-       struct kif               kif;
 
        if (ldp_iface_is_configured(conf, ifname))
                return NULL;
 
-       memset(&kif, 0, sizeof(kif));
-       strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-       ifp = if_lookup_by_name(ifname);
-       if (ifp) {
-               kif.ifindex = ifp->ifindex;
-               kif.flags = ifp->flags;
-       }
-
-       iface = if_new(&kif);
+       iface = if_new(name);
        RB_INSERT(iface_head, &conf->iface_tree, iface);
+       QOBJ_REG(iface, iface);
        return (iface);
 }
 
 void
 iface_del_api(struct ldpd_conf *conf, struct iface *iface)
 {
+       QOBJ_UNREG(iface);
        RB_REMOVE(iface_head, &conf->iface_tree, iface);
        free(iface);
 }
@@ -1841,12 +1671,14 @@ tnbr_new_api(struct ldpd_conf *conf, int af, union ldpd_addr *addr)
        tnbr = tnbr_new(af, addr);
        tnbr->flags |= F_TNBR_CONFIGURED;
        RB_INSERT(tnbr_head, &conf->tnbr_tree, tnbr);
+       QOBJ_REG(tnbr, tnbr);
        return (tnbr);
 }
 
 void
 tnbr_del_api(struct ldpd_conf *conf, struct tnbr *tnbr)
 {
+       QOBJ_UNREG(tnbr);
        RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
        free(tnbr);
 }
@@ -1861,12 +1693,14 @@ nbrp_new_api(struct ldpd_conf *conf, struct in_addr lsr_id)
 
        nbrp = nbr_params_new(lsr_id);
        RB_INSERT(nbrp_head, &conf->nbrp_tree, nbrp);
+       QOBJ_REG(nbrp, nbr_params);
        return (nbrp);
 }
 
 void
 nbrp_del_api(struct ldpd_conf *conf, struct nbr_params *nbrp)
 {
+       QOBJ_UNREG(nbrp);
        RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp);
        free(nbrp);
 }
@@ -1882,6 +1716,7 @@ l2vpn_new_api(struct ldpd_conf *conf, const char *name)
        l2vpn = l2vpn_new(name);
        l2vpn->type = L2VPN_TYPE_VPLS;
        RB_INSERT(l2vpn_head, &conf->l2vpn_tree, l2vpn);
+       QOBJ_REG(l2vpn, l2vpn);
        return (l2vpn);
 }
 
@@ -1892,17 +1727,21 @@ l2vpn_del_api(struct ldpd_conf *conf, struct l2vpn *l2vpn)
        struct l2vpn_pw         *pw;
 
        while ((lif = RB_ROOT(&l2vpn->if_tree)) != NULL) {
+               QOBJ_UNREG(lif);
                RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
                free(lif);
        }
        while ((pw = RB_ROOT(&l2vpn->pw_tree)) != NULL) {
+               QOBJ_UNREG(pw);
                RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
                free(pw);
        }
        while ((pw = RB_ROOT(&l2vpn->pw_inactive_tree)) != NULL) {
+               QOBJ_UNREG(pw);
                RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
                free(pw);
        }
+       QOBJ_UNREG(l2vpn);
        RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
        free(l2vpn);
 }
@@ -1912,28 +1751,20 @@ l2vpn_if_new_api(struct ldpd_conf *conf, struct l2vpn *l2vpn,
     const char *ifname)
 {
        struct l2vpn_if         *lif;
-       struct interface        *ifp;
-       struct kif               kif;
 
        if (ldp_iface_is_configured(conf, ifname))
                return (NULL);
 
-       memset(&kif, 0, sizeof(kif));
-       strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-       ifp = if_lookup_by_name(ifname);
-       if (ifp) {
-               kif.ifindex = ifp->ifindex;
-               kif.flags = ifp->flags;
-       }
-
-       lif = l2vpn_if_new(l2vpn, &kif);
+       lif = l2vpn_if_new(l2vpn, ifname);
        RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
+       QOBJ_REG(lif, l2vpn_if);
        return (lif);
 }
 
 void
 l2vpn_if_del_api(struct l2vpn *l2vpn, struct l2vpn_if *lif)
 {
+       QOBJ_UNREG(lif);
        RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
        free(lif);
 }
@@ -1943,29 +1774,21 @@ l2vpn_pw_new_api(struct ldpd_conf *conf, struct l2vpn *l2vpn,
     const char *ifname)
 {
        struct l2vpn_pw         *pw;
-       struct interface        *ifp;
-       struct kif               kif;
 
        if (ldp_iface_is_configured(conf, ifname))
                return (NULL);
 
-       memset(&kif, 0, sizeof(kif));
-       strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
-       ifp = if_lookup_by_name(ifname);
-       if (ifp) {
-               kif.ifindex = ifp->ifindex;
-               kif.flags = ifp->flags;
-       }
-
-       pw = l2vpn_pw_new(l2vpn, &kif);
+       pw = l2vpn_pw_new(l2vpn, ifname);
        pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
        RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+       QOBJ_REG(pw, l2vpn_pw);
        return (pw);
 }
 
 void
 l2vpn_pw_del_api(struct l2vpn *l2vpn, struct l2vpn_pw *pw)
 {
+       QOBJ_UNREG(pw);
        RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
        free(pw);
 }
index 56a64c84f374ce56c61b30ee7b710e7200203029..a149b7fe3522b4993dbd758cb88559dad8e291fa 100644 (file)
@@ -46,6 +46,8 @@ struct show_params {
        int             family;
        union ldpd_addr addr;
        uint8_t         prefixlen;
+       int             capabilities;
+       int             detail;
        int             json;
 };
 
@@ -55,24 +57,46 @@ static int           show_interface_msg(struct vty *, struct imsg *,
                            struct show_params *);
 static int              show_interface_msg_json(struct imsg *,
                            struct show_params *, json_object *);
-static void             show_discovery_adj(struct vty *, char *,
-                           struct ctl_adj *);
 static int              show_discovery_msg(struct vty *, struct imsg *,
                            struct show_params *);
-static void             show_discovery_adj_json(json_object *,
+static void             show_discovery_detail_adj(struct vty *, char *,
                            struct ctl_adj *);
+static int              show_discovery_detail_msg(struct vty *, struct imsg *,
+                           struct show_params *);
 static int              show_discovery_msg_json(struct imsg *,
                            struct show_params *, json_object *);
-static void             show_nbr_adj(struct vty *, char *, struct ctl_adj *);
+static void             show_discovery_detail_adj_json(json_object *,
+                           struct ctl_adj *);
+static int              show_discovery_detail_msg_json(struct imsg *,
+                           struct show_params *, json_object *);
+
 static int              show_nbr_msg(struct vty *, struct imsg *,
                            struct show_params *);
-static void             show_nbr_adj_json(struct ctl_adj *, json_object *);
 static int              show_nbr_msg_json(struct imsg *, struct show_params *,
                            json_object *);
+static void             show_nbr_detail_adj(struct vty *, char *,
+                           struct ctl_adj *);
+static int              show_nbr_detail_msg(struct vty *, struct imsg *,
+                           struct show_params *);
+static void             show_nbr_detail_adj_json(struct ctl_adj *,
+                           json_object *);
+static int              show_nbr_detail_msg_json(struct imsg *,
+                           struct show_params *, json_object *);
+static void             show_nbr_capabilities(struct vty *, struct ctl_nbr *);
+static int              show_nbr_capabilities_msg(struct vty *, struct imsg *,
+                           struct show_params *);
+static void             show_nbr_capabilities_json(struct ctl_nbr *,
+                           json_object *);
+static int              show_nbr_capabilities_msg_json(struct imsg *,
+                           struct show_params *, json_object *);
 static int              show_lib_msg(struct vty *, struct imsg *,
                            struct show_params *);
+static int              show_lib_detail_msg(struct vty *, struct imsg *,
+                           struct show_params *);
 static int              show_lib_msg_json(struct imsg *, struct show_params *,
                            json_object *);
+static int              show_lib_detail_msg_json(struct imsg *,
+                           struct show_params *, json_object *);
 static int              show_l2vpn_binding_msg(struct vty *, struct imsg *,
                            struct show_params *);
 static int              show_l2vpn_binding_msg_json(struct imsg *,
@@ -164,22 +188,73 @@ show_interface_msg_json(struct imsg *imsg, struct show_params *params,
        return (0);
 }
 
+static int
+show_discovery_msg(struct vty *vty, struct imsg *imsg,
+    struct show_params *params)
+{
+       struct ctl_adj          *adj;
+       const char              *addr;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_DISCOVERY:
+               adj = imsg->data;
+
+               if (params->family != AF_UNSPEC && params->family != adj->af)
+                       break;
+
+               vty_out(vty, "%-4s %-15s ", af_name(adj->af),
+                   inet_ntoa(adj->id));
+               switch(adj->type) {
+               case HELLO_LINK:
+                       vty_out(vty, "%-8s %-15s ", "Link", adj->ifname);
+                       break;
+               case HELLO_TARGETED:
+                       addr = log_addr(adj->af, &adj->src_addr);
+
+                       vty_out(vty, "%-8s %-15s ", "Targeted", addr);
+                       if (strlen(addr) > 15)
+                               vty_out(vty, "%s%46s", VTY_NEWLINE, " ");
+                       break;
+               }
+               vty_out(vty, "%9u%s", adj->holdtime, VTY_NEWLINE);
+               break;
+       case IMSG_CTL_END:
+               vty_out(vty, "%s", VTY_NEWLINE);
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
 static void
-show_discovery_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
+show_discovery_detail_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
 {
        size_t   buflen = strlen(buffer);
 
        snprintf(buffer + buflen, LDPBUFSIZ - buflen,
-           "      LDP Id: %s:0, Transport address: %s%s",
-           inet_ntoa(adj->id), log_addr(adj->af,
-           &adj->trans_addr), VTY_NEWLINE);
+           "      LSR Id: %s:0%s", inet_ntoa(adj->id), VTY_NEWLINE);
+       buflen = strlen(buffer);
+       snprintf(buffer + buflen, LDPBUFSIZ - buflen,
+           "          Source address: %s%s",
+           log_addr(adj->af, &adj->src_addr), VTY_NEWLINE);
+       buflen = strlen(buffer);
+       snprintf(buffer + buflen, LDPBUFSIZ - buflen,
+           "          Transport address: %s%s",
+           log_addr(adj->af, &adj->trans_addr), VTY_NEWLINE);
+       buflen = strlen(buffer);
+       snprintf(buffer + buflen, LDPBUFSIZ - buflen,
+           "          Hello hold time: %u secs (due in %u secs)%s",
+           adj->holdtime, adj->holdtime_remaining, VTY_NEWLINE);
        buflen = strlen(buffer);
        snprintf(buffer + buflen, LDPBUFSIZ - buflen,
-           "          Hold time: %u sec%s", adj->holdtime, VTY_NEWLINE);
+           "          Dual-stack capability TLV: %s%s",
+           (adj->ds_tlv) ? "yes" : "no", VTY_NEWLINE);
 }
 
 static int
-show_discovery_msg(struct vty *vty, struct imsg *imsg,
+show_discovery_detail_msg(struct vty *vty, struct imsg *imsg,
     struct show_params *params)
 {
        struct ctl_adj          *adj;
@@ -207,7 +282,7 @@ show_discovery_msg(struct vty *vty, struct imsg *imsg,
                buflen = strlen(ifaces_buffer);
                snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen,
                     "    %s: %s%s", iface->name, (iface->no_adj) ?
-                   "xmit" : "xmit/recv", VTY_NEWLINE);
+                   "(no adjacencies)" : "", VTY_NEWLINE);
                break;
        case IMSG_CTL_SHOW_DISC_TNBR:
                tnbr = imsg->data;
@@ -220,8 +295,8 @@ show_discovery_msg(struct vty *vty, struct imsg *imsg,
                buflen = strlen(tnbrs_buffer);
                snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen,
                    "    %s -> %s: %s%s", log_addr(tnbr->af, trans_addr),
-                   log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ? "xmit" :
-                   "xmit/recv", VTY_NEWLINE);
+                   log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ?
+                   "(no adjacencies)" : "", VTY_NEWLINE);
                break;
        case IMSG_CTL_SHOW_DISC_ADJ:
                adj = imsg->data;
@@ -231,17 +306,26 @@ show_discovery_msg(struct vty *vty, struct imsg *imsg,
 
                switch(adj->type) {
                case HELLO_LINK:
-                       show_discovery_adj(vty, ifaces_buffer, adj);
+                       show_discovery_detail_adj(vty, ifaces_buffer, adj);
                        break;
                case HELLO_TARGETED:
-                       show_discovery_adj(vty, tnbrs_buffer, adj);
+                       show_discovery_detail_adj(vty, tnbrs_buffer, adj);
                        break;
                }
                break;
        case IMSG_CTL_END:
                rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
-               vty_out(vty, "Local LDP Identifier: %s:0%s", inet_ntoa(rtr_id),
+               vty_out(vty, "Local:%s", VTY_NEWLINE);
+               vty_out(vty, "  LSR Id: %s:0%s", inet_ntoa(rtr_id),
                    VTY_NEWLINE);
+               if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
+                       vty_out(vty, "  Transport Address (IPv4): %s%s",
+                           log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr),
+                           VTY_NEWLINE);
+               if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
+                       vty_out(vty, "  Transport Address (IPv6): %s%s",
+                           log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr),
+                           VTY_NEWLINE);
                vty_out(vty, "Discovery Sources:%s", VTY_NEWLINE);
                vty_out(vty, "  Interfaces:%s", VTY_NEWLINE);
                vty_out(vty, "%s", ifaces_buffer);
@@ -256,8 +340,59 @@ show_discovery_msg(struct vty *vty, struct imsg *imsg,
        return (0);
 }
 
+static int
+show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
+    json_object *json)
+{
+       struct ctl_adj          *adj;
+       json_object             *json_array;
+       json_object             *json_adj;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_DISCOVERY:
+               adj = imsg->data;
+
+               if (params->family != AF_UNSPEC && params->family != adj->af)
+                       break;
+
+               json_object_object_get_ex(json, "adjacencies", &json_array);
+               if (!json_array) {
+                       json_array = json_object_new_array();
+                       json_object_object_add(json, "adjacencies", json_array);
+               }
+
+               json_adj = json_object_new_object();
+               json_object_string_add(json_adj, "addressFamily",
+                   af_name(adj->af));
+               json_object_string_add(json_adj, "neighborId",
+                   inet_ntoa(adj->id));
+               switch(adj->type) {
+               case HELLO_LINK:
+                       json_object_string_add(json_adj, "type", "link");
+                       json_object_string_add(json_adj, "interface",
+                           adj->ifname);
+                       break;
+               case HELLO_TARGETED:
+                       json_object_string_add(json_adj, "type", "targeted");
+                       json_object_string_add(json_adj, "peer",
+                           log_addr(adj->af, &adj->src_addr));
+                       break;
+               }
+               json_object_int_add(json_adj, "helloHoldtime", adj->holdtime);
+
+               json_object_array_add(json_array, json_adj);
+               break;
+       case IMSG_CTL_END:
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
 static void
-show_discovery_adj_json(json_object *json, struct ctl_adj *adj)
+show_discovery_detail_adj_json(json_object *json, struct ctl_adj *adj)
 {
        json_object *json_adj;
        json_object *json_array;
@@ -269,15 +404,21 @@ show_discovery_adj_json(json_object *json, struct ctl_adj *adj)
        }
 
        json_adj = json_object_new_object();
-       json_object_string_add(json_adj, "id", inet_ntoa(adj->id));
+       json_object_string_add(json_adj, "lsrId", inet_ntoa(adj->id));
+       json_object_string_add(json_adj, "sourceAddress", log_addr(adj->af,
+           &adj->src_addr));
        json_object_string_add(json_adj, "transportAddress", log_addr(adj->af,
            &adj->trans_addr));
-       json_object_int_add(json_adj, "holdtime", adj->holdtime);
+       json_object_int_add(json_adj, "helloHoldtime", adj->holdtime);
+       json_object_int_add(json_adj, "helloHoldtimeRemaining",
+           adj->holdtime_remaining);
+       json_object_int_add(json_adj, "dualStackCapabilityTlv",
+           adj->ds_tlv);
        json_object_array_add(json_array, json_adj);
 }
 
 static int
-show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
+show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params,
     json_object *json)
 {
        struct ctl_adj          *adj;
@@ -294,7 +435,13 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
        switch (imsg->hdr.type) {
        case IMSG_CTL_SHOW_DISCOVERY:
                rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
-               json_object_string_add(json, "id", inet_ntoa(rtr_id));
+               json_object_string_add(json, "lsrId", inet_ntoa(rtr_id));
+               if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
+                       json_object_string_add(json, "transportAddressIPv4",
+                           log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr));
+               if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
+                       json_object_string_add(json, "transportAddressIPv6",
+                           log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr));
                json_interfaces = json_object_new_object();
                json_object_object_add(json, "interfaces", json_interfaces);
                json_targets = json_object_new_object();
@@ -310,10 +457,6 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
                        break;
 
                json_interface = json_object_new_object();
-               json_object_boolean_true_add(json_interface, "transmit");
-               if (!iface->no_adj)
-                       json_object_boolean_true_add(json_interface, "receive");
-
                json_object_object_add(json_interfaces, iface->name,
                    json_interface);
                json_container = json_interface;
@@ -329,10 +472,6 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
                json_target = json_object_new_object();
                json_object_string_add(json_target, "sourceAddress",
                    log_addr(tnbr->af, trans_addr));
-               json_object_boolean_true_add(json_target, "transmit");
-               if (!tnbr->no_adj)
-                       json_object_boolean_true_add(json_target, "receive");
-
                json_object_object_add(json_targets, log_addr(tnbr->af,
                    &tnbr->addr), json_target);
                json_container = json_target;
@@ -345,10 +484,10 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
 
                switch(adj->type) {
                case HELLO_LINK:
-                       show_discovery_adj_json(json_container, adj);
+                       show_discovery_detail_adj_json(json_container, adj);
                        break;
                case HELLO_TARGETED:
-                       show_discovery_adj_json(json_container, adj);
+                       show_discovery_detail_adj_json(json_container, adj);
                        break;
                }
                break;
@@ -361,8 +500,37 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
        return (0);
 }
 
+static int
+show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
+{
+       struct ctl_nbr          *nbr;
+       const char              *addr;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_NBR:
+               nbr = imsg->data;
+
+               addr = log_addr(nbr->af, &nbr->raddr);
+
+               vty_out(vty, "%-4s %-15s %-11s %-15s",
+                   af_name(nbr->af), inet_ntoa(nbr->id),
+                   nbr_state_name(nbr->nbr_state), addr);
+               if (strlen(addr) > 15)
+                       vty_out(vty, "%s%48s", VTY_NEWLINE, " ");
+               vty_out(vty, " %8s%s", nbr->uptime == 0 ? "-" :
+                   log_time(nbr->uptime), VTY_NEWLINE);
+               break;
+       case IMSG_CTL_END:
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
 static void
-show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
+show_nbr_detail_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
 {
        size_t   buflen = strlen(buffer);
 
@@ -380,9 +548,11 @@ show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
 }
 
 static int
-show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
+show_nbr_detail_msg(struct vty *vty, struct imsg *imsg,
+    struct show_params *params)
 {
        struct ctl_nbr          *nbr;
+       struct ldp_stats        *stats;
        struct ctl_adj          *adj;
        static char              v4adjs_buffer[LDPBUFSIZ];
        static char              v6adjs_buffer[LDPBUFSIZ];
@@ -399,25 +569,54 @@ show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
                    log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport),
                    log_addr(nbr->af, &nbr->raddr), ntohs(nbr->rport),
                    VTY_NEWLINE);
-               vty_out(vty, "  Session Holdtime: %u sec%s", nbr->holdtime,
-                   VTY_NEWLINE);
+               vty_out(vty, "  Authentication: %s%s",
+                   (nbr->auth_method == AUTH_MD5SIG) ? "TCP MD5 Signature" :
+                   "none", VTY_NEWLINE);
+               vty_out(vty, "  Session Holdtime: %u secs; "
+                   "KeepAlive interval: %u secs%s", nbr->holdtime,
+                   nbr->holdtime / KEEPALIVE_PER_PERIOD, VTY_NEWLINE);
                vty_out(vty, "  State: %s; Downstream-Unsolicited%s",
                    nbr_state_name(nbr->nbr_state), VTY_NEWLINE);
                vty_out(vty, "  Up time: %s%s", log_time(nbr->uptime),
                    VTY_NEWLINE);
+
+               stats = &nbr->stats;
+               vty_out(vty, "  Messages sent/rcvd:%s", VTY_NEWLINE);
+               vty_out(vty, "   - Keepalive Messages: %u/%u%s",
+                   stats->kalive_sent, stats->kalive_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Address Messages: %u/%u%s",
+                   stats->addr_sent, stats->addr_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Address Withdraw Messages: %u/%u%s",
+                   stats->addrwdraw_sent, stats->addrwdraw_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Notification Messages: %u/%u%s",
+                   stats->notif_sent, stats->notif_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Capability Messages: %u/%u%s",
+                   stats->capability_sent, stats->capability_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Label Mapping Messages: %u/%u%s",
+                   stats->labelmap_sent, stats->labelmap_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Label Request Messages: %u/%u%s",
+                   stats->labelreq_sent, stats->labelreq_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Label Withdraw Messages: %u/%u%s",
+                   stats->labelwdraw_sent, stats->labelwdraw_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Label Release Messages: %u/%u%s",
+                   stats->labelrel_sent, stats->labelrel_rcvd, VTY_NEWLINE);
+               vty_out(vty, "   - Label Abort Request Messages: %u/%u%s",
+                   stats->labelabreq_sent, stats->labelabreq_rcvd, VTY_NEWLINE);
+
+               show_nbr_capabilities(vty, nbr);
                break;
        case IMSG_CTL_SHOW_NBR_DISC:
                adj = imsg->data;
 
                switch (adj->af) {
                case AF_INET:
-                       show_nbr_adj(vty, v4adjs_buffer, adj);
+                       show_nbr_detail_adj(vty, v4adjs_buffer, adj);
                        break;
                case AF_INET6:
-                       show_nbr_adj(vty, v6adjs_buffer, adj);
+                       show_nbr_detail_adj(vty, v6adjs_buffer, adj);
                        break;
                default:
-                       fatalx("show_nbr_msg: unknown af");
+                       fatalx("show_nbr_detail_msg: unknown af");
                }
                break;
        case IMSG_CTL_SHOW_NBR_END:
@@ -441,8 +640,49 @@ show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
        return (0);
 }
 
+static int
+show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
+    json_object *json)
+{
+       struct ctl_nbr          *nbr;
+       json_object             *json_array;
+       json_object             *json_nbr;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_NBR:
+               nbr = imsg->data;
+
+               json_object_object_get_ex(json, "neighbors", &json_array);
+               if (!json_array) {
+                       json_array = json_object_new_array();
+                       json_object_object_add(json, "neighbors", json_array);
+               }
+
+               json_nbr = json_object_new_object();
+               json_object_string_add(json_nbr, "addressFamily",
+                   af_name(nbr->af));
+               json_object_string_add(json_nbr, "neighborId",
+                   inet_ntoa(nbr->id));
+               json_object_string_add(json_nbr, "state",
+                   nbr_state_name(nbr->nbr_state));
+               json_object_string_add(json_nbr, "transportAddress",
+                   log_addr(nbr->af, &nbr->raddr));
+               json_object_string_add(json_nbr, "upTime",
+                   log_time(nbr->uptime));
+
+               json_object_array_add(json_array, json_nbr);
+               break;
+       case IMSG_CTL_END:
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
 static void
-show_nbr_adj_json(struct ctl_adj *adj, json_object *adj_list)
+show_nbr_detail_adj_json(struct ctl_adj *adj, json_object *adj_list)
 {
        char adj_string[128];
 
@@ -462,12 +702,15 @@ show_nbr_adj_json(struct ctl_adj *adj, json_object *adj_list)
 }
 
 static int
-show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
+show_nbr_detail_msg_json(struct imsg *imsg, struct show_params *params,
     json_object *json)
 {
        struct ctl_nbr          *nbr;
+       struct ldp_stats        *stats;
        struct ctl_adj          *adj;
        json_object             *json_nbr;
+       json_object             *json_array;
+       json_object             *json_counter;
        static json_object      *json_nbr_sources;
        static json_object      *json_v4adjs;
        static json_object      *json_v6adjs;
@@ -477,6 +720,8 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
                nbr = imsg->data;
 
                json_nbr = json_object_new_object();
+               json_object_object_add(json, inet_ntoa(nbr->id), json_nbr);
+
                json_object_string_add(json_nbr, "peerId", inet_ntoa(nbr->id));
                json_object_string_add(json_nbr, "tcpLocalAddress",
                    log_addr(nbr->af, &nbr->laddr));
@@ -486,13 +731,109 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
                    log_addr(nbr->af, &nbr->raddr));
                json_object_int_add(json_nbr, "tcpRemotePort",
                    ntohs(nbr->rport));
-               json_object_int_add(json_nbr, "holdtime", nbr->holdtime);
+               json_object_string_add(json_nbr, "authentication",
+                   (nbr->auth_method == AUTH_MD5SIG) ? "TCP MD5 Signature" :
+                   "none");
+               json_object_int_add(json_nbr, "sessionHoldtime", nbr->holdtime);
+               json_object_int_add(json_nbr, "keepAliveInterval",
+                   nbr->holdtime / KEEPALIVE_PER_PERIOD);
                json_object_string_add(json_nbr, "state",
                    nbr_state_name(nbr->nbr_state));
                json_object_string_add(json_nbr, "upTime",
                    log_time(nbr->uptime));
-               json_object_object_add(json, inet_ntoa(nbr->id), json_nbr);
 
+               /* message_counters */
+               stats = &nbr->stats;
+               json_array = json_object_new_array();
+               json_object_object_add(json_nbr, "sentMessages", json_array);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "keepalive",
+                   stats->kalive_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "address",
+                   stats->addr_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "addressWithdraw",
+                   stats->addrwdraw_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "notification",
+                   stats->notif_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "capability",
+                   stats->capability_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelMapping",
+                   stats->labelmap_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelRequest",
+                   stats->labelreq_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelWithdraw",
+                   stats->labelwdraw_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelRelease",
+                   stats->labelrel_sent);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelAbortRequest",
+                   stats->labelabreq_sent);
+               json_object_array_add(json_array, json_counter);
+
+               json_array = json_object_new_array();
+               json_object_object_add(json_nbr, "receivedMessages", json_array);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "keepalive",
+                   stats->kalive_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "address",
+                   stats->addr_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "addressWithdraw",
+                   stats->addrwdraw_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "notification",
+                   stats->notif_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "capability",
+                   stats->capability_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelMapping",
+                   stats->labelmap_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelRequest",
+                   stats->labelreq_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelWithdraw",
+                   stats->labelwdraw_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelRelease",
+                   stats->labelrel_rcvd);
+               json_object_array_add(json_array, json_counter);
+               json_counter = json_object_new_object();
+               json_object_int_add(json_counter, "labelAbortRequest",
+                   stats->labelabreq_rcvd);
+               json_object_array_add(json_array, json_counter);
+
+               /* capabilities */
+               show_nbr_capabilities_json(nbr, json_nbr);
+
+               /* discovery sources */
                json_nbr_sources = json_object_new_object();
                json_object_object_add(json_nbr, "discoverySources",
                    json_nbr_sources);
@@ -509,7 +850,7 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
                                json_object_object_add(json_nbr_sources, "ipv4",
                                    json_v4adjs);
                        }
-                       show_nbr_adj_json(adj, json_v4adjs);
+                       show_nbr_detail_adj_json(adj, json_v4adjs);
                        break;
                case AF_INET6:
                        if (!json_v6adjs) {
@@ -517,10 +858,10 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
                                json_object_object_add(json_nbr_sources, "ipv6",
                                    json_v6adjs);
                        }
-                       show_nbr_adj_json(adj, json_v6adjs);
+                       show_nbr_detail_adj_json(adj, json_v6adjs);
                        break;
                default:
-                       fatalx("show_nbr_msg_json: unknown af");
+                       fatalx("show_nbr_detail_msg_json: unknown af");
                }
                break;
        case IMSG_CTL_SHOW_NBR_END:
@@ -534,6 +875,139 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
        return (0);
 }
 
+void
+show_nbr_capabilities(struct vty *vty, struct ctl_nbr *nbr)
+{
+       vty_out(vty, "  Capabilities Sent:%s"
+           "   - Dynamic Announcement (0x0506)%s"
+           "   - Typed Wildcard (0x050B)%s"
+           "   - Unrecognized Notification (0x0603)%s",
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+       vty_out(vty, "  Capabilities Received:%s", VTY_NEWLINE);
+       if (nbr->flags & F_NBR_CAP_DYNAMIC)
+               vty_out(vty, "   - Dynamic Announcement (0x0506)%s",
+                   VTY_NEWLINE);
+       if (nbr->flags & F_NBR_CAP_TWCARD)
+               vty_out(vty, "   - Typed Wildcard (0x050B)%s", VTY_NEWLINE);
+       if (nbr->flags & F_NBR_CAP_UNOTIF)
+               vty_out(vty, "   - Unrecognized Notification (0x0603)%s",
+                   VTY_NEWLINE);
+}
+
+static int
+show_nbr_capabilities_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
+{
+       struct ctl_nbr          *nbr;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_NBR:
+               nbr = imsg->data;
+
+               if (nbr->nbr_state != NBR_STA_OPER)
+                       break;
+
+               vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id),
+                   VTY_NEWLINE);
+               show_nbr_capabilities(vty, nbr);
+               break;
+       case IMSG_CTL_END:
+               vty_out(vty, "%s", VTY_NEWLINE);
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
+static void
+show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr)
+{
+       json_object             *json_array;
+       json_object             *json_cap;
+
+       /* sent capabilities */
+       json_array = json_object_new_array();
+       json_object_object_add(json_nbr, "sentCapabilities", json_array);
+
+       /* Dynamic Announcement (0x0506) */
+       json_cap = json_object_new_object();
+       json_object_string_add(json_cap, "description", "Dynamic Announcement");
+       json_object_string_add(json_cap, "tlvType", "0x0506");
+       json_object_array_add(json_array, json_cap);
+
+       /* Typed Wildcard (0x050B) */
+       json_cap = json_object_new_object();
+       json_object_string_add(json_cap, "description", "Typed Wildcard");
+       json_object_string_add(json_cap, "tlvType", "0x050B");
+       json_object_array_add(json_array, json_cap);
+
+       /* Unrecognized Notification (0x0603) */
+       json_cap = json_object_new_object();
+       json_object_string_add(json_cap, "description",
+           "Unrecognized Notification");
+       json_object_string_add(json_cap, "tlvType", "0x0603");
+       json_object_array_add(json_array, json_cap);
+
+       /* received capabilities */
+       json_array = json_object_new_array();
+       json_object_object_add(json_nbr, "receivedCapabilities", json_array);
+
+       /* Dynamic Announcement (0x0506) */
+       if (nbr->flags & F_NBR_CAP_DYNAMIC) {
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Dynamic Announcement");
+               json_object_string_add(json_cap, "tlvType", "0x0506");
+               json_object_array_add(json_array, json_cap);
+       }
+
+       /* Typed Wildcard (0x050B) */
+       if (nbr->flags & F_NBR_CAP_TWCARD) {
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Typed Wildcard");
+               json_object_string_add(json_cap, "tlvType", "0x050B");
+               json_object_array_add(json_array, json_cap);
+       }
+
+       /* Unrecognized Notification (0x0603) */
+       if (nbr->flags & F_NBR_CAP_UNOTIF) {
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Unrecognized Notification");
+               json_object_string_add(json_cap, "tlvType", "0x0603");
+               json_object_array_add(json_array, json_cap);
+       }
+}
+
+static int
+show_nbr_capabilities_msg_json(struct imsg *imsg, struct show_params *params,
+    json_object *json)
+{
+       struct ctl_nbr          *nbr;
+       json_object             *json_nbr;
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_NBR:
+               nbr = imsg->data;
+
+               if (nbr->nbr_state != NBR_STA_OPER)
+                       break;
+
+               json_nbr = json_object_new_object();
+               json_object_object_add(json, inet_ntoa(nbr->id), json_nbr);
+               show_nbr_capabilities_json(nbr, json_nbr);
+               break;
+       case IMSG_CTL_END:
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
 static int
 show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
 {
@@ -541,34 +1015,99 @@ show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
        char             dstnet[BUFSIZ];
 
        switch (imsg->hdr.type) {
-       case IMSG_CTL_SHOW_LIB:
+       case IMSG_CTL_SHOW_LIB_BEGIN:
+       case IMSG_CTL_SHOW_LIB_RCVD:
                rt = imsg->data;
 
+               if (imsg->hdr.type == IMSG_CTL_SHOW_LIB_BEGIN &&
+                   !rt->no_downstream)
+                       break;
+
                if (params->family != AF_UNSPEC && params->family != rt->af)
                        break;
 
                snprintf(dstnet, sizeof(dstnet), "%s/%d",
                    log_addr(rt->af, &rt->prefix), rt->prefixlen);
 
-               if (rt->first) {
-                       vty_out(vty, "%s%s", dstnet, VTY_NEWLINE);
-                       vty_out(vty, "%-8sLocal binding: label: %s%s", "",
-                           log_label(rt->local_label), VTY_NEWLINE);
-
-                       if (rt->remote_label != NO_LABEL) {
-                               vty_out(vty, "%-8sRemote bindings:%s", "",
-                                   VTY_NEWLINE);
-                               vty_out(vty, "%-12sPeer                Label%s",
-                                   "", VTY_NEWLINE);
-                               vty_out(vty, "%-12s-----------------   "
-                                   "---------%s", "", VTY_NEWLINE);
-                       } else
-                               vty_out(vty, "%-8sNo remote bindings%s", "",
-                                   VTY_NEWLINE);
+               vty_out(vty, "%-4s %-20s", af_name(rt->af), dstnet);
+               if (strlen(dstnet) > 20)
+                       vty_out(vty, "%s%25s", VTY_NEWLINE, " ");
+               vty_out(vty, " %-15s %-11s %-13s %6s%s", inet_ntoa(rt->nexthop),
+                   log_label(rt->local_label), log_label(rt->remote_label),
+                   rt->in_use ? "yes" : "no", VTY_NEWLINE);
+               break;
+       case IMSG_CTL_END:
+               vty_out(vty, "%s", VTY_NEWLINE);
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
+static int
+show_lib_detail_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
+{
+       struct ctl_rt   *rt = NULL;
+       char             dstnet[BUFSIZ];
+       static int       upstream, downstream;
+       size_t           buflen;
+       static char      sent_buffer[LDPBUFSIZ];
+       static char      rcvd_buffer[LDPBUFSIZ];
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_LIB_BEGIN:
+       case IMSG_CTL_SHOW_LIB_SENT:
+       case IMSG_CTL_SHOW_LIB_RCVD:
+       case IMSG_CTL_SHOW_LIB_END:
+               rt = imsg->data;
+               if (params->family != AF_UNSPEC && params->family != rt->af)
+                       return (0);
+               break;
+       default:
+               break;
+       }
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_LIB_BEGIN:
+               upstream = 0;
+               downstream = 0;
+               sent_buffer[0] = '\0';
+               rcvd_buffer[0] = '\0';
+
+               snprintf(dstnet, sizeof(dstnet), "%s/%d",
+                   log_addr(rt->af, &rt->prefix), rt->prefixlen);
+
+               vty_out(vty, "%s%s", dstnet, VTY_NEWLINE);
+               vty_out(vty, "%-8sLocal binding: label: %s%s", "",
+                   log_label(rt->local_label), VTY_NEWLINE);
+               break;
+       case IMSG_CTL_SHOW_LIB_SENT:
+               upstream = 1;
+               buflen = strlen(sent_buffer);
+               snprintf(sent_buffer + buflen, LDPBUFSIZ - buflen,
+                   "%12s%s:0%s", "", inet_ntoa(rt->nexthop), VTY_NEWLINE);
+               break;
+       case IMSG_CTL_SHOW_LIB_RCVD:
+               downstream = 1;
+               buflen = strlen(rcvd_buffer);
+               snprintf(rcvd_buffer + buflen, LDPBUFSIZ - buflen,
+                   "%12s%s:0, label %s%s%s", "", inet_ntoa(rt->nexthop),
+                   log_label(rt->remote_label),
+                   rt->in_use ? " (in use)" : "", VTY_NEWLINE);
+               break;
+       case IMSG_CTL_SHOW_LIB_END:
+               if (upstream) {
+                       vty_out(vty, "%-8sAdvertised to:%s", "", VTY_NEWLINE);
+                       vty_out(vty, "%s", sent_buffer);
                }
-               if (rt->remote_label != NO_LABEL)
-                       vty_out(vty, "%12s%-20s%s%s", "", inet_ntoa(rt->nexthop),
-                           log_label(rt->remote_label), VTY_NEWLINE);
+               if (downstream) {
+                       vty_out(vty, "%-8sRemote bindings:%s", "", VTY_NEWLINE);
+                       vty_out(vty, "%s", rcvd_buffer);
+               } else
+                       vty_out(vty, "%-8sNo remote bindings%s", "",
+                           VTY_NEWLINE);
                break;
        case IMSG_CTL_END:
                vty_out(vty, "%s", VTY_NEWLINE);
@@ -584,42 +1123,109 @@ static int
 show_lib_msg_json(struct imsg *imsg, struct show_params *params,
     json_object *json)
 {
-       struct ctl_rt           *rt;
+       struct ctl_rt   *rt;
+       json_object     *json_array;
+       json_object     *json_lib_entry;
+       char             dstnet[BUFSIZ];
+
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_LIB_BEGIN:
+       case IMSG_CTL_SHOW_LIB_RCVD:
+               rt = imsg->data;
+
+               if (imsg->hdr.type == IMSG_CTL_SHOW_LIB_BEGIN &&
+                   !rt->no_downstream)
+                       break;
+
+               json_object_object_get_ex(json, "bindings", &json_array);
+               if (!json_array) {
+                       json_array = json_object_new_array();
+                       json_object_object_add(json, "bindings", json_array);
+               }
+
+               json_lib_entry = json_object_new_object();
+               json_object_string_add(json_lib_entry, "addressFamily",
+                   af_name(rt->af));
+               snprintf(dstnet, sizeof(dstnet), "%s/%d",
+                   log_addr(rt->af, &rt->prefix), rt->prefixlen);
+               json_object_string_add(json_lib_entry, "prefix", dstnet);
+               json_object_string_add(json_lib_entry, "neighborId",
+                   inet_ntoa(rt->nexthop));
+               json_object_string_add(json_lib_entry, "localLabel",
+                   log_label(rt->local_label));
+               json_object_string_add(json_lib_entry, "remoteLabel",
+                   log_label(rt->remote_label));
+               json_object_int_add(json_lib_entry, "inUse", rt->in_use);
+
+               json_object_array_add(json_array, json_lib_entry);
+               break;
+       case IMSG_CTL_END:
+               return (1);
+       default:
+               break;
+       }
+
+       return (0);
+}
+
+static int
+show_lib_detail_msg_json(struct imsg *imsg, struct show_params *params,
+    json_object *json)
+{
+       struct ctl_rt           *rt = NULL;
        char                     dstnet[BUFSIZ];
-       static json_object      *json_binding;
+       static json_object      *json_lib_entry;
+       static json_object      *json_adv_labels;
+       json_object             *json_adv_label;
        static json_object      *json_remote_labels;
        json_object             *json_remote_label;
 
        switch (imsg->hdr.type) {
-       case IMSG_CTL_SHOW_LIB:
+       case IMSG_CTL_SHOW_LIB_BEGIN:
+       case IMSG_CTL_SHOW_LIB_SENT:
+       case IMSG_CTL_SHOW_LIB_RCVD:
+       case IMSG_CTL_SHOW_LIB_END:
                rt = imsg->data;
-
                if (params->family != AF_UNSPEC && params->family != rt->af)
-                       break;
+                       return (0);
+               break;
+       default:
+               break;
+       }
 
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_SHOW_LIB_BEGIN:
                snprintf(dstnet, sizeof(dstnet), "%s/%d",
                    log_addr(rt->af, &rt->prefix), rt->prefixlen);
 
-               if (rt->first) {
-                       json_binding = json_object_new_object();
-                       json_object_string_add(json_binding, "localLabel",
-                           log_label(rt->local_label));
+               json_lib_entry = json_object_new_object();
+               json_object_string_add(json_lib_entry, "localLabel",
+                   log_label(rt->local_label));
 
-                       json_remote_labels = json_object_new_array();
-                       json_object_object_add(json_binding, "remoteLabels",
-                           json_remote_labels);
-                       json_object_object_add(json, dstnet, json_binding);
-               }
+               json_adv_labels = json_object_new_array();
+               json_object_object_add(json_lib_entry, "advertisedTo",
+                   json_adv_labels);
 
-               if (rt->remote_label != NO_LABEL) {
-                       json_remote_label = json_object_new_object();
-                       json_object_string_add(json_remote_label, "nexthop",
-                           inet_ntoa(rt->nexthop));
-                       json_object_string_add(json_remote_label, "label",
-                           log_label(rt->remote_label));
-                       json_object_array_add(json_remote_labels,
-                           json_remote_label);
-               }
+               json_remote_labels = json_object_new_array();
+               json_object_object_add(json_lib_entry, "remoteLabels",
+                   json_remote_labels);
+
+               json_object_object_add(json, dstnet, json_lib_entry);
+               break;
+       case IMSG_CTL_SHOW_LIB_SENT:
+               json_adv_label = json_object_new_object();
+               json_object_string_add(json_adv_label, "neighborId",
+                   inet_ntoa(rt->nexthop));
+               json_object_array_add(json_adv_labels, json_adv_label);
+               break;
+       case IMSG_CTL_SHOW_LIB_RCVD:
+               json_remote_label = json_object_new_object();
+               json_object_string_add(json_remote_label, "neighborId",
+                   inet_ntoa(rt->nexthop));
+               json_object_string_add(json_remote_label, "label",
+                   log_label(rt->remote_label));
+               json_object_int_add(json_remote_label, "inUse", rt->in_use);
+               json_object_array_add(json_remote_labels, json_remote_label);
                break;
        case IMSG_CTL_END:
                return (1);
@@ -825,34 +1431,83 @@ static int
 ldp_vty_dispatch_msg(struct vty *vty, struct imsg *imsg, enum show_command cmd,
     struct show_params *params, json_object *json)
 {
+       int      ret;
+
        switch (cmd) {
        case SHOW_IFACE:
-               if (json)
-                       return (show_interface_msg_json(imsg, params, json));
-               return (show_interface_msg(vty, imsg, params));
+               if (params->json)
+                       ret = show_interface_msg_json(imsg, params, json);
+               else
+                       ret = show_interface_msg(vty, imsg, params);
+               break;
        case SHOW_DISC:
-               if (json)
-                       return (show_discovery_msg_json(imsg, params, json));
-               return (show_discovery_msg(vty, imsg, params));
+               if (params->detail) {
+                       if (params->json)
+                               ret = show_discovery_detail_msg_json(imsg,
+                                   params, json);
+                       else
+                               ret = show_discovery_detail_msg(vty, imsg,
+                                   params);
+               } else {
+                       if (params->json)
+                               ret = show_discovery_msg_json(imsg, params,
+                                   json);
+                       else
+                               ret = show_discovery_msg(vty, imsg, params);
+               }
+               break;
        case SHOW_NBR:
-               if (json)
-                       return (show_nbr_msg_json(imsg, params, json));
-               return (show_nbr_msg(vty, imsg, params));
+               if (params->capabilities) {
+                       if (params->json)
+                               ret = show_nbr_capabilities_msg_json(imsg,
+                                   params, json);
+                       else
+                               ret = show_nbr_capabilities_msg(vty, imsg,
+                                   params);
+               } else if (params->detail) {
+                       if (params->json)
+                               ret = show_nbr_detail_msg_json(imsg, params,
+                                   json);
+                       else
+                               ret = show_nbr_detail_msg(vty, imsg, params);
+               } else {
+                       if (params->json)
+                               ret = show_nbr_msg_json(imsg, params, json);
+                       else
+                               ret = show_nbr_msg(vty, imsg, params);
+               }
+               break;
        case SHOW_LIB:
-               if (json)
-                       return (show_lib_msg_json(imsg, params, json));
-               return (show_lib_msg(vty, imsg, params));
+               if (params->detail) {
+                       if (params->json)
+                               ret = show_lib_detail_msg_json(imsg, params,
+                                   json);
+                       else
+                               ret = show_lib_detail_msg(vty, imsg, params);
+               } else {
+                       if (params->json)
+                               ret = show_lib_msg_json(imsg, params, json);
+                       else
+                               ret = show_lib_msg(vty, imsg, params);
+               }
+               break;
        case SHOW_L2VPN_PW:
-               if (json)
-                       return (show_l2vpn_pw_msg_json(imsg, params, json));
-               return (show_l2vpn_pw_msg(vty, imsg, params));
+               if (params->json)
+                       ret = show_l2vpn_pw_msg_json(imsg, params, json);
+               else
+                       ret = show_l2vpn_pw_msg(vty, imsg, params);
+               break;
        case SHOW_L2VPN_BINDING:
-               if (json)
-                       return (show_l2vpn_binding_msg_json(imsg, params, json));
-               return (show_l2vpn_binding_msg(vty, imsg, params));
+               if (params->json)
+                       ret = show_l2vpn_binding_msg_json(imsg, params, json);
+               else
+                       ret = show_l2vpn_binding_msg(vty, imsg, params);
+               break;
        default:
                return (0);
        }
+
+       return (ret);
 }
 
 static int
@@ -944,8 +1599,14 @@ ldp_vty_show_binding(struct vty *vty, struct vty_arg *args[])
 
        memset(&params, 0, sizeof(params));
        params.family = af;
+       params.detail = vty_get_arg_value(args, "detail") ? 1 : 0;
        params.json = vty_get_arg_value(args, "json") ? 1 : 0;
 
+       if (!params.detail && !params.json)
+               vty_out(vty, "%-4s %-20s %-15s %-11s %-13s %6s%s", "AF",
+                   "Destination", "Nexthop", "Local Label", "Remote Label",
+                   "In Use", VTY_NEWLINE);
+
        imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
        return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, &params));
 }
@@ -967,9 +1628,18 @@ ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[])
 
        memset(&params, 0, sizeof(params));
        params.family = af;
+       params.detail = vty_get_arg_value(args, "detail") ? 1 : 0;
        params.json = vty_get_arg_value(args, "json") ? 1 : 0;
 
-       imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
+       if (!params.detail && !params.json)
+               vty_out(vty, "%-4s %-15s %-8s %-15s %9s%s",
+                   "AF", "ID", "Type", "Source", "Holdtime", VTY_NEWLINE);
+
+       if (params.detail)
+               imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY_DTL, 0, 0, -1,
+                   NULL, 0);
+       else
+               imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
        return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, &params));
 }
 
@@ -1005,6 +1675,58 @@ ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[])
        return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, &params));
 }
 
+int
+ldp_vty_show_capabilities(struct vty *vty, struct vty_arg *args[])
+{
+       if (vty_get_arg_value(args, "json")) {
+               json_object     *json;
+               json_object     *json_array;
+               json_object     *json_cap;
+
+               json = json_object_new_object();
+               json_array = json_object_new_array();
+               json_object_object_add(json, "capabilities", json_array);
+
+               /* Dynamic Announcement (0x0506) */
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Dynamic Announcement");
+               json_object_string_add(json_cap, "tlvType",
+                   "0x0506");
+               json_object_array_add(json_array, json_cap);
+
+               /* Typed Wildcard (0x050B) */
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Typed Wildcard");
+               json_object_string_add(json_cap, "tlvType",
+                   "0x050B");
+               json_object_array_add(json_array, json_cap);
+
+               /* Unrecognized Notification (0x0603) */
+               json_cap = json_object_new_object();
+               json_object_string_add(json_cap, "description",
+                   "Unrecognized Notification");
+               json_object_string_add(json_cap, "tlvType",
+                   "0x0603");
+               json_object_array_add(json_array, json_cap);
+
+               vty_out(vty, "%s%s", json_object_to_json_string_ext(json,
+                   JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+               json_object_free(json);
+               return (0);
+       }
+
+       vty_out(vty,
+           "Supported LDP Capabilities%s"
+           " * Dynamic Announcement (0x0506)%s"
+           " * Typed Wildcard (0x050B)%s"
+           " * Unrecognized Notification (0x0603)%s%s", VTY_NEWLINE,
+           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+       return (0);
+}
+
 int
 ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[])
 {
@@ -1015,8 +1737,18 @@ ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[])
                return (CMD_WARNING);
 
        memset(&params, 0, sizeof(params));
+       params.capabilities = vty_get_arg_value(args, "capabilities") ? 1 : 0;
+       params.detail = vty_get_arg_value(args, "detail") ? 1 : 0;
        params.json = vty_get_arg_value(args, "json") ? 1 : 0;
 
+       if (params.capabilities)
+               params.detail = 1;
+
+       if (!params.detail && !params.json)
+               vty_out(vty, "%-4s %-15s %-11s %-15s %8s%s",
+                   "AF", "ID", "State", "Remote Address", "Uptime",
+                   VTY_NEWLINE);
+
        imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
        return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &params));
 }
index c41a0dbd9151516dbfd447946d24c10cbe797b97..702b5c5eaaf5203a37335b5007a628bb105e4460 100644 (file)
@@ -180,7 +180,7 @@ kif_redistribute(const char *ifname)
                        continue;
 
                ifp2kif(ifp, &kif);
-               main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+               main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
 
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
                        ifc2kaddr(ifp, ifc, &ka);
@@ -222,7 +222,7 @@ ldp_interface_add(int command, struct zclient *zclient, zebra_size_t length,
            ifp->ifindex, ifp->mtu);
 
        ifp2kif(ifp, &kif);
-       main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+       main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
 
        return (0);
 }
@@ -270,7 +270,7 @@ ldp_interface_status_change(int command, struct zclient *zclient,
        debug_zebra_in("interface %s state update", ifp->name);
 
        ifp2kif(ifp, &kif);
-       main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
+       main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
 
        link_new = (ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING);
        if (link_new) {
index 98ea5ca53e2116db8048c9050d3a80a6a7eb5204..9729499e284cc5f89054a76ee4445aa573840f17 100644 (file)
@@ -45,7 +45,7 @@
 
 static void             ldpd_shutdown(void);
 static pid_t            start_child(enum ldpd_process, char *, int, int,
-                           const char *, const char *, const char *);
+                           const char *, const char *, const char *, const char *);
 static int              main_dispatch_ldpe(struct thread *);
 static int              main_dispatch_lde(struct thread *);
 static int              main_imsg_send_ipc_sockets(struct imsgbuf *,
@@ -53,20 +53,20 @@ static int           main_imsg_send_ipc_sockets(struct imsgbuf *,
 static void             main_imsg_send_net_sockets(int);
 static void             main_imsg_send_net_socket(int, enum socket_type);
 static int              main_imsg_send_config(struct ldpd_conf *);
-static void             ldp_config_normalize(struct ldpd_conf *, void **);
-static void             ldp_config_reset_main(struct ldpd_conf *, void **);
-static void             ldp_config_reset_af(struct ldpd_conf *, int, void **);
-static void             merge_config_ref(struct ldpd_conf *, struct ldpd_conf *, void **);
+static void             ldp_config_normalize(struct ldpd_conf *);
+static void             ldp_config_reset_main(struct ldpd_conf *);
+static void             ldp_config_reset_af(struct ldpd_conf *, int);
+static void             ldp_config_reset_l2vpns(struct ldpd_conf *);
 static void             merge_global(struct ldpd_conf *, struct ldpd_conf *);
 static void             merge_af(int, struct ldpd_af_conf *,
                            struct ldpd_af_conf *);
-static void             merge_ifaces(struct ldpd_conf *, struct ldpd_conf *, void **);
+static void             merge_ifaces(struct ldpd_conf *, struct ldpd_conf *);
 static void             merge_iface_af(struct iface_af *, struct iface_af *);
-static void             merge_tnbrs(struct ldpd_conf *, struct ldpd_conf *, void **);
-static void             merge_nbrps(struct ldpd_conf *, struct ldpd_conf *, void **);
-static void             merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *, void **);
+static void             merge_tnbrs(struct ldpd_conf *, struct ldpd_conf *);
+static void             merge_nbrps(struct ldpd_conf *, struct ldpd_conf *);
+static void             merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *);
 static void             merge_l2vpn(struct ldpd_conf *, struct l2vpn *,
-                           struct l2vpn *, void **);
+                           struct l2vpn *);
 
 DEFINE_QOBJ_TYPE(iface)
 DEFINE_QOBJ_TYPE(tnbr)
@@ -77,7 +77,7 @@ DEFINE_QOBJ_TYPE(l2vpn)
 DEFINE_QOBJ_TYPE(ldpd_conf)
 
 struct ldpd_global      global;
-struct ldpd_conf       *ldpd_conf;
+struct ldpd_conf       *ldpd_conf, *vty_conf;
 
 static struct imsgev   *iev_ldpe, *iev_ldpe_sync;
 static struct imsgev   *iev_lde, *iev_lde_sync;
@@ -90,6 +90,8 @@ static pid_t           lde_pid;
 /* Master of threads. */
 struct thread_master *master;
 
+static struct frr_daemon_info ldpd_di;
+
 /* ldpd privileges */
 static zebra_capabilities_t _caps_p [] =
 {
@@ -119,6 +121,7 @@ char ctl_sock_path[MAXPATHLEN] = LDPD_SOCKET;
 static struct option longopts[] =
 {
        { "ctl_socket",  required_argument, NULL, OPTION_CTLSOCK},
+       { "instance",    required_argument, NULL, 'n'},
        { 0 }
 };
 
@@ -127,6 +130,21 @@ static void
 sighup(void)
 {
        log_info("SIGHUP received");
+
+       /* reset vty_conf */
+       ldp_config_reset_main(vty_conf);
+       ldp_config_reset_l2vpns(vty_conf);
+
+       /* read configuration file without applying any changes */
+       global.sighup = 1;
+       vty_read_config(ldpd_di.config_file, config_default);
+       global.sighup = 0;
+
+       /*
+        * Apply the new configuration all at once, this way merge_config()
+        * will be the least disruptive as possible.
+        */
+       ldp_reload(vty_conf);
 }
 
 /* SIGINT / SIGTERM handler. */
@@ -186,6 +204,8 @@ main(int argc, char *argv[])
        char                    *ctl_sock_name;
        const char              *user = NULL;
        const char              *group = NULL;
+       u_short                  instance = 0;
+       const char              *instance_char = NULL;
 
        ldpd_process = PROC_MAIN;
 
@@ -194,8 +214,9 @@ main(int argc, char *argv[])
                saved_argv0 = (char *)"ldpd";
 
        frr_preinit(&ldpd_di, argc, argv);
-       frr_opt_add("LE", longopts,
-               "      --ctl_socket   Override ctl socket path\n");
+       frr_opt_add("LEn:", longopts,
+               "      --ctl_socket   Override ctl socket path\n"
+               "-n,   --instance     Instance id\n");
 
        while (1) {
                int opt;
@@ -227,6 +248,12 @@ main(int argc, char *argv[])
                        strlcat(ctl_sock_path, ctl_sock_name,
                            sizeof(ctl_sock_path));
                        break;
+               case 'n':
+                       instance = atoi(optarg);
+                       instance_char = optarg;
+                       if (instance < 1)
+                               exit(0);
+                       break;
                case 'L':
                        lflag = 1;
                        break;
@@ -254,31 +281,13 @@ main(int argc, char *argv[])
                exit(1);
        }
 
-       openzlog(ldpd_di.progname, "LDP", 0,
-           LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-
        if (lflag)
-               lde(user, group);
+               lde(user, group, instance);
        else if (eflag)
                ldpe(user, group, ctl_sock_path);
 
-       master = thread_master_create();
-
-       cmd_init(1);
-       vty_config_lockless ();
-       vty_init(master);
-       vrf_init();
-       access_list_init ();
-       ldp_vty_init();
-       ldp_vty_if_init();
-
-       /* Get configuration file. */
-       ldpd_conf = config_new_empty();
-       ldp_config_reset_main(ldpd_conf, NULL);
-
-       frr_config_fork();
-
-       QOBJ_REG (ldpd_conf, ldpd_conf);
+       openzlog(ldpd_di.progname, "LDP", 0,
+           LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
 
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)
                fatal("socketpair");
@@ -308,10 +317,10 @@ main(int argc, char *argv[])
        /* start children */
        lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
            pipe_parent2lde[1], pipe_parent2lde_sync[1],
-           user, group, ctl_sock_custom_path);
+           user, group, ctl_sock_custom_path, instance_char);
        ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
            pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1],
-           user, group, ctl_sock_custom_path);
+           user, group, ctl_sock_custom_path, instance_char);
 
        /* drop privileges */
        zprivs_init(&ldpd_privs);
@@ -319,9 +328,34 @@ main(int argc, char *argv[])
        /* setup signal handler */
        signal_init(master, array_size(ldp_signals), ldp_signals);
 
+       /* thread master */
+       master = thread_master_create();
+
        /* library inits */
+       cmd_init(1);
+       vty_config_lockless();
+       vty_init(master);
+       vrf_init();
+       access_list_init();
+       ldp_vty_init();
        ldp_zebra_init(master);
 
+       /* create base configuration with sane defaults */
+       ldpd_conf = config_new_empty();
+       ldp_config_reset_main(ldpd_conf);
+
+       /*
+        * Create vty_conf as a duplicate of the main configuration. All
+        * configuration requests (e.g. CLI) act on vty_conf and then call
+        * ldp_reload() to merge the changes into ldpd_conf.
+        */
+       vty_conf = config_new_empty();
+       ldp_config_reset_main(vty_conf);
+       QOBJ_REG(vty_conf, ldpd_conf);
+
+       /* read configuration file and daemonize  */
+       frr_config_fork();
+
        /* setup pipes to children */
        if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL ||
            (iev_ldpe_sync = calloc(1, sizeof(struct imsgev))) == NULL ||
@@ -383,6 +417,11 @@ ldpd_shutdown(void)
 
        config_clear(ldpd_conf);
 
+       ldp_config_reset_main(vty_conf);
+       ldp_config_reset_l2vpns(vty_conf);
+       QOBJ_UNREG(vty_conf);
+       free(vty_conf);
+
        log_debug("waiting for children to terminate");
        do {
                pid = wait(&status);
@@ -414,9 +453,10 @@ ldpd_shutdown(void)
 
 static pid_t
 start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
-    const char *user, const char *group, const char *ctl_sock_custom_path)
+    const char *user, const char *group, const char *ctl_sock_custom_path,
+    const char *instance)
 {
-       char    *argv[9];
+       char    *argv[13];
        int      argc = 0;
        pid_t    pid;
 
@@ -459,6 +499,14 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
                argv[argc++] = (char *)"--ctl_socket";
                argv[argc++] = (char *)ctl_sock_custom_path;
        }
+       /* zclient serv path */
+       argv[argc++] = (char *)"-z";
+       argv[argc++] = (char *)zclient_serv_path_get();
+       /* instance */
+       if (instance) {
+               argv[argc++] = (char *)"-n";
+               argv[argc++] = (char *)instance;
+       }
        argv[argc++] = NULL;
 
        execvp(argv0, argv);
@@ -937,80 +985,106 @@ main_imsg_send_config(struct ldpd_conf *xconf)
 }
 
 int
-ldp_reload_ref(struct ldpd_conf *xconf, void **ref)
+ldp_reload(struct ldpd_conf *xconf)
 {
-       ldp_config_normalize(xconf, ref);
+       if (global.sighup)
+               return (0);
+
+       ldp_config_normalize(xconf);
 
        if (main_imsg_send_config(xconf) == -1)
                return (-1);
 
-       merge_config_ref(ldpd_conf, xconf, ref);
+       merge_config(ldpd_conf, xconf);
 
        return (0);
 }
 
-int
-ldp_reload(struct ldpd_conf *xconf)
-{
-       return ldp_reload_ref(xconf, NULL);
-}
-
 static void
-ldp_config_normalize(struct ldpd_conf *xconf, void **ref)
+ldp_config_normalize(struct ldpd_conf *xconf)
 {
+       struct iface            *iface, *itmp;
+       struct nbr_params       *nbrp, *ntmp;
        struct l2vpn            *l2vpn;
-       struct l2vpn_pw         *pw;
+       struct l2vpn_pw         *pw, *ptmp;
 
        if (!(xconf->flags & F_LDPD_ENABLED))
-               ldp_config_reset_main(xconf, ref);
+               ldp_config_reset_main(xconf);
        else {
                if (!(xconf->ipv4.flags & F_LDPD_AF_ENABLED))
-                       ldp_config_reset_af(xconf, AF_INET, ref);
+                       ldp_config_reset_af(xconf, AF_INET);
                if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED))
-                       ldp_config_reset_af(xconf, AF_INET6, ref);
-       }
+                       ldp_config_reset_af(xconf, AF_INET6);
 
-       RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
-                       if (pw->flags & F_PW_STATIC_NBR_ADDR)
+               RB_FOREACH_SAFE(iface, iface_head, &xconf->iface_tree, itmp) {
+                       if (iface->ipv4.enabled || iface->ipv6.enabled)
                                continue;
 
-                       pw->af = AF_INET;
-                       pw->addr.v4 = pw->lsr_id;
+                       QOBJ_UNREG(iface);
+                       RB_REMOVE(iface_head, &vty_conf->iface_tree, iface);
+                       free(iface);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) {
-                       if (pw->flags & F_PW_STATIC_NBR_ADDR)
+
+               RB_FOREACH_SAFE(nbrp, nbrp_head, &xconf->nbrp_tree, ntmp) {
+                       if (nbrp->flags & (F_NBRP_KEEPALIVE|F_NBRP_GTSM))
+                               continue;
+                       if (nbrp->auth.method != AUTH_NONE)
                                continue;
 
-                       pw->af = AF_INET;
-                       pw->addr.v4 = pw->lsr_id;
+                       QOBJ_UNREG(nbrp);
+                       RB_REMOVE(nbrp_head, &vty_conf->nbrp_tree, nbrp);
+                       free(nbrp);
+               }
+       }
+
+       RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
+               RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) {
+                       if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+                               pw->af = AF_INET;
+                               pw->addr.v4 = pw->lsr_id;
+                       }
+
+                       if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0)
+                               continue;
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+               }
+               RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree,
+                   ptmp) {
+                       if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+                               pw->af = AF_INET;
+                               pw->addr.v4 = pw->lsr_id;
+                       }
+
+                       if (pw->lsr_id.s_addr == INADDR_ANY || pw->pwid == 0)
+                               continue;
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
                }
        }
 }
 
 static void
-ldp_config_reset_main(struct ldpd_conf *conf, void **ref)
+ldp_config_reset_main(struct ldpd_conf *conf)
 {
        struct iface            *iface;
        struct nbr_params       *nbrp;
 
        while ((iface = RB_ROOT(&conf->iface_tree)) != NULL) {
-               if (ref && *ref == iface)
-                       *ref = NULL;
+               QOBJ_UNREG(iface);
                RB_REMOVE(iface_head, &conf->iface_tree, iface);
                free(iface);
        }
 
        while ((nbrp = RB_ROOT(&conf->nbrp_tree)) != NULL) {
-               if (ref && *ref == nbrp)
-                       *ref = NULL;
+               QOBJ_UNREG(nbrp);
                RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp);
                free(nbrp);
        }
 
        conf->rtr_id.s_addr = INADDR_ANY;
-       ldp_config_reset_af(conf, AF_INET, ref);
-       ldp_config_reset_af(conf, AF_INET6, ref);
+       ldp_config_reset_af(conf, AF_INET);
+       ldp_config_reset_af(conf, AF_INET6);
        conf->lhello_holdtime = LINK_DFLT_HOLDTIME;
        conf->lhello_interval = DEFAULT_HELLO_INTERVAL;
        conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
@@ -1020,7 +1094,7 @@ ldp_config_reset_main(struct ldpd_conf *conf, void **ref)
 }
 
 static void
-ldp_config_reset_af(struct ldpd_conf *conf, int af, void **ref)
+ldp_config_reset_af(struct ldpd_conf *conf, int af)
 {
        struct ldpd_af_conf     *af_conf;
        struct iface            *iface;
@@ -1036,8 +1110,7 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af, void **ref)
                if (tnbr->af != af)
                        continue;
 
-               if (ref && *ref == tnbr)
-                       *ref = NULL;
+               QOBJ_UNREG(tnbr);
                RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
                free(tnbr);
        }
@@ -1052,77 +1125,33 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af, void **ref)
        af_conf->flags = 0;
 }
 
-struct ldpd_conf *
-ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
+static void
+ldp_config_reset_l2vpns(struct ldpd_conf *conf)
 {
-       struct ldpd_conf        *xconf;
-       struct iface            *iface, *xi;
-       struct tnbr             *tnbr, *xt;
-       struct nbr_params       *nbrp, *xn;
-       struct l2vpn            *l2vpn, *xl;
-       struct l2vpn_if         *lif, *xf;
-       struct l2vpn_pw         *pw, *xp;
-
-#define COPY(a, b) do { \
-               a = calloc(1, sizeof(*a)); \
-               if (a == NULL) \
-                       fatal(__func__); \
-               *a = *b; \
-               if (ref && *ref == b) *ref = a; \
-       } while (0)
-
-       COPY(xconf, conf);
-       RB_INIT(&xconf->iface_tree);
-       RB_INIT(&xconf->tnbr_tree);
-       RB_INIT(&xconf->nbrp_tree);
-       RB_INIT(&xconf->l2vpn_tree);
-
-       RB_FOREACH(iface, iface_head, &conf->iface_tree) {
-               COPY(xi, iface);
-               xi->ipv4.iface = xi;
-               xi->ipv6.iface = xi;
-               RB_INSERT(iface_head, &xconf->iface_tree, xi);
-       }
-       RB_FOREACH(tnbr, tnbr_head, &conf->tnbr_tree) {
-               COPY(xt, tnbr);
-               RB_INSERT(tnbr_head, &xconf->tnbr_tree, xt);
-       }
-       RB_FOREACH(nbrp, nbrp_head, &conf->nbrp_tree) {
-               COPY(xn, nbrp);
-               RB_INSERT(nbrp_head, &xconf->nbrp_tree, xn);
-       }
-       RB_FOREACH(l2vpn, l2vpn_head, &conf->l2vpn_tree) {
-               COPY(xl, l2vpn);
-               RB_INIT(&xl->if_tree);
-               RB_INIT(&xl->pw_tree);
-               RB_INIT(&xl->pw_inactive_tree);
-               RB_INSERT(l2vpn_head, &xconf->l2vpn_tree, xl);
+       struct l2vpn            *l2vpn;
+       struct l2vpn_if         *lif;
+       struct l2vpn_pw         *pw;
 
-               RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) {
-                       COPY(xf, lif);
-                       xf->l2vpn = xl;
-                       RB_INSERT(l2vpn_if_head, &xl->if_tree, xf);
+       while ((l2vpn = RB_ROOT(&conf->l2vpn_tree)) != NULL) {
+               while ((lif = RB_ROOT(&l2vpn->if_tree)) != NULL) {
+                       QOBJ_UNREG(lif);
+                       RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
+                       free(lif);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
-                       COPY(xp, pw);
-                       xp->l2vpn = xl;
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_tree, xp);
+               while ((pw = RB_ROOT(&l2vpn->pw_tree)) != NULL) {
+                       QOBJ_UNREG(pw);
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       free(pw);
                }
-               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) {
-                       COPY(xp, pw);
-                       xp->l2vpn = xl;
-                       RB_INSERT(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
+               while ((pw = RB_ROOT(&l2vpn->pw_inactive_tree)) != NULL) {
+                       QOBJ_UNREG(pw);
+                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       free(pw);
                }
+               QOBJ_UNREG(l2vpn);
+               RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
+               free(l2vpn);
        }
-#undef COPY
-
-       return (xconf);
-}
-
-struct ldpd_conf *
-ldp_dup_config(struct ldpd_conf *conf)
-{
-       return ldp_dup_config_ref(conf, NULL);
 }
 
 void
@@ -1153,25 +1182,23 @@ ldp_clear_config(struct ldpd_conf *xconf)
        free(xconf);
 }
 
-static void
-merge_config_ref(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
-{
-       merge_global(conf, xconf);
-       merge_af(AF_INET, &conf->ipv4, &xconf->ipv4);
-       merge_af(AF_INET6, &conf->ipv6, &xconf->ipv6);
-       merge_ifaces(conf, xconf, ref);
-       merge_tnbrs(conf, xconf, ref);
-       merge_nbrps(conf, xconf, ref);
-       merge_l2vpns(conf, xconf, ref);
-       if (ref && *ref == xconf)
-               *ref = conf;
-       free(xconf);
-}
+#define COPY(a, b) do { \
+               a = malloc(sizeof(*a)); \
+               if (a == NULL) \
+                       fatal(__func__); \
+               *a = *b; \
+       } while (0)
 
 void
 merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
-       merge_config_ref(conf, xconf, NULL);
+       merge_global(conf, xconf);
+       merge_af(AF_INET, &conf->ipv4, &xconf->ipv4);
+       merge_af(AF_INET6, &conf->ipv6, &xconf->ipv6);
+       merge_ifaces(conf, xconf);
+       merge_tnbrs(conf, xconf);
+       merge_nbrps(conf, xconf);
+       merge_l2vpns(conf, xconf);
 }
 
 static void
@@ -1308,38 +1335,41 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
 }
 
 static void
-merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
+merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
        struct iface            *iface, *itmp, *xi;
 
        RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
                /* find deleted interfaces */
                if ((xi = if_lookup_name(xconf, iface->name)) == NULL) {
-                       RB_REMOVE(iface_head, &conf->iface_tree, iface);
-
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               if_exit(iface);
+                               ldpe_if_exit(iface);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_UNREG (iface);
                                break;
                        }
+                       RB_REMOVE(iface_head, &conf->iface_tree, iface);
                        free(iface);
                }
        }
        RB_FOREACH_SAFE(xi, iface_head, &xconf->iface_tree, itmp) {
                /* find new interfaces */
                if ((iface = if_lookup_name(conf, xi->name)) == NULL) {
-                       RB_REMOVE(iface_head, &xconf->iface_tree, xi);
-                       RB_INSERT(iface_head, &conf->iface_tree, xi);
+                       COPY(iface, xi);
+                       RB_INSERT(iface_head, &conf->iface_tree, iface);
 
-                       if (ldpd_process == PROC_MAIN) {
-                               QOBJ_REG (xi, iface);
+                       switch (ldpd_process) {
+                       case PROC_LDP_ENGINE:
+                               ldpe_if_init(iface);
+                               break;
+                       case PROC_LDE_ENGINE:
+                               break;
+                       case PROC_MAIN:
                                /* resend addresses to activate new interfaces */
-                               kif_redistribute(xi->name);
+                               kif_redistribute(iface->name);
+                               break;
                        }
                        continue;
                }
@@ -1347,10 +1377,6 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                /* update existing interfaces */
                merge_iface_af(&iface->ipv4, &xi->ipv4);
                merge_iface_af(&iface->ipv6, &xi->ipv6);
-               RB_REMOVE(iface_head, &xconf->iface_tree, xi);
-               if (ref && *ref == xi)
-                       *ref = iface;
-               free(xi);
        }
 }
 
@@ -1360,14 +1386,14 @@ merge_iface_af(struct iface_af *ia, struct iface_af *xi)
        if (ia->enabled != xi->enabled) {
                ia->enabled = xi->enabled;
                if (ldpd_process == PROC_LDP_ENGINE)
-                       if_update(ia->iface, ia->af);
+                       ldp_if_update(ia->iface, ia->af);
        }
        ia->hello_holdtime = xi->hello_holdtime;
        ia->hello_interval = xi->hello_interval;
 }
 
 static void
-merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
+merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
        struct tnbr             *tnbr, *ttmp, *xt;
 
@@ -1378,17 +1404,13 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                /* find deleted tnbrs */
                if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) {
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
-                               free(tnbr);
-                               break;
                        case PROC_LDP_ENGINE:
                                tnbr->flags &= ~F_TNBR_CONFIGURED;
                                tnbr_check(conf, tnbr);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
                                RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
-                               QOBJ_UNREG (tnbr);
                                free(tnbr);
                                break;
                        }
@@ -1397,17 +1419,15 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
        RB_FOREACH_SAFE(xt, tnbr_head, &xconf->tnbr_tree, ttmp) {
                /* find new tnbrs */
                if ((tnbr = tnbr_find(conf, xt->af, &xt->addr)) == NULL) {
-                       RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
-                       RB_INSERT(tnbr_head, &conf->tnbr_tree, xt);
+                       COPY(tnbr, xt);
+                       RB_INSERT(tnbr_head, &conf->tnbr_tree, tnbr);
 
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               tnbr_update(xt);
+                               tnbr_update(tnbr);
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_REG (xt, tnbr);
                                break;
                        }
                        continue;
@@ -1416,15 +1436,11 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                /* update existing tnbrs */
                if (!(tnbr->flags & F_TNBR_CONFIGURED))
                        tnbr->flags |= F_TNBR_CONFIGURED;
-               RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
-               if (ref && *ref == xt)
-                       *ref = tnbr;
-               free(xt);
        }
 }
 
 static void
-merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
+merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
        struct nbr_params       *nbrp, *ntmp, *xn;
        struct nbr              *nbr;
@@ -1434,8 +1450,6 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                /* find deleted nbrps */
                if ((xn = nbr_params_find(xconf, nbrp->lsr_id)) == NULL) {
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
                                nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
                                if (nbr) {
@@ -1448,12 +1462,13 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                                            nbr->af))->ldp_session_socket,
                                            nbr->af, &nbr->raddr, NULL);
 #endif
+                                       nbr->auth.method = AUTH_NONE;
                                        if (nbr_session_active_role(nbr))
                                                nbr_establish_connection(nbr);
                                }
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_UNREG (nbrp);
                                break;
                        }
                        RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp);
@@ -1463,32 +1478,31 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
        RB_FOREACH_SAFE(xn, nbrp_head, &xconf->nbrp_tree, ntmp) {
                /* find new nbrps */
                if ((nbrp = nbr_params_find(conf, xn->lsr_id)) == NULL) {
-                       RB_REMOVE(nbrp_head, &xconf->nbrp_tree, xn);
-                       RB_INSERT(nbrp_head, &conf->nbrp_tree, xn);
+                       COPY(nbrp, xn);
+                       RB_INSERT(nbrp_head, &conf->nbrp_tree, nbrp);
 
                        switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               break;
                        case PROC_LDP_ENGINE:
-                               nbr = nbr_find_ldpid(xn->lsr_id.s_addr);
+                               nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
                                if (nbr) {
                                        session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+                                       nbr->auth.method = nbrp->auth.method;
 #ifdef __OpenBSD__
-                                       if (pfkey_establish(nbr, xn) == -1)
+                                       if (pfkey_establish(nbr, nbrp) == -1)
                                                fatalx("pfkey setup failed");
 #else
                                        sock_set_md5sig(
                                            (ldp_af_global_get(&global,
                                            nbr->af))->ldp_session_socket,
                                            nbr->af, &nbr->raddr,
-                                           xn->auth.md5key);
+                                           nbrp->auth.md5key);
 #endif
                                        if (nbr_session_active_role(nbr))
                                                nbr_establish_connection(nbr);
                                }
                                break;
+                       case PROC_LDE_ENGINE:
                        case PROC_MAIN:
-                               QOBJ_REG (xn, nbr_params);
                                break;
                        }
                        continue;
@@ -1520,9 +1534,11 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                                session_shutdown(nbr, S_SHUTDOWN, 0, 0);
 #ifdef __OpenBSD__
                                pfkey_remove(nbr);
+                               nbr->auth.method = nbrp->auth.method;
                                if (pfkey_establish(nbr, nbrp) == -1)
                                        fatalx("pfkey setup failed");
 #else
+                               nbr->auth.method = nbrp->auth.method;
                                sock_set_md5sig((ldp_af_global_get(&global,
                                    nbr->af))->ldp_session_socket, nbr->af,
                                    &nbr->raddr, nbrp->auth.md5key);
@@ -1531,25 +1547,17 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                                        nbr_establish_connection(nbr);
                        }
                }
-               RB_REMOVE(nbrp_head, &xconf->nbrp_tree, xn);
-               if (ref && *ref == xn)
-                       *ref = nbrp;
-               free(xn);
        }
 }
 
 static void
-merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
+merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf)
 {
        struct l2vpn            *l2vpn, *ltmp, *xl;
-       struct l2vpn_if         *lif;
-       struct l2vpn_pw         *pw;
 
        RB_FOREACH_SAFE(l2vpn, l2vpn_head, &conf->l2vpn_tree, ltmp) {
                /* find deleted l2vpns */
                if ((xl = l2vpn_find(xconf, l2vpn->name)) == NULL) {
-                       RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
-
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
                                l2vpn_exit(l2vpn);
@@ -1558,55 +1566,45 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                                ldpe_l2vpn_exit(l2vpn);
                                break;
                        case PROC_MAIN:
-                               RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
-                                       QOBJ_UNREG (lif);
-                               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree)
-                                       QOBJ_UNREG (pw);
-                               RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree)
-                                       QOBJ_UNREG (pw);
-                               QOBJ_UNREG (l2vpn);
                                break;
                        }
+                       RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
                        l2vpn_del(l2vpn);
                }
        }
        RB_FOREACH_SAFE(xl, l2vpn_head, &xconf->l2vpn_tree, ltmp) {
                /* find new l2vpns */
                if ((l2vpn = l2vpn_find(conf, xl->name)) == NULL) {
-                       RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
-                       RB_INSERT(l2vpn_head, &conf->l2vpn_tree, xl);
+                       COPY(l2vpn, xl);
+                       RB_INSERT(l2vpn_head, &conf->l2vpn_tree, l2vpn);
+                       RB_INIT(&l2vpn->if_tree);
+                       RB_INIT(&l2vpn->pw_tree);
+                       RB_INIT(&l2vpn->pw_inactive_tree);
 
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
-                               l2vpn_init(xl);
+                               l2vpn_init(l2vpn);
                                break;
                        case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_init(xl);
+                               ldpe_l2vpn_init(l2vpn);
                                break;
                        case PROC_MAIN:
-                               QOBJ_REG (xl, l2vpn);
                                break;
                        }
-                       continue;
                }
 
                /* update existing l2vpns */
-               merge_l2vpn(conf, l2vpn, xl, ref);
-               RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
-               if (ref && *ref == xl)
-                       *ref = l2vpn;
-               free(xl);
+               merge_l2vpn(conf, l2vpn, xl);
        }
 }
 
 static void
-merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void **ref)
+merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
 {
        struct l2vpn_if         *lif, *ftmp, *xf;
        struct l2vpn_pw         *pw, *ptmp, *xp;
        struct nbr              *nbr;
        int                      reset_nbr, reinstall_pwfec, reinstall_tnbr;
-       struct l2vpn_pw_head     pw_aux_list;
        int                      previous_pw_type, previous_mtu;
 
        previous_pw_type = l2vpn->pw_type;
@@ -1615,35 +1613,33 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
        /* merge intefaces */
        RB_FOREACH_SAFE(lif, l2vpn_if_head, &l2vpn->if_tree, ftmp) {
                /* find deleted interfaces */
-               if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) {
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_UNREG (lif);
+               if ((xf = l2vpn_if_find(xl, lif->ifname)) == NULL) {
                        RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
                        free(lif);
                }
        }
        RB_FOREACH_SAFE(xf, l2vpn_if_head, &xl->if_tree, ftmp) {
                /* find new interfaces */
-               if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
-                       RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, xf);
-                       xf->l2vpn = l2vpn;
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_REG (xf, l2vpn_if);
-                       continue;
-               }
+               if ((lif = l2vpn_if_find(l2vpn, xf->ifname)) == NULL) {
+                       COPY(lif, xf);
+                       RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
+                       lif->l2vpn = l2vpn;
 
-               RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
-               if (ref && *ref == xf)
-                       *ref = lif;
-               free(xf);
+                       switch (ldpd_process) {
+                       case PROC_LDP_ENGINE:
+                       case PROC_LDE_ENGINE:
+                               break;
+                       case PROC_MAIN:
+                               kif_redistribute(lif->ifname);
+                               break;
+                       }
+               }
        }
 
        /* merge active pseudowires */
-       RB_INIT(&pw_aux_list);
        RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) {
                /* find deleted active pseudowires */
-               if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) {
+               if ((xp = l2vpn_pw_find_active(xl, pw->ifname)) == NULL) {
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
                                l2vpn_pw_exit(pw);
@@ -1652,7 +1648,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
                                ldpe_l2vpn_pw_exit(pw);
                                break;
                        case PROC_MAIN:
-                               QOBJ_UNREG (pw);
                                break;
                        }
 
@@ -1662,20 +1657,20 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
        }
        RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_tree, ptmp) {
                /* find new active pseudowires */
-               if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, xp);
-                       xp->l2vpn = l2vpn;
+               if ((pw = l2vpn_pw_find_active(l2vpn, xp->ifname)) == NULL) {
+                       COPY(pw, xp);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
+                       pw->l2vpn = l2vpn;
 
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
-                               l2vpn_pw_init(xp);
+                               l2vpn_pw_init(pw);
                                break;
                        case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_pw_init(xp);
+                               ldpe_l2vpn_pw_init(pw);
                                break;
                        case PROC_MAIN:
-                               QOBJ_REG (xp, l2vpn_pw);
+                               kif_redistribute(pw->ifname);
                                break;
                        }
                        continue;
@@ -1702,28 +1697,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
                else
                        reinstall_pwfec = 0;
 
-               /* check if the pseudowire should be disabled */
-               if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0) {
-                       reinstall_tnbr = 0;
-                       reset_nbr = 0;
-                       reinstall_pwfec = 0;
-
-                       switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               l2vpn_pw_exit(pw);
-                               break;
-                       case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_pw_exit(pw);
-                               break;
-                       case PROC_MAIN:
-                               break;
-                       }
-
-                       /* remove from active list */
-                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
-                       RB_INSERT(l2vpn_pw_head, &pw_aux_list, pw);
-               }
-
                if (ldpd_process == PROC_LDP_ENGINE) {
                        if (reinstall_tnbr)
                                ldpe_l2vpn_pw_exit(pw);
@@ -1764,31 +1737,31 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
                        l2vpn->pw_type = previous_pw_type;
                        l2vpn->mtu = previous_mtu;
                }
-
-               RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
-               if (ref && *ref == xp)
-                       *ref = pw;
-               free(xp);
        }
 
        /* merge inactive pseudowires */
        RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree, ptmp) {
                /* find deleted inactive pseudowires */
-               if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) {
+               if ((xp = l2vpn_pw_find_inactive(xl, pw->ifname)) == NULL) {
                        RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_UNREG (pw);
                        free(pw);
                }
        }
        RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_inactive_tree, ptmp) {
                /* find new inactive pseudowires */
-               if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) {
-                       RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, xp);
-                       xp->l2vpn = l2vpn;
-                       if (ldpd_process == PROC_MAIN)
-                               QOBJ_REG (xp, l2vpn_pw);
+               if ((pw = l2vpn_pw_find_inactive(l2vpn, xp->ifname)) == NULL) {
+                       COPY(pw, xp);
+                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
+                       pw->l2vpn = l2vpn;
+
+                       switch (ldpd_process) {
+                       case PROC_LDE_ENGINE:
+                       case PROC_LDP_ENGINE:
+                               break;
+                       case PROC_MAIN:
+                               kif_redistribute(pw->ifname);
+                               break;
+                       }
                        continue;
                }
 
@@ -1800,35 +1773,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
                strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname));
                pw->ifindex = xp->ifindex;
                pw->flags = xp->flags;
-
-               /* check if the pseudowire should be activated */
-               if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0) {
-                       /* remove from inactive list */
-                       RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
-                       RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
-
-                       switch (ldpd_process) {
-                       case PROC_LDE_ENGINE:
-                               l2vpn_pw_init(pw);
-                               break;
-                       case PROC_LDP_ENGINE:
-                               ldpe_l2vpn_pw_init(pw);
-                               break;
-                       case PROC_MAIN:
-                               break;
-                       }
-               }
-
-               RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
-               if (ref && *ref == xp)
-                       *ref = pw;
-               free(xp);
-       }
-
-       /* insert pseudowires that were disabled in the inactive list */
-       RB_FOREACH_SAFE(pw, l2vpn_pw_head, &pw_aux_list, ptmp) {
-               RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
-               RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
        }
 
        l2vpn->pw_type = xl->pw_type;
@@ -1872,7 +1816,6 @@ config_clear(struct ldpd_conf *conf)
        xconf->trans_pref = conf->trans_pref;
        xconf->flags = conf->flags;
        merge_config(conf, xconf);
-       if (ldpd_process == PROC_MAIN)
-               QOBJ_UNREG (conf);
+       free(xconf);
        free(conf);
 }
index 0a7e1177bc54f468d1c185672cccaee3ee3e7a31..d2fc5aa3afe8be4d12c0dfacfbd00ec843597e0a 100644 (file)
@@ -77,6 +77,7 @@ enum imsg_type {
        IMSG_CTL_RELOAD,
        IMSG_CTL_SHOW_INTERFACE,
        IMSG_CTL_SHOW_DISCOVERY,
+       IMSG_CTL_SHOW_DISCOVERY_DTL,
        IMSG_CTL_SHOW_DISC_IFACE,
        IMSG_CTL_SHOW_DISC_TNBR,
        IMSG_CTL_SHOW_DISC_ADJ,
@@ -84,6 +85,10 @@ enum imsg_type {
        IMSG_CTL_SHOW_NBR_DISC,
        IMSG_CTL_SHOW_NBR_END,
        IMSG_CTL_SHOW_LIB,
+       IMSG_CTL_SHOW_LIB_BEGIN,
+       IMSG_CTL_SHOW_LIB_SENT,
+       IMSG_CTL_SHOW_LIB_RCVD,
+       IMSG_CTL_SHOW_LIB_END,
        IMSG_CTL_SHOW_L2VPN_PW,
        IMSG_CTL_SHOW_L2VPN_BINDING,
        IMSG_CTL_CLEAR_NBR,
@@ -140,7 +145,9 @@ enum imsg_type {
        IMSG_RECONF_END,
        IMSG_DEBUG_UPDATE,
        IMSG_LOG,
-       IMSG_ACL_CHECK
+       IMSG_ACL_CHECK,
+       IMSG_GET_LABEL_CHUNK,
+       IMSG_RELEASE_LABEL_CHUNK
 };
 
 union ldpd_addr {
@@ -345,6 +352,29 @@ DECLARE_QOBJ_TYPE(nbr_params)
 #define F_NBRP_GTSM             0x02
 #define F_NBRP_GTSM_HOPS        0x04
 
+struct ldp_stats {
+       uint32_t                 kalive_sent;
+       uint32_t                 kalive_rcvd;
+       uint32_t                 addr_sent;
+       uint32_t                 addr_rcvd;
+       uint32_t                 addrwdraw_sent;
+       uint32_t                 addrwdraw_rcvd;
+       uint32_t                 notif_sent;
+       uint32_t                 notif_rcvd;
+       uint32_t                 capability_sent;
+       uint32_t                 capability_rcvd;
+       uint32_t                 labelmap_sent;
+       uint32_t                 labelmap_rcvd;
+       uint32_t                 labelreq_sent;
+       uint32_t                 labelreq_rcvd;
+       uint32_t                 labelwdraw_sent;
+       uint32_t                 labelwdraw_rcvd;
+       uint32_t                 labelrel_sent;
+       uint32_t                 labelrel_rcvd;
+       uint32_t                 labelabreq_sent;
+       uint32_t                 labelabreq_rcvd;
+};
+
 struct l2vpn_if {
        RB_ENTRY(l2vpn_if)       entry;
        struct l2vpn            *l2vpn;
@@ -473,6 +503,7 @@ struct ldpd_af_global {
 
 struct ldpd_global {
        int                      cmd_opts;
+       int                      sighup;
        time_t                   uptime;
        struct in_addr           rtr_id;
        struct ldpd_af_global    ipv4;
@@ -566,7 +597,9 @@ struct ctl_adj {
        char                     ifname[IF_NAMESIZE];
        union ldpd_addr          src_addr;
        uint16_t                 holdtime;
+       uint16_t                 holdtime_remaining;
        union ldpd_addr          trans_addr;
+       int                      ds_tlv;
 };
 
 struct ctl_nbr {
@@ -576,9 +609,12 @@ struct ctl_nbr {
        in_port_t                lport;
        union ldpd_addr          raddr;
        in_port_t                rport;
+       enum auth_method         auth_method;
        uint16_t                 holdtime;
        time_t                   uptime;
        int                      nbr_state;
+       struct ldp_stats         stats;
+       int                      flags;
 };
 
 struct ctl_rt {
@@ -590,7 +626,7 @@ struct ctl_rt {
        uint32_t                 remote_label;
        uint8_t                  flags;
        uint8_t                  in_use;
-       int                      first;
+       int                      no_downstream;
 };
 
 struct ctl_pw {
@@ -610,7 +646,7 @@ struct ctl_pw {
        uint32_t                 status;
 };
 
-extern struct ldpd_conf                *ldpd_conf;
+extern struct ldpd_conf                *ldpd_conf, *vty_conf;
 extern struct ldpd_global       global;
 
 /* parse.y */
@@ -670,9 +706,6 @@ struct ldpd_af_global       *ldp_af_global_get(struct ldpd_global *, int);
 int                     ldp_is_dual_stack(struct ldpd_conf *);
 in_addr_t               ldp_rtr_id_get(struct ldpd_conf *);
 int                     ldp_reload(struct ldpd_conf *);
-int                     ldp_reload_ref(struct ldpd_conf *, void **);
-struct ldpd_conf       *ldp_dup_config_ref(struct ldpd_conf *, void **ref);
-struct ldpd_conf       *ldp_dup_config(struct ldpd_conf *);
 void                    ldp_clear_config(struct ldpd_conf *);
 void                    merge_config(struct ldpd_conf *, struct ldpd_conf *);
 struct ldpd_conf       *config_new_empty(void);
index 3bb84e92a992906be803fc525c94a09b031cfa38..1bec3d2a958cd08532db799f5390d71f7263c626 100644 (file)
@@ -87,6 +87,10 @@ sigint(void)
 
 static struct quagga_signal_t ldpe_signals[] =
 {
+       {
+               .signal = SIGHUP,
+               /* ignore */
+       },
        {
                .signal = SIGINT,
                .handler = &sigint,
@@ -252,8 +256,8 @@ ldpe_dispatch_main(struct thread *thread)
        struct tnbr             *ntnbr;
        struct nbr_params       *nnbrp;
        static struct l2vpn     *l2vpn, *nl2vpn;
-       struct l2vpn_if         *lif = NULL, *nlif;
-       struct l2vpn_pw         *npw;
+       struct l2vpn_if         *lif, *nlif;
+       struct l2vpn_pw         *pw, *npw;
        struct imsg              imsg;
        int                      fd = THREAD_FD(thread);
        struct imsgev           *iev = THREAD_ARG(thread);
@@ -294,19 +298,22 @@ ldpe_dispatch_main(struct thread *thread)
                        iface = if_lookup_name(leconf, kif->ifname);
                        if (iface) {
                                if_update_info(iface, kif);
-                               if_update(iface, AF_UNSPEC);
+                               ldp_if_update(iface, AF_UNSPEC);
                                break;
                        }
 
                        RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) {
-                               lif = l2vpn_if_find_name(l2vpn, kif->ifname);
+                               lif = l2vpn_if_find(l2vpn, kif->ifname);
                                if (lif) {
-                                       lif->flags = kif->flags;
-                                       memcpy(lif->mac, kif->mac,
-                                           sizeof(lif->mac));
+                                       l2vpn_if_update_info(lif, kif);
                                        l2vpn_if_update(lif);
                                        break;
                                }
+                               pw = l2vpn_pw_find(l2vpn, kif->ifname);
+                               if (pw) {
+                                       l2vpn_pw_update_info(pw, kif);
+                                       break;
+                               }
                        }
                        break;
                case IMSG_NEWADDR:
@@ -354,6 +361,7 @@ ldpe_dispatch_main(struct thread *thread)
 #ifdef __OpenBSD__
                                pfkey_remove(nbr);
 #endif
+                               nbr->auth.method = AUTH_NONE;
                        }
                        ldpe_close_sockets(af);
                        if_update_all(af);
@@ -409,8 +417,11 @@ ldpe_dispatch_main(struct thread *thread)
                                    af))->trans_addr;
 #ifdef __OpenBSD__
                                nbrp = nbr_params_find(leconf, nbr->id);
-                               if (nbrp && pfkey_establish(nbr, nbrp) == -1)
-                                       fatalx("pfkey setup failed");
+                               if (nbrp) {
+                                       nbr->auth.method = nbrp->auth.method;
+                                       if (pfkey_establish(nbr, nbrp) == -1)
+                                               fatalx("pfkey setup failed");
+                               }
 #endif
                                if (nbr_session_active_role(nbr))
                                        nbr_establish_connection(nbr);
@@ -441,12 +452,6 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        memcpy(niface, imsg.data, sizeof(struct iface));
 
-                       LIST_INIT(&niface->addr_list);
-                       RB_INIT(&niface->ipv4.adj_tree);
-                       RB_INIT(&niface->ipv6.adj_tree);
-                       niface->ipv4.iface = niface;
-                       niface->ipv6.iface = niface;
-
                        RB_INSERT(iface_head, &nconf->iface_tree, niface);
                        break;
                case IMSG_RECONF_TNBR:
@@ -479,7 +484,6 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
 
-                       nlif->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_if_head, &nl2vpn->if_tree, nlif);
                        break;
                case IMSG_RECONF_L2VPN_PW:
@@ -487,7 +491,6 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
 
-                       npw->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_tree, npw);
                        break;
                case IMSG_RECONF_L2VPN_IPW:
@@ -495,11 +498,11 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
 
-                       npw->l2vpn = nl2vpn;
                        RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_inactive_tree, npw);
                        break;
                case IMSG_RECONF_END:
                        merge_config(leconf, nconf);
+                       ldp_clear_config(nconf);
                        nconf = NULL;
                        global.conf_seqnum++;
                        break;
@@ -642,7 +645,10 @@ ldpe_dispatch_lde(struct thread *thread)
                        send_notification_full(nbr->tcp, nm);
                        break;
                case IMSG_CTL_END:
-               case IMSG_CTL_SHOW_LIB:
+               case IMSG_CTL_SHOW_LIB_BEGIN:
+               case IMSG_CTL_SHOW_LIB_RCVD:
+               case IMSG_CTL_SHOW_LIB_SENT:
+               case IMSG_CTL_SHOW_LIB_END:
                case IMSG_CTL_SHOW_L2VPN_PW:
                case IMSG_CTL_SHOW_L2VPN_BINDING:
                        control_imsg_relay(&imsg);
@@ -819,6 +825,21 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
 
 void
 ldpe_adj_ctl(struct ctl_conn *c)
+{
+       struct adj      *adj;
+       struct ctl_adj  *actl;
+
+       RB_FOREACH(adj, global_adj_head, &global.adj_tree) {
+               actl = adj_to_ctl(adj);
+               imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0,
+                   -1, actl, sizeof(struct ctl_adj));
+       }
+
+       imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
+}
+
+void
+ldpe_adj_detail_ctl(struct ctl_conn *c)
 {
        struct iface            *iface;
        struct tnbr             *tnbr;
index 22b75eb008c2723efc24d08d6ea4052efa568768..a3f41a8b9fa12f1914fb59e0d1eb1a8e2c10c97e 100644 (file)
@@ -100,6 +100,7 @@ struct nbr {
        int                      idtimer_cnt;
        uint16_t                 keepalive;
        uint16_t                 max_pdu_len;
+       struct ldp_stats         stats;
 
        struct {
                uint8_t                 established;
@@ -207,20 +208,22 @@ void               ldpe_stop_init_backoff(int);
 struct ctl_conn;
 void            ldpe_iface_ctl(struct ctl_conn *, unsigned int);
 void            ldpe_adj_ctl(struct ctl_conn *);
+void            ldpe_adj_detail_ctl(struct ctl_conn *);
 void            ldpe_nbr_ctl(struct ctl_conn *);
 void            mapping_list_add(struct mapping_head *, struct map *);
 void            mapping_list_clr(struct mapping_head *);
 
 /* interface.c */
-struct iface   *if_new(struct kif *);
-void            if_exit(struct iface *);
+struct iface   *if_new(const char *);
+void            ldpe_if_init(struct iface *);
+void            ldpe_if_exit(struct iface *);
 struct iface   *if_lookup(struct ldpd_conf *, unsigned short);
 struct iface   *if_lookup_name(struct ldpd_conf *, const char *);
 void            if_update_info(struct iface *, struct kif *);
 struct iface_af *iface_af_get(struct iface *, int);
 void            if_addr_add(struct kaddr *);
 void            if_addr_del(struct kaddr *);
-void            if_update(struct iface *, int);
+void            ldp_if_update(struct iface *, int);
 void            if_update_all(int);
 uint16_t        if_get_hello_holdtime(struct iface_af *);
 uint16_t        if_get_hello_interval(struct iface_af *);
@@ -231,7 +234,7 @@ in_addr_t    if_get_ipv4_addr(struct iface *);
 struct adj     *adj_new(struct in_addr, struct hello_source *,
                    union ldpd_addr *);
 void            adj_del(struct adj *, uint32_t);
-struct adj     *adj_find(struct hello_source *);
+struct adj     *adj_find(struct in_addr, struct hello_source *);
 int             adj_get_af(struct adj *adj);
 void            adj_start_itimer(struct adj *);
 void            adj_stop_itimer(struct adj *);
index 077d472850059129c9b9fc6d33f64ebd3edf97f8..9a92a00d32327a811ae39888ee26ccac8b602e93 100644 (file)
@@ -264,6 +264,7 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
 
        nbrp = nbr_params_find(leconf, nbr->id);
        if (nbrp) {
+               nbr->auth.method = nbrp->auth.method;
 #ifdef __OpenBSD__
                if (pfkey_establish(nbr, nbrp) == -1)
                        fatalx("pfkey setup failed");
@@ -296,6 +297,7 @@ nbr_del(struct nbr *nbr)
            (ldp_af_global_get(&global, nbr->af))->ldp_session_socket,
            nbr->af, &nbr->raddr, NULL);
 #endif
+       nbr->auth.method = AUTH_NONE;
 
        if (nbr_pending_connect(nbr))
                THREAD_WRITE_OFF(nbr->ev_connect);
@@ -808,8 +810,11 @@ nbr_to_ctl(struct nbr *nbr)
        nctl.lport = nbr->tcp->lport;
        nctl.raddr = nbr->raddr;
        nctl.rport = nbr->tcp->rport;
+       nctl.auth_method = nbr->auth.method;
        nctl.holdtime = nbr->keepalive;
        nctl.nbr_state = nbr->state;
+       nctl.stats = nbr->stats;
+       nctl.flags = nbr->flags;
 
        gettimeofday(&now, NULL);
        if (nbr->state == NBR_STA_OPER) {
index 393994ed5f72686990055cd99c131b46384693e5..f10faa4a54b3bcf06b602388a86cabed616f09b5 100644 (file)
@@ -66,6 +66,7 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
        if (tcp->nbr) {
                log_msg_notification(1, tcp->nbr, nm);
                nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT);
+               tcp->nbr->stats.notif_sent++;
        }
 
        evbuf_enqueue(&tcp->wbuf, buf);
index a7be0f6b42e0a578ac03736a62ea14f91297486c..46893b992bd5b2e2d0f193e47dc4c1613c4541f8 100644 (file)
@@ -572,6 +572,42 @@ session_read(struct thread *thread)
                                return (0);
                        }
 
+                       /* no errors - update per neighbor message counters */
+                       switch (type) {
+                       case MSG_TYPE_NOTIFICATION:
+                               nbr->stats.notif_rcvd++;
+                               break;
+                       case MSG_TYPE_KEEPALIVE:
+                               nbr->stats.kalive_rcvd++;
+                               break;
+                       case MSG_TYPE_CAPABILITY:
+                               nbr->stats.capability_rcvd++;
+                               break;
+                       case MSG_TYPE_ADDR:
+                               nbr->stats.addr_rcvd++;
+                               break;
+                       case MSG_TYPE_ADDRWITHDRAW:
+                               nbr->stats.addrwdraw_rcvd++;
+                               break;
+                       case MSG_TYPE_LABELMAPPING:
+                               nbr->stats.labelmap_rcvd++;
+                               break;
+                       case MSG_TYPE_LABELREQUEST:
+                               nbr->stats.labelreq_rcvd++;
+                               break;
+                       case MSG_TYPE_LABELWITHDRAW:
+                               nbr->stats.labelwdraw_rcvd++;
+                               break;
+                       case MSG_TYPE_LABELRELEASE:
+                               nbr->stats.labelrel_rcvd++;
+                               break;
+                       case MSG_TYPE_LABELABORTREQ:
+                               nbr->stats.labelabreq_rcvd++;
+                               break;
+                       default:
+                               break;
+                       }
+
                        /* Analyse the next message */
                        pdu += msg_size;
                        len -= msg_size;
index 88a778cccca7de604d798a253bc682b8cf9593c3..a1a79dabfd359291611a7c776494da86c14af4b0 100644 (file)
@@ -418,12 +418,6 @@ pfkey_establish(struct nbr *nbr, struct nbr_params *nbrp)
        if (nbrp->auth.method == AUTH_NONE)
                return (0);
 
-       /*
-        * make sure we keep copies of everything we need to
-        * remove SAs and flows later again.
-        */
-       nbr->auth.method = nbrp->auth.method;
-
        switch (nbr->auth.method) {
        case AUTH_MD5SIG:
                strlcpy(nbr->auth.md5key, nbrp->auth.md5key,
index 55b1eb8044da0cae370af98d3d7041421a3a480b..c4989c73c999d22ccd89511f38daede88b25db9e 100644 (file)
@@ -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 \
@@ -33,12 +33,29 @@ libfrr_la_SOURCES = \
        strlcpy.c \
        strlcat.c \
        sha256.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 = \
+       frratomic.h \
        buffer.h checksum.h filter.h getopt.h hash.h \
        if.h linklist.h log.h \
        graph.h command_match.h \
@@ -55,6 +72,8 @@ pkginclude_HEADERS = \
        monotime.h \
        spf_backoff.h \
        srcdest_table.h \
+       module.h \
+       hook.h \
        libfrr.h \
        sha256.h \
        # end
index 4175e7ba927e96131e860ebb1057b713e038ef86..11d5c9385d103f51f549ed6f2f9dc53293589376 100644 (file)
@@ -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 */
index a5edaea21756626c24e8572bf9f4541fa76845dd..b651a05a097cec5f4428833ddeee78e6cddaa73b 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -293,7 +293,7 @@ bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp,
   /* Lookup index. */
   if (ifindex != 0)
     {
-      ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+      ifp = if_lookup_by_index (ifindex, vrf_id);
       if (ifp == NULL)
         {
          if (bfd_debug)
index cae848a5c1c9b0ba06befd1e2f0f2f5f285b7b25..f0d7a64eb7e6ba7bf990851daaf0f6551f8205ec 100644 (file)
@@ -41,6 +41,7 @@
 #include "vrf.h"
 #include "command_match.h"
 #include "qobj.h"
+#include "defaults.h"
 
 DEFINE_MTYPE(       LIB, HOST,       "Host config")
 DEFINE_MTYPE(       LIB, STRVEC,     "String vector")
@@ -1538,6 +1539,23 @@ DEFUN (show_version,
   return CMD_SUCCESS;
 }
 
+/* "Set" version ... ignore version tags */
+DEFUN (frr_version_defaults,
+       frr_version_defaults_cmd,
+       "frr <version|defaults> LINE...",
+       "FRRouting global parameters\n"
+       "version configuration was written by\n"
+       "set of configuration defaults used\n"
+       "version string\n")
+{
+  if (vty->type == VTY_TERM || vty->type == VTY_SHELL)
+    /* only print this when the user tries to do run it */
+    vty_out (vty, "%% NOTE: This command currently does nothing.%s"
+             "%% It is written to the configuration for future reference.%s",
+             VTY_NEWLINE, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
 /* Help display function for all node. */
 DEFUN (config_help,
        config_help_cmd,
@@ -1638,6 +1656,37 @@ DEFUN (show_commandtree,
   return cmd_list_cmds (vty, argc == 3);
 }
 
+static void
+vty_write_config (struct vty *vty)
+{
+  size_t i;
+  struct cmd_node *node;
+
+  if (vty->type == VTY_TERM)
+    {
+      vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+               VTY_NEWLINE);
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+
+  vty_out (vty, "frr version %s%s", FRR_VER_SHORT, VTY_NEWLINE);
+  vty_out (vty, "frr defaults %s%s", DFLT_NAME, VTY_NEWLINE);
+  vty_out (vty, "!%s", VTY_NEWLINE);
+
+  for (i = 0; i < vector_active (cmdvec); i++)
+    if ((node = vector_slot (cmdvec, i)) && node->func
+        && (node->vtysh || vty->type != VTY_SHELL))
+      {
+        if ((*node->func) (vty))
+          vty_out (vty, "!%s", VTY_NEWLINE);
+      }
+
+  if (vty->type == VTY_TERM)
+    {
+      vty_out (vty, "end%s",VTY_NEWLINE);
+    }
+}
+
 /* Write current configuration into file. */
 
 DEFUN (config_write,
@@ -1649,9 +1698,7 @@ DEFUN (config_write,
        "Write configuration to terminal\n")
 {
   int idx_type = 1;
-  unsigned int i;
   int fd, dirfd;
-  struct cmd_node *node;
   char *config_file, *slash;
   char *config_file_tmp = NULL;
   char *config_file_sav = NULL;
@@ -1662,32 +1709,10 @@ DEFUN (config_write,
   // if command was 'write terminal' or 'show running-config'
   if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal") ||
                     !strcmp(argv[0]->text, "show")))
-  {
-    if (vty->type == VTY_SHELL_SERV)
-      {
-        for (i = 0; i < vector_active (cmdvec); i++)
-          if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
-            {
-              if ((*node->func) (vty))
-                vty_out (vty, "!%s", VTY_NEWLINE);
-            }
-      }
-    else
-      {
-        vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
-                 VTY_NEWLINE);
-        vty_out (vty, "!%s", VTY_NEWLINE);
-
-        for (i = 0; i < vector_active (cmdvec); i++)
-          if ((node = vector_slot (cmdvec, i)) && node->func)
-            {
-              if ((*node->func) (vty))
-                vty_out (vty, "!%s", VTY_NEWLINE);
-            }
-        vty_out (vty, "end%s",VTY_NEWLINE);
-      }
-    return CMD_SUCCESS;
-  }
+    {
+      vty_write_config (vty);
+      return CMD_SUCCESS;
+    }
 
   if (host.noconfig)
     return CMD_SUCCESS;
@@ -1751,13 +1776,7 @@ DEFUN (config_write,
   vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
   vty_time_print (file_vty, 1);
   vty_out (file_vty, "!\n");
-
-  for (i = 0; i < vector_active (cmdvec); i++)
-    if ((node = vector_slot (cmdvec, i)) && node->func)
-      {
-        if ((*node->func) (file_vty))
-          vty_out (file_vty, "!\n");
-      }
+  vty_write_config (file_vty);
   vty_close (file_vty);
 
   if (stat(config_file, &conf_stat) >= 0)
@@ -1819,7 +1838,9 @@ DEFUN (copy_runningconf_startupconf,
        "Copy running config to... \n"
        "Copy running config to startup config (same as write file)\n")
 {
-  return config_write (self, vty, argc, argv);
+  if (!host.noconfig)
+    vty_write_config (vty);
+  return CMD_SUCCESS;
 }
 /** -- **/
 
@@ -2696,6 +2717,7 @@ cmd_init (int terminal)
 
   install_element (CONFIG_NODE, &hostname_cmd);
   install_element (CONFIG_NODE, &no_hostname_cmd);
+  install_element (CONFIG_NODE, &frr_version_defaults_cmd);
 
   if (terminal > 0)
     {
index 2e76e352cb8ee6fc2b8653b121fe8dd6e18c2b08..01c338f1773a6b8ee8687de3dd972d3485643190 100644 (file)
@@ -524,14 +524,14 @@ distribute_list_init (int node)
   disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
-  install_element (node, &distribute_list_cmd);
-  install_element (node, &no_distribute_list_cmd);
-/*
-  install_element (RIP_NODE, &distribute_list_cmd);
-  install_element (RIP_NODE, &no_distribute_list_cmd);
-  install_element (RIPNG_NODE, &distribute_list_cmd);
-  install_element (RIPNG_NODE, &no_distribute_list_cmd);
- */
+  /* vtysh command-extraction doesn't grok install_element(node, ) */
+  if (node == RIP_NODE) {
+    install_element (RIP_NODE, &distribute_list_cmd);
+    install_element (RIP_NODE, &no_distribute_list_cmd);
+  } else if (node == RIPNG_NODE) {
+    install_element (RIPNG_NODE, &distribute_list_cmd);
+    install_element (RIPNG_NODE, &no_distribute_list_cmd);
+  }
 
   /* install v6 */
   if (node == RIPNG_NODE) {
diff --git a/lib/frratomic.h b/lib/frratomic.h
new file mode 100644 (file)
index 0000000..183790a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-16  David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRRATOMIC_H
+#define _FRRATOMIC_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef FRR_AUTOCONF_ATOMIC
+#error autoconf checks for atomic functions were not properly run
+#endif
+
+/* ISO C11 */
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+
+/* gcc 4.7 and newer */
+#elif defined(HAVE___ATOMIC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed __ATOMIC_RELAXED
+#define memory_order_consume __ATOMIC_CONSUME
+#define memory_order_acquire __ATOMIC_ACQUIRE
+#define memory_order_release __ATOMIC_RELEASE
+#define memory_order_acq_rel __ATOMIC_ACQ_REL
+#define memory_order_seq_cst __ATOMIC_SEQ_CST
+
+#define atomic_load_explicit __atomic_load_n
+#define atomic_store_explicit __atomic_store_n
+#define atomic_exchange_explicit __atomic_exchange_n
+#define atomic_fetch_add_explicit __atomic_fetch_add
+#define atomic_fetch_sub_explicit __atomic_fetch_sub
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       __atomic_compare_exchange_n(atom, expect, desire, 1, mem1, mem2)
+
+/* gcc 4.1 and newer,
+ * clang 3.3 (possibly older)
+ *
+ * __sync_swap isn't in gcc's documentation, but clang has it
+ *
+ * note __sync_synchronize() 
+ */
+#elif defined(HAVE___SYNC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed 0
+#define memory_order_consume 0
+#define memory_order_acquire 0
+#define memory_order_release 0
+#define memory_order_acq_rel 0
+#define memory_order_seq_cst 0
+
+#define atomic_load_explicit(ptr, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), 0); \
+          __sync_synchronize(); rval; })
+#define atomic_store_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          *(ptr) = (val); \
+          __sync_synchronize(); (void)0; })
+#ifdef HAVE___SYNC_SWAP
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_swap((ptr, val), 0); \
+          __sync_synchronize(); rval; })
+#else /* !HAVE___SYNC_SWAP */
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ typeof(ptr) _ptr = (ptr); typeof(val) _val = (val); \
+          __sync_synchronize(); \
+          typeof(*ptr) old1, old2 = __sync_fetch_and_add(_ptr, 0); \
+          do { \
+               old1 = old2; \
+               old2 = __sync_val_compare_and_swap (_ptr, old1, _val); \
+          } while (old1 != old2); \
+          __sync_synchronize(); \
+          old2; \
+       })
+#endif /* !HAVE___SYNC_SWAP */
+#define atomic_fetch_add_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), (val)); \
+          __sync_synchronize(); rval; })
+#define atomic_fetch_sub_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_sub((ptr), (val)); \
+          __sync_synchronize(); rval; })
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       ({ typeof(atom) _atom = (atom); typeof(expect) _expect = (expect); \
+          typeof(desire) _desire = (desire); \
+          __sync_synchronize(); \
+          typeof(*atom) rval = __sync_val_compare_and_swap(_atom, *_expect, _desire); \
+          __sync_synchronize(); \
+          bool ret = (rval == *_expect); *_expect = rval; ret; })
+
+#else /* !HAVE___ATOMIC && !HAVE_STDATOMIC_H */
+#error no atomic functions...
+#endif
+
+#endif /* _FRRATOMIC_H */
index e3a7c979fcc176e1d82adfca6933966501f0a36c..97de9432161227a4197c03611a58f95e195a5aaa 100644 (file)
@@ -411,7 +411,7 @@ DEFUN (grammar_findambig,
       {
         int same = prev && !strcmp (prev->cmd, cur->cmd);
         if (printall && !same)
-          vty_out (vty, "'%s'%s", cur->cmd, VTY_NEWLINE);
+          vty_out (vty, "'%s' [%x]%s", cur->cmd, cur->el->daemon, VTY_NEWLINE);
         if (same)
           {
             vty_out (vty, "'%s' AMBIGUOUS:%s", cur->cmd, VTY_NEWLINE);
diff --git a/lib/hook.c b/lib/hook.c
new file mode 100644 (file)
index 0000000..04d803c
--- /dev/null
@@ -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 (file)
index 0000000..0cb7ab5
--- /dev/null
@@ -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 */
index f25be591d9ebfa17393bcf5b1e5eb8860d6ab6a3..ecb74631685f826266d35f01338c77c2d4e1392f 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -123,7 +123,7 @@ if_cmp_func (struct interface *ifp1, struct interface *ifp2)
 
 /* Create new interface structure. */
 struct interface *
-if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
+if_create (const char *name, int namelen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
   struct list *intf_list = vrf_iflist_get (vrf_id);
@@ -136,7 +136,7 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
   strncpy (ifp->name, name, namelen);
   ifp->name[namelen] = '\0';
   ifp->vrf_id = vrf_id;
-  if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL)
+  if (if_lookup_by_name (ifp->name, vrf_id) == NULL)
     listnode_add_sort (intf_list, ifp);
   else
     zlog_err("if_create(%s): corruption detected -- interface with this "
@@ -158,15 +158,9 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
   return ifp;
 }
 
-struct interface *
-if_create (const char *name, int namelen)
-{
-  return if_create_vrf (name, namelen, VRF_DEFAULT);
-}
-
 /* Create new interface structure. */
 void
-if_update_vrf (struct interface *ifp, const char *name, int namelen, vrf_id_t vrf_id)
+if_update (struct interface *ifp, const char *name, int namelen, vrf_id_t vrf_id)
 {
   struct list *intf_list = vrf_iflist_get (vrf_id);
 
@@ -179,7 +173,7 @@ if_update_vrf (struct interface *ifp, const char *name, int namelen, vrf_id_t vr
   strncpy (ifp->name, name, namelen);
   ifp->name[namelen] = '\0';
   ifp->vrf_id = vrf_id;
-  if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL)
+  if (if_lookup_by_name (ifp->name, vrf_id) == NULL)
     listnode_add_sort (intf_list, ifp);
   else
     zlog_err("if_create(%s): corruption detected -- interface with this "
@@ -239,7 +233,7 @@ if_add_hook (int type, int (*func)(struct interface *ifp))
 
 /* Interface existance check by index. */
 struct interface *
-if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
+if_lookup_by_index (ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
@@ -252,45 +246,27 @@ if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
   return NULL;
 }
 
-struct interface *
-if_lookup_by_index (ifindex_t ifindex)
-{
-  return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
-}
-
 const char *
-ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
+ifindex2ifname (ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ?
+  return ((ifp = if_lookup_by_index (ifindex, vrf_id)) != NULL) ?
         ifp->name : "unknown";
 }
 
-const char *
-ifindex2ifname (ifindex_t ifindex)
-{
-  return ifindex2ifname_vrf (ifindex, VRF_DEFAULT);
-}
-
 ifindex_t
-ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
+ifname2ifindex (const char *name, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex
+  return ((ifp = if_lookup_by_name (name, vrf_id)) != NULL) ? ifp->ifindex
                                                    : IFINDEX_INTERNAL;
 }
 
-ifindex_t
-ifname2ifindex (const char *name)
-{
-  return ifname2ifindex_vrf (name, VRF_DEFAULT);
-}
-
 /* Interface existance check by interface name. */
 struct interface *
-if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id)
+if_lookup_by_name (const char *name, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
@@ -312,7 +288,7 @@ if_lookup_by_name_all_vrf (const char *name)
 
   RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
     {
-      ifp = if_lookup_by_name_vrf (name, vrf->vrf_id);
+      ifp = if_lookup_by_name (name, vrf->vrf_id);
       if (ifp)
        return ifp;
     }
@@ -321,13 +297,7 @@ if_lookup_by_name_all_vrf (const char *name)
 }
 
 struct interface *
-if_lookup_by_name (const char *name)
-{
-  return if_lookup_by_name_vrf (name, VRF_DEFAULT);
-}
-
-struct interface *
-if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
+if_lookup_by_name_len (const char *name, size_t namelen, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
@@ -343,15 +313,9 @@ if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
   return NULL;
 }
 
-struct interface *
-if_lookup_by_name_len(const char *name, size_t namelen)
-{
-  return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT);
-}
-
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_exact_address_vrf (void *src, int family, vrf_id_t vrf_id)
+if_lookup_exact_address (void *src, int family, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct listnode *cnode;
@@ -383,15 +347,9 @@ if_lookup_exact_address_vrf (void *src, int family, vrf_id_t vrf_id)
   return NULL;
 }
 
-struct interface *
-if_lookup_exact_address (void *src, int family)
-{
-  return if_lookup_exact_address_vrf (src, family, VRF_DEFAULT);
-}
-
 /* Lookup interface by IPv4 address. */
 struct connected *
-if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id)
+if_lookup_address (void *matchaddr, int family, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct prefix addr;
@@ -432,15 +390,9 @@ if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id)
   return match;
 }
 
-struct connected *
-if_lookup_address (void *matchaddr, int family)
-{
-  return if_lookup_address_vrf (matchaddr, family, VRF_DEFAULT);
-}
-
 /* Lookup interface by prefix */
 struct interface *
-if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
+if_lookup_prefix (struct prefix *prefix, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct listnode *cnode;
@@ -460,37 +412,25 @@ if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
   return NULL;
 }
 
-struct interface *
-if_lookup_prefix (struct prefix *prefix)
-{
-  return if_lookup_prefix_vrf (prefix, VRF_DEFAULT);
-}
-
 /* Get interface by name if given name interface doesn't exist create
    one. */
 struct interface *
-if_get_by_name_vrf (const char *name, vrf_id_t vrf_id)
+if_get_by_name (const char *name, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp :
-         if_create_vrf (name, strlen(name), vrf_id);
+  return ((ifp = if_lookup_by_name (name, vrf_id)) != NULL) ? ifp :
+         if_create (name, strlen(name), vrf_id);
 }
 
 struct interface *
-if_get_by_name (const char *name)
-{
-  return if_get_by_name_vrf (name, VRF_DEFAULT);
-}
-
-struct interface *
-if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id, int vty)
+if_get_by_name_len (const char *name, size_t namelen, vrf_id_t vrf_id, int vty)
 {
   struct interface *ifp;
   struct vrf *vrf;
   struct listnode *node;
 
-  ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id);
+  ifp = if_lookup_by_name_len (name, namelen, vrf_id);
   if (ifp)
     return ifp;
 
@@ -515,19 +455,13 @@ if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id, int v
                 }
              else
                {
-                 if_update_vrf (ifp, name, namelen, vrf_id);
+                 if_update (ifp, name, namelen, vrf_id);
                  return ifp;
                }
            }
        }
     }
-  return (if_create_vrf (name, namelen, vrf_id));
-}
-
-struct interface *
-if_get_by_name_len (const char *name, size_t namelen)
-{
-  return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT, 0);
+  return (if_create (name, namelen, vrf_id));
 }
 
 /* Does interface up ? */
@@ -729,7 +663,7 @@ if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id)
   struct interface *ifp;
   size_t seppos = 0;
 
-  if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL)
+  if ( (ifp = if_lookup_by_name_len (name, nlen, vrf_id)) != NULL)
     return ifp;
   
   /* hunt the primary interface name... */
@@ -738,9 +672,9 @@ if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id)
   
   /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */
   if (seppos < nlen)
-    return if_get_by_name_len_vrf (name, seppos, vrf_id, 1);
+    return if_get_by_name_len (name, seppos, vrf_id, 1);
   else
-    return if_get_by_name_len_vrf (name, nlen, vrf_id, 1);
+    return if_get_by_name_len (name, nlen, vrf_id, 1);
 }
 #endif /* SUNOS_5 */
 
@@ -776,7 +710,7 @@ DEFUN (interface,
 #ifdef SUNOS_5
   ifp = if_sunwzebra_get (ifname, sl, vrf_id);
 #else
-  ifp = if_get_by_name_len_vrf (ifname, sl, vrf_id, 1);
+  ifp = if_get_by_name_len (ifname, sl, vrf_id, 1);
 #endif /* SUNOS_5 */
 
   if (!ifp)
@@ -807,7 +741,7 @@ DEFUN_NOSH (no_interface,
   if (argc > 3)
     VRF_GET_ID (vrf_id, vrfname);
 
-  ifp = if_lookup_by_name_vrf (ifname, vrf_id);
+  ifp = if_lookup_by_name (ifname, vrf_id);
 
   if (ifp == NULL)
     {
@@ -1188,7 +1122,7 @@ ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex)
       return ifp;
     }
   else
-    return if_lookup_by_index(ifindex);
+    return if_lookup_by_index(ifindex, VRF_DEFAULT);
 }
 #endif /* ifaddr_ipv4_table */
 
index 32e5d92a97996a4f2f259de7482ee14472c70b96..e8e84ffc8886f0cc214d63f4be33263200c5ced2 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -229,6 +229,9 @@ struct interface
   /* Interface metric */
   uint32_t metric;
 
+  /* Interface Speed in Mb/s */
+  uint32_t speed;
+
   /* Interface MTU. */
   unsigned int mtu;    /* IPv4 MTU */
   unsigned int mtu6;   /* IPv6 MTU - probably, but not neccessarily same as mtu */
@@ -389,45 +392,33 @@ struct nbr_connected
 
 /* Prototypes. */
 extern int if_cmp_name_func (char *, char *);
-extern struct interface *if_create (const char *name, int namelen);
-extern struct interface *if_lookup_by_index (ifindex_t);
-extern struct interface *if_lookup_exact_address (void *matchaddr, int family);
-extern struct connected *if_lookup_address (void *matchaddr, int family);
-extern struct interface *if_lookup_prefix (struct prefix *prefix);
 
-extern void if_update_vrf (struct interface *, const char *name, int namelen,
-                                vrf_id_t vrf_id);
-extern struct interface *if_create_vrf (const char *name, int namelen,
-                                vrf_id_t vrf_id);
-extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id);
-extern struct interface *if_lookup_exact_address_vrf (void *matchaddr, int family,
-                                vrf_id_t vrf_id);
-extern struct connected *if_lookup_address_vrf (void *matchaddr, int family,
-                                vrf_id_t vrf_id);
-extern struct interface *if_lookup_prefix_vrf (struct prefix *prefix,
+extern void if_update (struct interface *, const char *name, int namelen,
+                       vrf_id_t vrf_id);
+extern struct interface *if_create (const char *name, int namelen,
+                                    vrf_id_t vrf_id);
+extern struct interface *if_lookup_by_index (ifindex_t, vrf_id_t vrf_id);
+extern struct interface *if_lookup_exact_address (void *matchaddr, int family,
+                                                  vrf_id_t vrf_id);
+extern struct connected *if_lookup_address (void *matchaddr, int family,
+                                            vrf_id_t vrf_id);
+extern struct interface *if_lookup_prefix (struct prefix *prefix,
                                 vrf_id_t vrf_id);
 
-/* These 2 functions are to be used when the ifname argument is terminated
+/* These 3 functions are to be used when the ifname argument is terminated
    by a '\0' character: */
-extern struct interface *if_lookup_by_name (const char *ifname);
-extern struct interface *if_get_by_name (const char *ifname);
-
 extern struct interface *if_lookup_by_name_all_vrf (const char *ifname);
-extern struct interface *if_lookup_by_name_vrf (const char *ifname,
-                                vrf_id_t vrf_id);
-extern struct interface *if_get_by_name_vrf (const char *ifname,
+extern struct interface *if_lookup_by_name (const char *ifname,
+                                                vrf_id_t vrf_id);
+extern struct interface *if_get_by_name (const char *ifname,
                                 vrf_id_t vrf_id);
 
 /* For these 2 functions, the namelen argument should be the precise length
    of the ifname string (not counting any optional trailing '\0' character).
    In most cases, strnlen should be used to calculate the namelen value. */
 extern struct interface *if_lookup_by_name_len(const char *ifname,
-                                              size_t namelen);
-extern struct interface *if_get_by_name_len(const char *ifname,size_t namelen);
-
-extern struct interface *if_lookup_by_name_len_vrf(const char *ifname,
-                                size_t namelen, vrf_id_t vrf_id);
-extern struct interface *if_get_by_name_len_vrf(const char *ifname,
+                                               size_t namelen, vrf_id_t vrf_id);
+extern struct interface *if_get_by_name_len(const char *ifname,
                                size_t namelen, vrf_id_t vrf_id, int vty);
 
 
@@ -459,14 +450,12 @@ extern const char *if_link_type_str (enum zebra_link_type);
 /* Please use ifindex2ifname instead of if_indextoname where possible;
    ifindex2ifname uses internal interface info, whereas if_indextoname must
    make a system call. */
-extern const char *ifindex2ifname (ifindex_t);
-extern const char *ifindex2ifname_vrf (ifindex_t, vrf_id_t vrf_id);
+extern const char *ifindex2ifname (ifindex_t, vrf_id_t vrf_id);
 
 /* Please use ifname2ifindex instead of if_nametoindex where possible;
    ifname2ifindex uses internal interface info, whereas if_nametoindex must
    make a system call. */
-extern ifindex_t ifname2ifindex(const char *ifname);
-extern ifindex_t ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id);
+extern ifindex_t ifname2ifindex(const char *ifname, vrf_id_t vrf_id);
 
 /* Connected address functions. */
 extern struct connected *connected_new (void);
index cd8039b95bd95219afd263ac6c03e7408ff9e272..95a2c8e599a1f7d56df8f27fd4d7731adc4c8444 100644 (file)
@@ -240,7 +240,7 @@ key_delete (struct keychain *keychain, struct key *key)
   key_free (key);
 }
 
-DEFUN (key_chain,
+DEFUN_NOSH (key_chain,
        key_chain_cmd,
        "key chain WORD",
        "Authentication key management\n"
@@ -280,7 +280,7 @@ DEFUN (no_key_chain,
   return CMD_SUCCESS;
 }
 
-DEFUN (key,
+DEFUN_NOSH (key,
        key_cmd,
        "key (0-2147483647)",
        "Configure a key\n"
index b7ce0679c3a007d5bfb0c10b187cde7c145694ec..64f8be2ca6fbc4512ee24b1d14d1abdef44e1837 100644 (file)
@@ -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);
index d37f406f5b601881bcf22792df39abd0d1f99b48..a40fc34892616a41afeec0ec12692de089f51343 100644 (file)
@@ -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);
index c86eb61af370567e455b403bc34b271d282502ec..4460efca6e5f3548267b6c6728f232420daffb00 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -734,6 +734,17 @@ openzlog (const char *progname, const char *protoname, u_short instance,
 
   openlog (progname, syslog_flags, zl->facility);
   zlog_default = zl;
+
+#ifdef HAVE_GLIBC_BACKTRACE
+  /* work around backtrace() using lazily resolved dynamically linked
+   * symbols, which will otherwise cause funny breakage in the SEGV handler.
+   * (particularly, the dynamic linker can call malloc(), which uses locks
+   * in programs linked with -pthread, thus can deadlock.) */
+  void *bt[4];
+  backtrace (bt, array_size(bt));
+  free (backtrace_symbols (bt, 0));
+  backtrace_symbols_fd (bt, 0, 0);
+#endif
 }
 
 void
@@ -964,6 +975,9 @@ static const struct zebra_desc_table command_types[] = {
   DESC_ENTRY   (ZEBRA_IPV6_NEXTHOP_ADD),
   DESC_ENTRY   (ZEBRA_IPV6_NEXTHOP_DELETE),
   DESC_ENTRY    (ZEBRA_IPMR_ROUTE_STATS),
+  DESC_ENTRY    (ZEBRA_LABEL_MANAGER_CONNECT),
+  DESC_ENTRY    (ZEBRA_GET_LABEL_CHUNK),
+  DESC_ENTRY    (ZEBRA_RELEASE_LABEL_CHUNK),
 };
 #undef DESC_ENTRY
 
@@ -1058,7 +1072,7 @@ proto_redistnum(int afi, const char *s)
        return ZEBRA_ROUTE_VNC;
       else if (strmatch (s, "vnc-direct"))
        return ZEBRA_ROUTE_VNC_DIRECT;
-      else if (strncmp (s, "n", 1) == 0)
+      else if (strmatch (s, "nhrp"))
        return ZEBRA_ROUTE_NHRP;
     }
   if (afi == AFI_IP6)
@@ -1083,7 +1097,7 @@ proto_redistnum(int afi, const char *s)
        return ZEBRA_ROUTE_VNC;
       else if (strmatch (s, "vnc-direct"))
        return ZEBRA_ROUTE_VNC_DIRECT;
-      else if (strncmp (s, "n", 1) == 0)
+      else if (strmatch (s, "nhrp"))
        return ZEBRA_ROUTE_NHRP;
     }
   return -1;
index ad55366f64a15a040547b41666753f49222bb04f..c6207adb981f1ef32f9ab233608cb51c0caaa358 100644 (file)
@@ -27,119 +27,107 @@ struct memgroup **mg_insert = &mg_first;
 DEFINE_MGROUP(LIB, "libfrr")
 DEFINE_MTYPE(LIB, TMP, "Temporary memory")
 
-static inline void
-mt_count_alloc (struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size)
 {
-  mt->n_alloc++;
+       size_t oldsize;
 
-  if (mt->size == 0)
-    mt->size = size;
-  else if (mt->size != size)
-    mt->size = SIZE_VAR;
+       atomic_fetch_add_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+       oldsize = atomic_load_explicit(&mt->size, memory_order_relaxed);
+       if (oldsize == 0)
+               oldsize = atomic_exchange_explicit(&mt->size, size, memory_order_relaxed);
+       if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
+               atomic_store_explicit(&mt->size, SIZE_VAR, memory_order_relaxed);
 }
 
-static inline void
-mt_count_free (struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt)
 {
-  assert(mt->n_alloc);
-  mt->n_alloc--;
+       assert(mt->n_alloc);
+       atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
 }
 
-static inline void *
-mt_checkalloc (struct memtype *mt, void *ptr, size_t size)
+static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (__builtin_expect(ptr == NULL, 0))
-    {
-      memory_oom (size, mt->name);
-      return NULL;
-    }
-  mt_count_alloc (mt, size);
-  return ptr;
+       if (__builtin_expect(ptr == NULL, 0)) {
+               memory_oom(size, mt->name);
+               return NULL;
+       }
+       mt_count_alloc(mt, size);
+       return ptr;
 }
 
-void *
-qmalloc (struct memtype *mt, size_t size)
+void *qmalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, malloc (size), size);
+       return mt_checkalloc(mt, malloc(size), size);
 }
 
-void *
-qcalloc (struct memtype *mt, size_t size)
+void *qcalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, calloc (size, 1), size);
+       return mt_checkalloc(mt, calloc(size, 1), size);
 }
 
-void *
-qrealloc (struct memtype *mt, void *ptr, size_t size)
+void *qrealloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (ptr)
-    mt_count_free (mt);
-  return mt_checkalloc (mt, ptr ? realloc (ptr, size) : malloc (size), size);
+       if (ptr)
+               mt_count_free(mt);
+       return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
 }
 
-void *
-qstrdup (struct memtype *mt, const char *str)
+void *qstrdup(struct memtype *mt, const char *str)
 {
-  return mt_checkalloc (mt, strdup (str), strlen (str) + 1);
+       return mt_checkalloc(mt, strdup(str), strlen(str) + 1);
 }
 
-void
-qfree (struct memtype *mt, void *ptr)
+void qfree(struct memtype *mt, void *ptr)
 {
-  if (ptr)
-    mt_count_free (mt);
-  free (ptr);
+       if (ptr)
+               mt_count_free(mt);
+       free(ptr);
 }
 
-int
-qmem_walk (qmem_walk_fn *func, void *arg)
+int qmem_walk(qmem_walk_fn *func, void *arg)
 {
-  struct memgroup *mg;
-  struct memtype *mt;
-  int rv;
-
-  for (mg = mg_first; mg; mg = mg->next)
-    {
-      if ((rv = func (arg, mg, NULL)))
-        return rv;
-      for (mt = mg->types; mt; mt = mt->next)
-        if ((rv = func (arg, mg, mt)))
-          return rv;
-    }
-  return 0;
+       struct memgroup *mg;
+       struct memtype *mt;
+       int rv;
+
+       for (mg = mg_first; mg; mg = mg->next) {
+               if ((rv = func(arg, mg, NULL)))
+                       return rv;
+               for (mt = mg->types; mt; mt = mt->next)
+                       if ((rv = func(arg, mg, mt)))
+                               return rv;
+       }
+       return 0;
 }
 
-struct exit_dump_args
-{
-  const char *prefix;
-  int error;
+struct exit_dump_args {
+       const char *prefix;
+       int error;
 };
 
-static int
-qmem_exit_walker (void *arg, struct memgroup *mg, struct memtype *mt)
+static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
 {
-  struct exit_dump_args *eda = arg;
-
-  if (!mt)
-    {
-      fprintf (stderr, "%s: showing active allocations in memory group %s\n",
-               eda->prefix, mg->name);
-    }
-  else if (mt->n_alloc)
-    {
-      char size[32];
-      eda->error++;
-      snprintf (size, sizeof (size), "%10zu", mt->size);
-      fprintf (stderr, "%s: memstats:  %-30s: %6zu * %s\n",
-               eda->prefix, mt->name, mt->n_alloc,
-               mt->size == SIZE_VAR ? "(variably sized)" : size);
-    }
-  return 0;
+       struct exit_dump_args *eda = arg;
+
+       if (!mt) {
+               fprintf(stderr, "%s: showing active allocations in "
+                               "memory group %s\n",
+                               eda->prefix, mg->name);
+
+       } else if (mt->n_alloc) {
+               char size[32];
+               eda->error++;
+               snprintf(size, sizeof(size), "%10zu", mt->size);
+               fprintf(stderr, "%s: memstats:  %-30s: %6zu * %s\n",
+                               eda->prefix, mt->name, mt->n_alloc,
+                               mt->size == SIZE_VAR ? "(variably sized)" : size);
+       }
+       return 0;
 }
 
-void
-log_memstats_stderr (const char *prefix)
+void log_memstats_stderr(const char *prefix)
 {
-  struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
-  qmem_walk (qmem_exit_walker, &eda);
+       struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
+       qmem_walk(qmem_exit_walker, &eda);
 }
index 477a6162dc45960aa0be35c66269a38227af33d6..9e8803a8b2a6dbc1881df66e050cfe83c2072c4a 100644 (file)
 #define _QUAGGA_MEMORY_H
 
 #include <stdlib.h>
+#include <frratomic.h>
 
 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
 
 #define SIZE_VAR ~0UL
-struct memtype
-{
-  struct memtype *next, **ref;
-  const char *name;
-  size_t n_alloc;
-  size_t size;
+struct memtype {
+       struct memtype *next, **ref;
+       const char *name;
+       _Atomic size_t n_alloc;
+       _Atomic size_t size;
 };
 
-struct memgroup
-{
-  struct memgroup *next, **ref;
-  struct memtype *types, **insert;
-  const char *name;
+struct memgroup {
+       struct memgroup *next, **ref;
+       struct memtype *types, **insert;
+       const char *name;
 };
 
 #if defined(__clang__)
@@ -82,14 +81,14 @@ struct memgroup
  *    DEFINE_MGROUP(MYDAEMON, "my daemon memory")
  *    DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
  *                   "this mtype is used in multiple files in mydaemon")
- *    foo = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*foo))
+ *    foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
  *
  *  mydaemon_io.c
- *    bar = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*bar))
+ *    bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
  *
  *    DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
  *                          "this mtype is used only in this file")
- *    baz = qmalloc (MTYPE_MYDAEMON_IO, sizeof (*baz))
+ *    baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
  *
  *  Note:  Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
  *         by not having these as part of the macro arguments)
@@ -155,15 +154,15 @@ DECLARE_MGROUP(LIB)
 DECLARE_MTYPE(TMP)
 
 
-extern void *qmalloc (struct memtype *mt, size_t size)
+extern void *qmalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qcalloc (struct memtype *mt, size_t size)
+extern void *qcalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qrealloc (struct memtype *mt, void *ptr, size_t size)
+extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
        __attribute__ ((_ALLOC_SIZE(3), nonnull (1) _RET_NONNULL));
 extern void *qstrdup (struct memtype *mt, const char *str)
        __attribute__ ((malloc, nonnull (1) _RET_NONNULL));
-extern void qfree (struct memtype *mt, void *ptr)
+extern void qfree(struct memtype *mt, void *ptr)
        __attribute__ ((nonnull (1)));
 
 #define XMALLOC(mtype, size)           qmalloc(mtype, size)
@@ -183,10 +182,10 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
  *
  * return value: 0: continue, !0: abort walk.  qmem_walk will return the
  * last value from qmem_walk_fn. */
-typedef int qmem_walk_fn (void *arg, struct memgroup *mg, struct memtype *mt);
-extern int qmem_walk (qmem_walk_fn *func, void *arg);
-extern void log_memstats_stderr (const char *);
+typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
+extern int qmem_walk(qmem_walk_fn *func, void *arg);
+extern void log_memstats_stderr(const char *);
 
-extern void memory_oom (size_t size, const char *name);
+extern void memory_oom(size_t size, const char *name);
 
 #endif /* _QUAGGA_MEMORY_H */
index 149b32913002da7cb7cacb330072c45871a5d963..6d63bc2d53b3bb02c29f54200b6622f17307161d 100644 (file)
@@ -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>
 #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 (file)
index 0000000..4ebe3c0
--- /dev/null
@@ -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 (file)
index 0000000..cb66e60
--- /dev/null
@@ -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 */
index b5c1a653b1f9150a45a11873b44250d90b5d2b20..13a46e10127cacdd67002c07ec8309aede0a9ac6 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef _QUAGGA_MPLS_H
 #define _QUAGGA_MPLS_H
 
+#include <arpa/inet.h>
+
 /* Well-known MPLS label values (RFC 3032 etc). */
 #define MPLS_V4_EXP_NULL_LABEL             0
 #define MPLS_RA_LABEL                      1
index 1673ac0a66c5482dbbc30c554c16181b45fe85a5..ae0a24668eef566dbcf920581dca01486c186358 100644 (file)
--- a/lib/ns.c
+++ b/lib/ns.c
@@ -304,7 +304,7 @@ ns_netns_pathname (struct vty *vty, const char *name)
   return pathname;
 }
 
-DEFUN (ns_netns,
+DEFUN_NOSH (ns_netns,
        ns_netns_cmd,
        "logical-router (1-65535) ns NAME",
        "Enable a logical-router\n"
index 376d6f3365bb8c22f50397420acabbb554492493..decd4bb7db94319d81d1078e745fe46d08b342b2 100644 (file)
@@ -731,7 +731,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
   if (zprivs->user)
     {
       ngroups = sizeof(groups);
-      if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 )
+      if (getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups) < 0)
         {
           /* cant use log.h here as it depends on vty */
           fprintf (stderr, "privs_init: could not getgrouplist for user %s\n",
index 1647ac36683c7102275b5311ddc8642dc5df5e10..cd34ffaae5349567bc277c7b1537eafb99dc4f43 100644 (file)
@@ -2538,7 +2538,7 @@ DEFUN (no_set_tag,
 
 
 
-DEFUN (route_map,
+DEFUN_NOSH (route_map,
        route_map_cmd,
        "route-map WORD <deny|permit> (1-65535)",
        "Create route-map or enter route-map command mode\n"
@@ -2754,7 +2754,7 @@ DEFUN (no_rmap_continue,
 }
 
 
-DEFUN (rmap_show_name,
+DEFUN_NOSH (rmap_show_name,
        rmap_show_name_cmd,
        "show route-map [WORD]",
        SHOW_STR
index a120028d810580f5d1d73ff69326c445062dfee2..b2059a17bf6104de35a54a847fa1f04c41fbbac7 100644 (file)
@@ -108,7 +108,8 @@ quagga_sigevent_process (void)
           if (sig->caught > 0)
             {
               sig->caught = 0;
-              sig->handler ();
+              if (sig->handler)
+                sig->handler ();
             }
         }
     }
@@ -232,6 +233,18 @@ core_handler(int signo
 #endif
            )
 {
+  /* make sure we don't hang in here.  default for SIGALRM is terminate.
+   * - if we're in backtrace for more than a second, abort. */
+  struct sigaction sa_default = { .sa_handler = SIG_DFL };
+  sigaction (SIGALRM, &sa_default, NULL);
+
+  sigset_t sigset;
+  sigemptyset (&sigset);
+  sigaddset (&sigset, SIGALRM);
+  sigprocmask (SIG_UNBLOCK, &sigset, NULL);
+
+  alarm (1);
+
   zlog_signal(signo, "aborting..."
 #ifdef SA_SIGINFO
              , siginfo, program_counter(context)
@@ -325,6 +338,11 @@ trap_default_signals(void)
 #else
                  act.sa_handler = sigmap[i].handler;
                  act.sa_flags = 0;
+#endif
+#ifdef SA_RESETHAND
+                  /* don't try to print backtraces recursively */
+                  if (sigmap[i].handler == core_handler)
+                    act.sa_flags |= SA_RESETHAND;
 #endif
                }
              if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
index 3abfadcd28721297f0e48edccc075689ad56ba49..370b8f138e17ac5160dfd2e2cbecf4ee1a9767a8 100644 (file)
@@ -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 */
index f6f9845e2d7df6fb0a6e3988beb5cdc672c6bb91..1cbd41c72089b4727fc5a0eb8f1c1102870817f1 100644 (file)
@@ -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 */
index 6138e79718c92d20338fb27ddd19fa8a61aa37e8..e707fc584cf893dfc2e7b6ee77f3b9ab7ac7d5a9 100644 (file)
@@ -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)
index adc82781892b2ee3e77ad71df0736e8e68dba6d7..d9eabb9f8170595f305b3b1d32da97507f43b4a5 100644 (file)
@@ -39,8 +39,9 @@
 #define FRR_SMUX_NAME   "@PACKAGE_NAME@"
 #define FRR_PTM_NAME    "@PACKAGE_NAME@"
 
-#define FRR_FULL_NAME   "FreeRangeRouting"
+#define FRR_FULL_NAME   "FRRouting"
 #define FRR_VERSION     "@PACKAGE_VERSION@" GIT_SUFFIX
+#define FRR_VER_SHORT   "@PACKAGE_VERSION@"
 #define FRR_BUG_ADDRESS "@PACKAGE_BUGREPORT@"
 #define FRR_COPYRIGHT   "Copyright 1996-2005 Kunihiro Ishiguro, et al."
 #define FRR_CONFIG_ARGS "@CONFIG_ARGS@"
index ab7b43b078231145853e21c61df3b69f917f8255..ce57bb6e7a1c3d84da250526fdfb1a77c7f97691 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -474,7 +474,7 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id)
 }
 
 /* vrf CLI commands */
-DEFUN (vrf,
+DEFUN_NOSH (vrf,
        vrf_cmd,
        "vrf NAME",
        "Select a VRF to configure\n"
index 54caf6ad7a13d92c6351b6a685e586e9edd1b0d1..bd0b1c3219719cd74cd8903559aec0f7305107e8 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2662,7 +2662,7 @@ vty_event (enum event event, int sock, struct vty *vty)
     }
 }
 
-DEFUN (config_who,
+DEFUN_NOSH (config_who,
        config_who_cmd,
        "who",
        "Display who is on vty\n")
@@ -2679,7 +2679,7 @@ DEFUN (config_who,
 }
 
 /* Move to vty configuration mode. */
-DEFUN (line_vty,
+DEFUN_NOSH (line_vty,
        line_vty_cmd,
        "line vty",
        "Configure a terminal line\n"
@@ -2869,7 +2869,7 @@ DEFUN (no_service_advanced_vty,
   return CMD_SUCCESS;
 }
 
-DEFUN (terminal_monitor,
+DEFUN_NOSH (terminal_monitor,
        terminal_monitor_cmd,
        "terminal monitor",
        "Set terminal line parameters\n"
@@ -2879,7 +2879,7 @@ DEFUN (terminal_monitor,
   return CMD_SUCCESS;
 }
 
-DEFUN (terminal_no_monitor,
+DEFUN_NOSH (terminal_no_monitor,
        terminal_no_monitor_cmd,
        "terminal no monitor",
        "Set terminal line parameters\n"
@@ -2890,7 +2890,7 @@ DEFUN (terminal_no_monitor,
   return CMD_SUCCESS;
 }
 
-DEFUN (no_terminal_monitor,
+DEFUN_NOSH (no_terminal_monitor,
        no_terminal_monitor_cmd,
        "no terminal monitor",
        NO_STR
@@ -2901,7 +2901,7 @@ DEFUN (no_terminal_monitor,
 }
 
 
-DEFUN (show_history,
+DEFUN_NOSH (show_history,
        show_history_cmd,
        "show history",
        SHOW_STR
index 859751deb8a761698f7c34d470d0e5f8b03a7a0a..71b95ae7dbadcc8e3e4cad14b7c28ae33eb5d264 100644 (file)
@@ -33,6 +33,7 @@
 #include "memory.h"
 #include "table.h"
 #include "nexthop.h"
+#include "mpls.h"
 
 DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
 DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -1002,6 +1003,8 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid)
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |  metric                                                       |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  speed                                                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |  ifmtu                                                        |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |  ifmtu6                                                       |
@@ -1066,9 +1069,9 @@ zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id)
   stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
 
   /* Lookup/create interface by name. */
-  ifp = if_get_by_name_len_vrf (ifname_tmp,
-                                strnlen (ifname_tmp, INTERFACE_NAMSIZ),
-                                vrf_id, 0);
+  ifp = if_get_by_name_len (ifname_tmp,
+                            strnlen (ifname_tmp, INTERFACE_NAMSIZ),
+                            vrf_id, 0);
 
   zebra_interface_if_set_value (s, ifp);
 
@@ -1092,9 +1095,9 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id)
   stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
 
   /* Lookup this by interface index. */
-  ifp = if_lookup_by_name_len_vrf (ifname_tmp,
-                                   strnlen (ifname_tmp, INTERFACE_NAMSIZ),
-                                   vrf_id);
+  ifp = if_lookup_by_name_len (ifname_tmp,
+                               strnlen (ifname_tmp, INTERFACE_NAMSIZ),
+                               vrf_id);
   if (ifp == NULL)
     {
       zlog_warn ("INTERFACE_STATE: Cannot find IF %s in VRF %d",
@@ -1153,7 +1156,7 @@ zebra_interface_link_params_read (struct stream *s)
 
   ifindex = stream_getl (s);
 
-  struct interface *ifp = if_lookup_by_index (ifindex);
+  struct interface *ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
 
   if (ifp == NULL)
     {
@@ -1184,6 +1187,7 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
   ifp->ptm_enable = stream_getc (s);
   ifp->ptm_status = stream_getc (s);
   ifp->metric = stream_getl (s);
+  ifp->speed = stream_getl (s);
   ifp->mtu = stream_getl (s);
   ifp->mtu6 = stream_getl (s);
   ifp->bandwidth = stream_getl (s);
@@ -1302,7 +1306,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   ifindex = stream_getl (s);
 
   /* Lookup index. */
-  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+  ifp = if_lookup_by_index (ifindex, vrf_id);
   if (ifp == NULL)
     {
       zlog_warn ("INTERFACE_ADDRESS_%s: Cannot find IF %u in VRF %d",
@@ -1396,7 +1400,7 @@ zebra_interface_nbr_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   ifindex = stream_getl (s);
 
   /* Lookup index. */
-  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+  ifp = if_lookup_by_index (ifindex, vrf_id);
   if (ifp == NULL)
     {
       zlog_warn ("INTERFACE_NBR_%s: Cannot find IF %u in VRF %d",
@@ -1447,7 +1451,7 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
   ifindex = stream_getl (s);
 
   /* Lookup interface. */
-  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+  ifp = if_lookup_by_index (ifindex, vrf_id);
   if (ifp == NULL)
     {
       zlog_warn ("INTERFACE_VRF_UPDATE: Cannot find IF %u in VRF %d",
@@ -1461,6 +1465,223 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
   *new_vrf_id = new_id;
   return ifp;
 }
+/**
+ * Connect to label manager in a syncronous way
+ *
+ * It first writes the request to zcient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @result Result of response
+ */
+int
+lm_label_manager_connect (struct zclient *zclient)
+{
+  int ret;
+  struct stream *s;
+  u_char result;
+  u_int16_t size;
+  u_char marker;
+  u_char version;
+  vrf_id_t vrf_id;
+  u_int16_t cmd;
+
+  zlog_debug ("Connecting to Label Manager");
+  if (zclient->sock < 0)
+    return -1;
+
+  /* send request */
+  s = zclient->obuf;
+  stream_reset (s);
+  zclient_create_header (s, ZEBRA_LABEL_MANAGER_CONNECT, VRF_DEFAULT);
+
+  /* proto */
+  stream_putc (s, zclient->redist_default);
+  /* instance */
+  stream_putw (s, zclient->instance);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at(s, 0, stream_get_endp(s));
+
+  ret = writen (zclient->sock, s->data, stream_get_endp (s));
+  if (ret < 0)
+    {
+      zlog_err ("%s: can't write to zclient->sock", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("%s: zclient->sock connection closed", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+  zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret);
+
+  /* read response */
+  s = zclient->ibuf;
+  stream_reset (s);
+
+  ret = zclient_read_header (s, zclient->sock, &size, &marker, &version,
+                             &vrf_id, &cmd);
+  if (ret != 0 || cmd != ZEBRA_LABEL_MANAGER_CONNECT) {
+      zlog_err ("%s: Invalid Label Manager Connect Message Reply Header", __func__);
+      return -1;
+  }
+  /* result */
+  result = stream_getc(s);
+  zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u",
+              __func__, size, result);
+
+  return (int)result;
+}
+
+/**
+ * Function to request a label chunk in a syncronous way
+ *
+ * It first writes the request to zlcient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @param keep Avoid garbage collection
+ * @param chunk_size Amount of labels requested
+ * @param start To write first assigned chunk label to
+ * @param end To write last assigned chunk label to
+ * @result 0 on success, -1 otherwise
+ */
+int
+lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size,
+                    uint32_t *start, uint32_t *end)
+{
+  int ret;
+  struct stream *s;
+  u_int16_t size;
+  u_char marker;
+  u_char version;
+  vrf_id_t vrf_id;
+  u_int16_t cmd;
+  u_char response_keep;
+
+  zlog_debug ("Getting Label Chunk");
+  if (zclient->sock < 0)
+    return -1;
+
+  /* send request */
+  s = zclient->obuf;
+  stream_reset (s);
+  zclient_create_header (s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT);
+  /* keep */
+  stream_putc (s, keep);
+  /* chunk size */
+  stream_putl (s, chunk_size);
+  /* Put length at the first point of the stream. */
+  stream_putw_at(s, 0, stream_get_endp(s));
+
+  ret = writen (zclient->sock, s->data, stream_get_endp (s));
+  if (ret < 0)
+    {
+      zlog_err ("%s: can't write to zclient->sock", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("%s: zclient->sock connection closed", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+  zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret);
+
+  /* read response */
+  s = zclient->ibuf;
+  stream_reset (s);
+
+  ret = zclient_read_header (s, zclient->sock, &size, &marker, &version,
+                             &vrf_id, &cmd);
+  if (ret != 0 || cmd != ZEBRA_GET_LABEL_CHUNK) {
+      zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__);
+      return -1;
+  }
+  zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size);
+  /* keep */
+  response_keep = stream_getc(s);
+  /* start and end labels */
+  *start = stream_getl(s);
+  *end = stream_getl(s);
+
+  /* not owning this response */
+  if (keep != response_keep) {
+          zlog_err ("%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
+                    __func__, *start, *end, keep, response_keep);
+  }
+  /* sanity */
+  if (*start > *end
+      || *start < MPLS_MIN_UNRESERVED_LABEL
+      || *end > MPLS_MAX_UNRESERVED_LABEL) {
+          zlog_err ("%s: Invalid Label chunk: %u - %u", __func__,
+                    *start, *end);
+          return -1;
+  }
+
+  zlog_debug ("Label Chunk assign: %u - %u (%u) ",
+              *start, *end, response_keep);
+
+  return 0;
+}
+
+/**
+ * Function to release a label chunk
+ *
+ * @param zclient Zclient used to connect to label manager (zebra)
+ * @param start First label of chunk
+ * @param end Last label of chunk
+ * @result 0 on success, -1 otherwise
+ */
+int
+lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end)
+{
+  int ret;
+  struct stream *s;
+
+  zlog_debug ("Releasing Label Chunk");
+  if (zclient->sock < 0)
+    return -1;
+
+  /* send request */
+  s = zclient->obuf;
+  stream_reset (s);
+  zclient_create_header (s, ZEBRA_RELEASE_LABEL_CHUNK, VRF_DEFAULT);
+
+  /* start */
+  stream_putl (s, start);
+  /* end */
+  stream_putl (s, end);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at(s, 0, stream_get_endp(s));
+
+  ret = writen (zclient->sock, s->data, stream_get_endp (s));
+  if (ret < 0)
+    {
+      zlog_err ("%s: can't write to zclient->sock", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("%s: zclient->sock connection closed", __func__);
+      close (zclient->sock);
+      zclient->sock = -1;
+      return -1;
+    }
+
+  return 0;
+}
 
 /* Zebra client message read function. */
 static int
index 89fc865c78319a70a1a95d2fbeafc07c5a033de6..d3d0a202c5caf379bcaf3d56324fb9bd6db33b87 100644 (file)
@@ -91,6 +91,9 @@ typedef enum {
   ZEBRA_IPV6_NEXTHOP_ADD,
   ZEBRA_IPV6_NEXTHOP_DELETE,
   ZEBRA_IPMR_ROUTE_STATS,
+  ZEBRA_LABEL_MANAGER_CONNECT,
+  ZEBRA_GET_LABEL_CHUNK,
+  ZEBRA_RELEASE_LABEL_CHUNK,
 } zebra_message_types_t;
 
 struct redist_proto
@@ -271,6 +274,10 @@ extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
 extern struct interface *zebra_interface_link_params_read (struct stream *);
 extern size_t zebra_interface_link_params_write (struct stream *,
                                                  struct interface *);
+extern int lm_label_manager_connect (struct zclient *zclient);
+extern int lm_get_label_chunk (struct zclient *zclient, u_char keep,
+                               uint32_t chunk_size, uint32_t *start, uint32_t *end);
+extern int lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end);
 /* IPv6 prefix add and delete function prototype. */
 
 struct zapi_ipv6
index 3f3bd0a73574620a2ba5b3b7dc04cb74a2369aaf..798188b0b93d284c066bf7845fd74f23040fde0d 100644 (file)
@@ -4,4 +4,5 @@ Makefile.in
 .arch-ids
 *~
 *.loT
-
+!ax_pthread.m4
+!ax_sys_weak_alias.m4
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644 (file)
index 0000000..d383ad5
--- /dev/null
@@ -0,0 +1,332 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#
+#   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 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 21
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+                  [AC_MSG_RESULT([yes])],
+                  [ax_pthread_extra_flags=
+                   AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT([$attr_name])
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                # TODO: What about Clang on Solaris?
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT([$flag])
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            [ax_cv_PTHREAD_PRIO_INHERIT], [
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != xyes; then
+            case $host_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                  [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                  [#handle absolute path differently from PATH based program lookup
+                   AS_CASE(["x$CC"],
+                     [x/*],
+                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff --git a/nhrpd/.gitignore b/nhrpd/.gitignore
new file mode 100644 (file)
index 0000000..3d4d56d
--- /dev/null
@@ -0,0 +1 @@
+nhrpd
index a418ecabd3013f50e85704f621b190fecb182bb6..76419a7ff1e12094e7fcfcf04e0d49756cadf119 100644 (file)
@@ -75,7 +75,7 @@ static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb)
                }
        }
 
-       ifp = if_lookup_by_index(ndm->ndm_ifindex);
+       ifp = if_lookup_by_index(ndm->ndm_ifindex, VRF_DEFAULT);
        if (!ifp || sockunion_family(&addr) == AF_UNSPEC)
                return;
 
@@ -185,7 +185,7 @@ static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
        if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
                return;
 
-       ifp = if_lookup_by_index(htonl(*in_ndx));
+       ifp = if_lookup_by_index(htonl(*in_ndx), VRF_DEFAULT);
        if (!ifp)
                return;
 
index 4ac612d3adb5558b47b0876a7801531fbccd0b55..bbaa630cd5ec098e1a53ee0b0ca9ed84975fbc3e 100644 (file)
@@ -117,7 +117,7 @@ static void nhrp_interface_update_nbma(struct interface *ifp)
        sockunion_family(&nbma) = AF_UNSPEC;
 
        if (nifp->source)
-               nbmaifp = if_lookup_by_name(nifp->source);
+          nbmaifp = if_lookup_by_name(nifp->source, VRF_DEFAULT);
 
        switch (ifp->ll_type) {
        case ZEBRA_LLT_IPGRE: {
@@ -127,7 +127,7 @@ static void nhrp_interface_update_nbma(struct interface *ifp)
                        if (saddr.s_addr)
                                sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr));
                        else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
-                               nbmaifp = if_lookup_by_index(nifp->linkidx);
+                          nbmaifp = if_lookup_by_index(nifp->linkidx, VRF_DEFAULT);
                }
                break;
        default:
index 5d2866a67e36aed5402cf04f4729d21751a5b259..36dbdfd7772d1589dfa88884b22c3d1ed5b3b2e5 100644 (file)
@@ -290,7 +290,7 @@ static int nhrp_packet_recvraw(struct thread *t)
                goto err;
        }
 
-       ifp = if_lookup_by_index(ifindex);
+       ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
        if (!ifp) goto err;
 
        p = nhrp_peer_get(ifp, &remote_nbma);
index 73b6aaccf6720d50d71d514ef49bccd23b9d07ce..4c1d97a4898e51a9988f5bb91e1fb05ff437b57f 100644 (file)
@@ -425,7 +425,6 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
                nbma_natoa = NULL;
                if (natted) {
                        nbma_natoa = nbma_addr;
-                       nbma_addr = &p->peer->vc->remote.nbma;
                }
 
                holdtime = htons(cie->holding_time);
index 8d066eeaefbb44d0bb5c721ff43fe793d0152222..69c55e305869de8c9577e257523ce48e20a12a15 100644 (file)
@@ -198,7 +198,7 @@ int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_i
                for (i = 0; i < ifindex_num; i++) {
                        ifindex = stream_getl(s);
                        if (i == 0 && ifindex != IFINDEX_INTERNAL)
-                               ifp = if_lookup_by_index(ifindex);
+                          ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
                }
        }
        if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
index 06fc7a30afe969ed453a4754163bcd7bdd510de7..75dd8ffe460462c3bf4b3479ef43a432c957f0cf 100644 (file)
@@ -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,13 @@ 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_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ospf6d_snmp_la_LIBADD = ../lib/libfrrsnmp.la
+
 examplesdir = $(exampledir)
 dist_examples_DATA = ospf6d.conf.sample
index 5f2d662b78573e2d053c627d6d39a640f7814477..8caae502211fba50588af1169a6fb5688a6009b9 100644 (file)
@@ -866,7 +866,7 @@ ospf6_routemap_rule_match_interface (void *rule, struct prefix *prefix,
   if (type == RMAP_OSPF6)
     {
       ei = ((struct ospf6_route *) object)->route_option;
-      ifp = if_lookup_by_name ((char *)rule);
+      ifp = if_lookup_by_name ((char *)rule, VRF_DEFAULT);
 
       if (ifp != NULL
       &&  ei->ifindex == ifp->ifindex)
index 8998799cf6c998154bbd34f35d2743e2846f0226..8cf7f4afaadb83a5e68e5ac55fbe618de9173e70 100644 (file)
 #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;
 
@@ -69,7 +71,7 @@ ospf6_interface_lookup_by_ifindex (ifindex_t ifindex)
   struct ospf6_interface *oi;
   struct interface *ifp;
 
-  ifp = if_lookup_by_index (ifindex);
+  ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
   if (ifp == NULL)
     return (struct ospf6_interface *) NULL;
 
@@ -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);
 }
 
 
@@ -1006,7 +999,7 @@ DEFUN (show_ipv6_ospf6_interface,
 
   if (argc == 5)
     {
-      ifp = if_lookup_by_name (argv[idx_ifname]->arg);
+      ifp = if_lookup_by_name (argv[idx_ifname]->arg, VRF_DEFAULT);
       if (ifp == NULL)
         {
           vty_out (vty, "No such Interface: %s%s", argv[idx_ifname]->arg,
@@ -1043,7 +1036,7 @@ DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
   struct interface *ifp;
   struct ospf6_interface *oi;
 
-  ifp = if_lookup_by_name (argv[idx_ifname]->arg);
+  ifp = if_lookup_by_name (argv[idx_ifname]->arg, VRF_DEFAULT);
   if (ifp == NULL)
     {
       vty_out (vty, "No such Interface: %s%s", argv[idx_ifname]->arg, VNL);
@@ -1897,7 +1890,7 @@ DEFUN (clear_ipv6_ospf6_interface,
     }
   else /* Interface name is specified. */
     {
-      if ((ifp = if_lookup_by_name (argv[idx_ifname]->arg)) == NULL)
+      if ((ifp = if_lookup_by_name (argv[idx_ifname]->arg, VRF_DEFAULT)) == NULL)
         {
           vty_out (vty, "No such Interface: %s%s", argv[idx_ifname]->arg, VNL);
           return CMD_WARNING;
index 179477a634d2d18e49bd66c0e893768ecffe702c..846cde41919a57d9eab6cba19b355f9d550e3f5d 100644 (file)
@@ -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 */
index d93406fb68bfe1d5eb309edb5048d08dbb9ea418..6461963856024e7daf4bc5dc858e8585060ada58 100644 (file)
@@ -30,6 +30,7 @@
 #include "table.h"
 #include "vty.h"
 #include "command.h"
+#include "vrf.h"
 
 #include "ospf6_proto.h"
 #include "ospf6_message.h"
@@ -1311,7 +1312,7 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
 
       if (direct_connect)
         {
-          ifp = if_lookup_prefix(&route->prefix);
+          ifp = if_lookup_prefix(&route->prefix, VRF_DEFAULT);
           if (ifp)
            ospf6_route_add_nexthop (route, ifp->ifindex, NULL);
         }
index ec79a1552bf3a02f4e02dcdc573df0cd5508d214..118210dfc7dc4ecfc927eac8abad7c3ca147ae49 100644 (file)
@@ -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"
 #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);
 }
 
index f9e197e99bbd03b251864be9744e9ef3c06791fd..c275ff830e73f1f19193f08926cb0a74870e8a14 100644 (file)
@@ -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 */
index 29956c61a0c03514aaad570f4bd02b00334aef1b..b8e5ca6196e73048ad2b4e32679865ba3bbda56d 100644 (file)
@@ -349,7 +349,7 @@ ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
            {
              const char *ifname;
              inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf));
-             ifname = ifindex2ifname (nh->ifindex);
+             ifname = ifindex2ifname (nh->ifindex, VRF_DEFAULT);
              zlog_debug ("  nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
                          nh->ifindex);
            }
@@ -1040,7 +1040,7 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
       /* nexthop */
       inet_ntop (AF_INET6, &nh->address, nexthop,
                  sizeof (nexthop));
-      ifname = ifindex2ifname (nh->ifindex);     
+      ifname = ifindex2ifname (nh->ifindex, VRF_DEFAULT);
 
       if (!i)
        {
@@ -1146,7 +1146,7 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
     {
       /* nexthop */
       inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop));
-      ifname = ifindex2ifname (nh->ifindex);
+      ifname = ifindex2ifname (nh->ifindex, VRF_DEFAULT);
       vty_out (vty, "  %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
     }
   vty_out (vty, "%s", VNL);
index 86cfd17c83f39fbd1c51be3a6f7193662b94b8f5..96f1e3dd219c006a5fb008edba7f8db8d4a2d37c 100644 (file)
@@ -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 (file)
index fa1b0c3..0000000
+++ /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*/
-
-
index 92111c73fc4ab53b1e062ae1386d6cd1a3d90ddc..f2a1c8c2ecfbc65f0a88018f11f3645b920e6926 100644 (file)
@@ -29,6 +29,7 @@
 #include "table.h"
 #include "thread.h"
 #include "command.h"
+#include "defaults.h"
 
 #include "ospf6_proto.h"
 #include "ospf6_message.h"
@@ -160,7 +161,10 @@ ospf6_create (void)
   o->distance_table = route_table_init ();
 
   /* Enable "log-adjacency-changes" */
+#if DFLT_OSPF6_LOG_ADJACENCY_CHANGES
   SET_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES);
+#endif
+
   QOBJ_REG (o, ospf6);
 
   return o;
@@ -288,7 +292,7 @@ ospf6_maxage_remove (struct ospf6 *o)
 }
 
 /* start ospf6 */
-DEFUN (router_ospf6,
+DEFUN_NOSH (router_ospf6,
        router_ospf6_cmd,
        "router ospf6",
        ROUTER_STR
@@ -391,7 +395,6 @@ DEFUN (no_ospf6_log_adjacency_changes_detail,
   VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 
   UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL);
-  UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES);
   return CMD_SUCCESS;
 }
 
@@ -470,21 +473,9 @@ DEFUN (no_ospf6_distance,
 
 DEFUN (ospf6_distance_ospf6,
        ospf6_distance_ospf6_cmd,
-       "distance ospf6 <intra-area (1-255)|inter-area (1-255)|external (1-255)> <intra-area (1-255)|inter-area (1-255)|external (1-255)> <intra-area (1-255)|inter-area (1-255)|external (1-255)>",
+       "distance ospf6 {intra-area (1-255)|inter-area (1-255)|external (1-255)}",
        "Administrative distance\n"
-       "OSPF6 distance\n"
-       "Intra-area routes\n"
-       "Distance for intra-area routes\n"
-       "Inter-area routes\n"
-       "Distance for inter-area routes\n"
-       "External routes\n"
-       "Distance for external routes\n"
-       "Intra-area routes\n"
-       "Distance for intra-area routes\n"
-       "Inter-area routes\n"
-       "Distance for inter-area routes\n"
-       "External routes\n"
-       "Distance for external routes\n"
+       "OSPF6 administrative distance\n"
        "Intra-area routes\n"
        "Distance for intra-area routes\n"
        "Inter-area routes\n"
@@ -493,53 +484,23 @@ DEFUN (ospf6_distance_ospf6,
        "Distance for external routes\n")
 {
   VTY_DECLVAR_CONTEXT(ospf6, o);
-
-  char *intra, *inter, *external;
-  intra = inter = external = NULL;
-
   int idx = 0;
-  if (argv_find (argv, argc, "intra-area", &idx))
-    intra = argv[++idx]->arg;
-  if (argv_find (argv, argc, "intra-area", &idx))
-  {
-    vty_out (vty, "%% Cannot specify intra-area distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
 
+  if (argv_find (argv, argc, "intra-area", &idx))
+    o->distance_intra = atoi(argv[idx + 1]->arg);
   idx = 0;
   if (argv_find (argv, argc, "inter-area", &idx))
-    inter = argv[++idx]->arg;
-  if (argv_find (argv, argc, "inter-area", &idx))
-  {
-    vty_out (vty, "%% Cannot specify inter-area distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
-
+    o->distance_inter = atoi(argv[idx + 1]->arg);
   idx = 0;
   if (argv_find (argv, argc, "external", &idx))
-    external = argv[++idx]->arg;
-  if (argv_find (argv, argc, "external", &idx))
-  {
-    vty_out (vty, "%% Cannot specify external distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
-
-
-  if (intra)
-    o->distance_intra = atoi (intra);
-
-  if (inter)
-    o->distance_inter = atoi (inter);
-
-  if (external)
-    o->distance_external = atoi (external);
+    o->distance_external = atoi(argv[idx + 1]->arg);
 
   return CMD_SUCCESS;
 }
 
 DEFUN (no_ospf6_distance_ospf6,
        no_ospf6_distance_ospf6_cmd,
-       "no distance ospf6 [<intra-area (1-255)|inter-area (1-255)|external (1-255)> <intra-area (1-255)|inter-area (1-255)|external (1-255)> <intra-area (1-255)|inter-area (1-255)|external (1-255)>]",
+       "no distance ospf6 [{intra-area [(1-255)]|inter-area [(1-255)]|external [(1-255)]}]",
        NO_STR
        "Administrative distance\n"
        "OSPF6 distance\n"
@@ -548,70 +509,16 @@ DEFUN (no_ospf6_distance_ospf6,
        "Inter-area routes\n"
        "Distance for inter-area routes\n"
        "External routes\n"
-       "Distance for external routes\n"
-       "Intra-area routes\n"
-       "Distance for intra-area routes\n"
-       "Inter-area routes\n"
-       "Distance for inter-area routes\n"
-       "External routes\n"
-       "Distance for external routes\n"
-       "Intra-area routes\n"
-       "Distance for intra-area routes\n"
-       "Inter-area routes\n"
-       "Distance for inter-area routes\n"
-       "External routes\n"
        "Distance for external routes\n")
 {
   VTY_DECLVAR_CONTEXT(ospf6, o);
-
-  char *intra, *inter, *external;
-  intra = inter = external = NULL;
-
-  if (argc == 3)
-  {
-    /* If no arguments are given, clear all distance information */
-    o->distance_intra = 0;
-    o->distance_inter = 0;
-    o->distance_external = 0;
-    return CMD_SUCCESS;
-  }
-
   int idx = 0;
-  if (argv_find (argv, argc, "intra-area", &idx))
-    intra = argv[++idx]->arg;
-  if (argv_find (argv, argc, "intra-area", &idx))
-  {
-    vty_out (vty, "%% Cannot specify intra-area distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
 
-  idx = 0;
-  if (argv_find (argv, argc, "inter-area", &idx))
-    inter = argv[++idx]->arg;
-  if (argv_find (argv, argc, "inter-area", &idx))
-  {
-    vty_out (vty, "%% Cannot specify inter-area distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
-
-  idx = 0;
-  if (argv_find (argv, argc, "external", &idx))
-    external = argv[++idx]->arg;
-  if (argv_find (argv, argc, "external", &idx))
-  {
-    vty_out (vty, "%% Cannot specify external distance twice%s", VTY_NEWLINE);
-    return CMD_WARNING;
-  }
-  if (argc < 3) /* should not happen */
-    return CMD_WARNING;
-
-  if (intra)
-    o->distance_intra = 0;
-
-  if (inter)
-    o->distance_inter = 0;
-
-  if (external)
+  if (argv_find (argv, argc, "intra-area", &idx) || argc == 3)
+    idx = o->distance_intra = 0;
+  if (argv_find (argv, argc, "inter-area", &idx) || argc == 3)
+    idx = o->distance_inter = 0;
+  if (argv_find (argv, argc, "external", &idx) || argc == 3)
     o->distance_external = 0;
 
   return CMD_SUCCESS;
@@ -668,7 +575,7 @@ DEFUN (ospf6_interface_area,
   u_int32_t area_id;
 
   /* find/create ospf6 interface */
-  ifp = if_get_by_name (argv[idx_ifname]->arg);
+  ifp = if_get_by_name (argv[idx_ifname]->arg, VRF_DEFAULT);
   oi = (struct ospf6_interface *) ifp->info;
   if (oi == NULL)
     oi = ospf6_interface_create (ifp);
@@ -728,7 +635,7 @@ DEFUN (no_ospf6_interface_area,
   struct interface *ifp;
   u_int32_t area_id;
 
-  ifp = if_lookup_by_name (argv[idx_ifname]->arg);
+  ifp = if_lookup_by_name (argv[idx_ifname]->arg, VRF_DEFAULT);
   if (ifp == NULL)
     {
       vty_out (vty, "No such interface %s%s", argv[idx_ifname]->arg, VNL);
@@ -1118,8 +1025,10 @@ config_write_ospf6 (struct vty *vty)
     {
       if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL))
         vty_out(vty, " log-adjacency-changes detail%s", VTY_NEWLINE);
+      else if (!DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
+        vty_out(vty, " log-adjacency-changes%s", VTY_NEWLINE);
     }
-  else
+  else if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
     {
       vty_out(vty, " no log-adjacency-changes%s", VTY_NEWLINE);
     }
index 2aaed5fcbf3f6d411e320a39165bfffc676d5b42..036cc6d4c85ca21b6d5843a2b57494f138df24a0 100644 (file)
 #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);
 
index 71e0df0dc53202864313b0efcaadc65cc4a3e912..c6a5ec91d2aca95f1a71bbe864953d9d1bb856ef 100644 (file)
@@ -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,21 @@ 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_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ospfd_snmp_la_LIBADD = ../lib/libfrrsnmp.la
+
 EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt
 
 examplesdir = $(exampledir)
index 20e7740d32019bdfdd3cc77a72a07597f3e62c3c..5ef262ce5414b4be247bbcbfd08b0eec34c9765c 100644 (file)
@@ -2,7 +2,7 @@
  * OSPFd dump routine (parts used by ospfclient).
  * Copyright (C) 1999, 2000 Toshiaki Takada
  *
- * This file is part of FreeRangeRouting (FRR).
+ * This file is part of FRRouting (FRR).
  *
  * FRR 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
index c3ff1e3f5438f66c76a0c2e93b31e2cde2fab06d..1cd8257f0ca613a49d42a4878051959d39ed1934 100644 (file)
@@ -2,7 +2,7 @@
  * OSPFd dump routine (parts used by ospfclient).
  * Copyright (C) 1999 Toshiaki Takada
  *
- * This file is part of FreeRangeRouting (FRR).
+ * This file is part of FRRouting (FRR).
  *
  * FRR 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
index 936ec69666b80e8d4653780b6755510d73a277b4..b4a282a52a1ed324c2f5b6e96b585d1af9089149 100644 (file)
 #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)
@@ -874,7 +873,7 @@ ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data)
     zlog_debug ("ospf_vl_new(): creating pseudo zebra interface");
 
   snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count);
-  vi = if_create (ifname, strnlen(ifname, sizeof(ifname)));
+  vi = if_create (ifname, strnlen(ifname, sizeof(ifname)), VRF_DEFAULT);
   /*
    * if_create sets ZEBRA_INTERFACE_LINKDETECTION
    * virtual links don't need this.
@@ -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);
index bd51bbf422a5c617415b629e39e475de06ea16de..39202f777a5cf5d30f1db4a19a5fc9ca2f043390 100644 (file)
@@ -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 */
index 9630616accef27c6e42256ac73e6f0f1022206bb..717c99c21f23507e2fc2c08ba00e94afb2325349 100644 (file)
 #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);
index f0357a482421c367d2605aed324c0676fa0017b0..fa8e6d70f67f8adf0110d4fe6e7646a928830816 100644 (file)
@@ -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
 #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 */
index f462c207e4597d3f1cdfbdd99a2435fa6ce1cd45..38718b35d5a491fc7b9053945926286c6c70c4a6 100644 (file)
@@ -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
index 01617055ce1b3a42a164a57d0c167e54a021dad3..97f3f6a3829d4546ae0ae9eb7ffd545c04e6d8f5 100644 (file)
 #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. */
index 9b7e14a4ae71c451eea60bd26eacf35bf67d5925..4531f6ec7da0ed52e5593618c0f34ef5aee5f553 100644 (file)
@@ -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 */
 
index a0cc367cd73c92eecfd9157428bc0c75e65031c9..b7721adb3e53d8ff70ce7b21b3561c248c3a0c60 100644 (file)
@@ -35,6 +35,7 @@
 #include "sockopt.h"
 #include "checksum.h"
 #include "md5.h"
+#include "vrf.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_network.h"
@@ -2218,7 +2219,7 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
 
   ifindex = getsockopt_ifindex (AF_INET, &msgh);
   
-  *ifp = if_lookup_by_index (ifindex);
+  *ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
 
   if (ret != ip_len)
     {
@@ -2788,7 +2789,7 @@ ospf_read (struct thread *thread)
       /* Handle cases where the platform does not support retrieving the ifindex,
         and also platforms (such as Solaris 8) that claim to support ifindex
         retrieval but do not. */
-      c = if_lookup_address ((void *)&iph->ip_src, AF_INET);
+      c = if_lookup_address ((void *)&iph->ip_src, AF_INET, VRF_DEFAULT);
       if (c)
        ifp = c->ifp;
       if (ifp == NULL)
index 717dc25f94e7bbf1c3d7edc768af70ec67f0ce4e..db51abca230d832cb9f9586ac0b051563b8a171f 100644 (file)
@@ -32,6 +32,7 @@
 #include "command.h"
 #include "log.h"
 #include "plist.h"
+#include "vrf.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_asbr.h"
@@ -360,7 +361,7 @@ route_match_interface (void *rule, struct prefix *prefix,
   if (type == RMAP_OSPF)
     {
       ei = object;
-      ifp = if_lookup_by_name ((char *)rule);
+      ifp = if_lookup_by_name ((char *)rule, VRF_DEFAULT);
 
       if (ifp == NULL || ifp->ifindex != ei->ifindex)
        return RMAP_NOMATCH;
index 4afbda878894b0ba21189dc0aa3270f32ce8adb8..32449d55976af1420b41440c831803dd74bdcd1d 100644 (file)
@@ -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
 #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 (file)
index 413d1d7..0000000
+++ /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 */
index 077d0e68adc73de93c5305e66e4341ae10545b59..31f0d9d286f5620c2d005bb2a28a3aa861954c9a 100644 (file)
@@ -1159,14 +1159,14 @@ ospf_rtrs_print (struct route_table *rtrs)
                 {
                   if (IS_DEBUG_OSPF_EVENT)
                     zlog_debug ("   directly attached to %s\r\n",
-                               ifindex2ifname (path->ifindex));
+                               ifindex2ifname (path->ifindex), VRF_DEFAULT);
                 }
               else
                 {
                   if (IS_DEBUG_OSPF_EVENT)
                     zlog_debug ("   via %s, %s\r\n",
                                inet_ntoa (path->nexthop),
-                               ifindex2ifname (path->ifindex));
+                               ifindex2ifname (path->ifindex), VRF_DEFAULT);
                 }
             }
         }
index 4c5862e84a54bccb0b60d3591dad3b10be973907..449f9e7b97f7f7767bc529c6052f5bba9c1a4b0f 100644 (file)
@@ -2630,7 +2630,7 @@ DEFUN (show_ip_ospf_mpls_te_link,
   /* Interface name is specified. */
   else
     {
-      if ((ifp = if_lookup_by_name (argv[idx_interface]->arg)) == NULL)
+      if ((ifp = if_lookup_by_name (argv[idx_interface]->arg, VRF_DEFAULT)) == NULL)
         vty_out (vty, "No such interface name%s", VTY_NEWLINE);
       else
         show_mpls_te_link_sub (vty, ifp);
index ce4bc9dfaa5e3ec4f1c7f46e80fc574e9dbec990..49474df82626649fbb32591fe1d3354582bd6a8e 100644 (file)
@@ -34,6 +34,7 @@
 #include "log.h"
 #include "zclient.h"
 #include <lib/json.h>
+#include "defaults.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_asbr.h"
@@ -144,7 +145,7 @@ ospf_oi_count (struct interface *ifp)
   return i;
 }
 
-DEFUN (router_ospf,
+DEFUN_NOSH (router_ospf,
        router_ospf_cmd,
        "router ospf [(1-65535)]",
        "Enable a routing process\n"
@@ -387,7 +388,7 @@ DEFUN (ospf_passive_interface,
       return CMD_SUCCESS;
     }
 
-  ifp = if_get_by_name (argv[1]->arg);
+  ifp = if_get_by_name (argv[1]->arg, VRF_DEFAULT);
 
   params = IF_DEF_PARAMS (ifp);
 
@@ -457,7 +458,7 @@ DEFUN (no_ospf_passive_interface,
       return CMD_SUCCESS;
     }
     
-  ifp = if_get_by_name (argv[2]->arg);
+  ifp = if_get_by_name (argv[2]->arg, VRF_DEFAULT);
 
   params = IF_DEF_PARAMS (ifp);
 
@@ -2137,7 +2138,6 @@ DEFUN (no_ospf_log_adjacency_changes_detail,
 {
   VTY_DECLVAR_CONTEXT(ospf, ospf);
 
-  UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES);
   UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL);
   return CMD_SUCCESS;
 }
@@ -3592,7 +3592,7 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc,
   else
     {
       /* Interface name is specified. */
-      if ((ifp = if_lookup_by_name (argv[iface_argv]->arg)) == NULL)
+      if ((ifp = if_lookup_by_name (argv[iface_argv]->arg, VRF_DEFAULT)) == NULL)
         {
           if (use_json)
               json_object_boolean_true_add(json, "noSuchIface");
@@ -3950,7 +3950,7 @@ show_ip_ospf_neighbor_int_common (struct vty *vty, struct ospf *ospf, int arg_ba
                  VTY_NEWLINE, VTY_NEWLINE);
     }
 
-  ifp = if_lookup_by_name (argv[arg_base]->arg);
+  ifp = if_lookup_by_name (argv[arg_base]->arg, VRF_DEFAULT);
   if (!ifp)
     {
       if (use_json)
@@ -4609,7 +4609,7 @@ show_ip_ospf_neighbor_int_detail_common (struct vty *vty, struct ospf *ospf,
                  VTY_NEWLINE, VTY_NEWLINE);
     }
 
-  ifp = if_lookup_by_name (argv[arg_base]->arg);
+  ifp = if_lookup_by_name (argv[arg_base]->arg, VRF_DEFAULT);
   if (!ifp)
     {
       if (!use_json)
@@ -7458,7 +7458,7 @@ DEFUN (no_ospf_default_metric,
 DEFUN (ospf_distance,
        ospf_distance_cmd,
        "distance (1-255)",
-       "Define an administrative distance\n"
+       "Administrative distance\n"
        "OSPF Administrative distance\n")
 {
   VTY_DECLVAR_CONTEXT(ospf, ospf);
@@ -7473,7 +7473,7 @@ DEFUN (no_ospf_distance,
        no_ospf_distance_cmd,
        "no distance (1-255)",
        NO_STR
-       "Define an administrative distance\n"
+       "Administrative distance\n"
        "OSPF Administrative distance\n")
 {
   VTY_DECLVAR_CONTEXT(ospf, ospf);
@@ -7485,10 +7485,10 @@ DEFUN (no_ospf_distance,
 
 DEFUN (no_ospf_distance_ospf,
        no_ospf_distance_ospf_cmd,
-       "no distance ospf [<intra-area (1-255)|inter-area (1-255)|external (1-255)>]",
+       "no distance ospf [{intra-area [(1-255)]|inter-area [(1-255)]|external [(1-255)]}]",
        NO_STR
-       "Define an administrative distance\n"
-       "OSPF Administrative distance\n"
+       "Administrative distance\n"
+       "OSPF administrative distance\n"
        "Intra-area routes\n"
        "Distance for intra-area routes\n"
        "Inter-area routes\n"
@@ -7497,42 +7497,26 @@ DEFUN (no_ospf_distance_ospf,
        "Distance for external routes\n")
 {
   VTY_DECLVAR_CONTEXT(ospf, ospf);
-  int idx_area_distance = 3;
-
-  if (!ospf)
-    return CMD_SUCCESS;
-
-  if (argc < 3)
-    return CMD_WARNING;
+  int idx = 0;
 
   if (!ospf)
     return CMD_SUCCESS;
 
-  if (argv[idx_area_distance]->arg != NULL)
-    ospf->distance_intra = 0;
-
-  if (argv[1] != NULL)
-    ospf->distance_inter = 0;
-
-  if (argv[2] != NULL)
+  if (argv_find (argv, argc, "intra-area", &idx) || argc == 3)
+    idx = ospf->distance_intra = 0;
+  if (argv_find (argv, argc, "inter-area", &idx) || argc == 3)
+    idx = ospf->distance_inter = 0;
+  if (argv_find (argv, argc, "external", &idx) || argc == 3)
     ospf->distance_external = 0;
 
-  if (argv[idx_area_distance]->arg || argv[1] || argv[2])
-    return CMD_SUCCESS;
-
-  /* If no arguments are given, clear all distance information */
-  ospf->distance_intra = 0;
-  ospf->distance_inter = 0;
-  ospf->distance_external = 0;
-
   return CMD_SUCCESS;
 }
 
 DEFUN (ospf_distance_ospf,
        ospf_distance_ospf_cmd,
-       "distance ospf [<intra-area (1-255)|inter-area (1-255)|external (1-255)>]",
-       "Define an administrative distance\n"
-       "OSPF Administrative distance\n"
+       "distance ospf {intra-area (1-255)|inter-area (1-255)|external (1-255)}",
+       "Administrative distance\n"
+       "OSPF administrative distance\n"
        "Intra-area routes\n"
        "Distance for intra-area routes\n"
        "Inter-area routes\n"
@@ -7541,26 +7525,16 @@ DEFUN (ospf_distance_ospf,
        "Distance for external routes\n")
 {
   VTY_DECLVAR_CONTEXT(ospf, ospf);
-  int idx_area_distance = 2;
-
-  if (argc < 3) /* should not happen */
-    return CMD_WARNING;
-
-  if (!argv[idx_area_distance]->arg && !argv[1] && !argv[2])
-    {
-      vty_out(vty, "%% Command incomplete. (Arguments required)%s",
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  if (strcmp (argv[idx_area_distance]->text, "intra") == 0)
-    ospf->distance_intra = atoi(argv[idx_area_distance+1]->arg);
-
-  if (strcmp (argv[idx_area_distance]->text, "inter") == 0)
-    ospf->distance_inter = atoi(argv[idx_area_distance+1]->arg);
+  int idx = 0;
 
-  if (strcmp (argv[idx_area_distance]->text, "external") == 0)
-    ospf->distance_external = atoi(argv[idx_area_distance+1]->arg);
+  if (argv_find (argv, argc, "intra-area", &idx))
+    ospf->distance_intra = atoi(argv[idx + 1]->arg);
+  idx = 0;
+  if (argv_find (argv, argc, "inter-area", &idx))
+    ospf->distance_inter = atoi(argv[idx + 1]->arg);
+  idx = 0;
+  if (argv_find (argv, argc, "external", &idx))
+    ospf->distance_external = atoi(argv[idx + 1]->arg);
 
   return CMD_SUCCESS;
 }
@@ -7948,15 +7922,15 @@ show_ip_ospf_route_network (struct vty *vty, struct route_table *rt)
         if (or->type == OSPF_DESTINATION_NETWORK)
           for (ALL_LIST_ELEMENTS (or->paths, pnode, pnnode, path))
             {
-              if (if_lookup_by_index(path->ifindex))
+              if (if_lookup_by_index(path->ifindex, VRF_DEFAULT))
                 {
                   if (path->nexthop.s_addr == 0)
                     vty_out (vty, "%24s   directly attached to %s%s",
-                             "", ifindex2ifname (path->ifindex), VTY_NEWLINE);
+                             "", ifindex2ifname (path->ifindex, VRF_DEFAULT), VTY_NEWLINE);
                   else
                     vty_out (vty, "%24s   via %s, %s%s", "",
                              inet_ntoa (path->nexthop),
-                            ifindex2ifname (path->ifindex), VTY_NEWLINE);
+                            ifindex2ifname (path->ifindex, VRF_DEFAULT), VTY_NEWLINE);
                 }
             }
       }
@@ -7998,16 +7972,16 @@ show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs)
                   
                   for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
                     {
-                     if (if_lookup_by_index(path->ifindex))
+                     if (if_lookup_by_index(path->ifindex, VRF_DEFAULT))
                        {
                          if (path->nexthop.s_addr == 0)
                            vty_out (vty, "%24s   directly attached to %s%s",
-                                    "", ifindex2ifname (path->ifindex),
+                                    "", ifindex2ifname (path->ifindex, VRF_DEFAULT),
                                     VTY_NEWLINE);
                          else
                            vty_out (vty, "%24s   via %s, %s%s", "",
                                     inet_ntoa (path->nexthop),
-                                    ifindex2ifname (path->ifindex),
+                                    ifindex2ifname (path->ifindex, VRF_DEFAULT),
                                     VTY_NEWLINE);
                        }
                     }
@@ -8047,15 +8021,15 @@ show_ip_ospf_route_external (struct vty *vty, struct route_table *rt)
 
         for (ALL_LIST_ELEMENTS (er->paths, pnode, pnnode, path))
           {
-            if (if_lookup_by_index(path->ifindex))
+            if (if_lookup_by_index(path->ifindex, VRF_DEFAULT))
               {
                 if (path->nexthop.s_addr == 0)
                   vty_out (vty, "%24s   directly attached to %s%s",
-                           "", ifindex2ifname (path->ifindex), VTY_NEWLINE);
+                           "", ifindex2ifname (path->ifindex, VRF_DEFAULT), VTY_NEWLINE);
                 else
                   vty_out (vty, "%24s   via %s, %s%s", "",
                            inet_ntoa (path->nexthop),
-                          ifindex2ifname (path->ifindex),
+                          ifindex2ifname (path->ifindex, VRF_DEFAULT),
                            VTY_NEWLINE);
               }
            }
@@ -8832,8 +8806,10 @@ ospf_config_write (struct vty *vty)
        {
          if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
            vty_out(vty, " log-adjacency-changes detail%s", VTY_NEWLINE);
+         else if (!DFLT_OSPF_LOG_ADJACENCY_CHANGES)
+           vty_out(vty, " log-adjacency-changes%s", VTY_NEWLINE);
        }
-      else
+      else if (DFLT_OSPF_LOG_ADJACENCY_CHANGES)
         {
          vty_out(vty, " no log-adjacency-changes%s", VTY_NEWLINE);
         }
@@ -9142,7 +9118,7 @@ DEFUN (clear_ip_ospf_interface,
     }
   else /* Interface name is specified. */
     {
-      if ((ifp = if_lookup_by_name (argv[idx_ifname]->text)) == NULL)
+      if ((ifp = if_lookup_by_name (argv[idx_ifname]->text, VRF_DEFAULT)) == NULL)
         vty_out (vty, "No such interface name%s", VTY_NEWLINE);
       else
         ospf_interface_clear(ifp);
index b0ff5d0e3c7973fbfe619f1567c2b1ac170676d4..abb6db0347862bda899ee7c2e98b4ce5fc1f7ff1 100644 (file)
 #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)
@@ -165,7 +161,8 @@ zebra_interface_if_lookup (struct stream *s, vrf_id_t vrf_id)
 
   /* And look it up. */
   return if_lookup_by_name_len(ifname_tmp,
-                              strnlen(ifname_tmp, INTERFACE_NAMSIZ));
+                               strnlen(ifname_tmp, INTERFACE_NAMSIZ),
+                               VRF_DEFAULT);
 }
 
 static int
@@ -276,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;
 }
@@ -323,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);
 
index 8e93ed2691b36dfc4550b4b2ef9a3d055d9503b4..22c71a49e17ff504eb3f053ead806318bbf884e5 100644 (file)
@@ -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 */
 
index 7cd3903678cbbebe4edb11a178d5abc535c5324d..30b1e9622f1c1480015ac268f0ac00be704ca34a 100644 (file)
@@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "plist.h"
 #include "sockopt.h"
 #include "bfd.h"
+#include "defaults.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_network.h"
@@ -292,7 +293,10 @@ ospf_new (u_short instance)
   new->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT;
   
   /* Enable "log-adjacency-changes" */
+#if DFLT_OSPF_LOG_ADJACENCY_CHANGES
   SET_FLAG(new->config, OSPF_LOG_ADJACENCY_CHANGES);
+#endif
+
   QOBJ_REG (new, ospf);
 
   return new;
index a3bd0ca12f068eeb67d5ab9e6e496494f9309f9a..9198d5c6203918a15cdae46af54ad3d8b69ba3ba 100644 (file)
@@ -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);
 
index 59abd1aa304b9c001ba764c6a912a5e8be60f598..77eb5c7568f628905fe8ac9af5f9719f1635b490 100644 (file)
@@ -53,7 +53,7 @@ libpim_a_SOURCES = \
        pim_ssmpingd.c pim_int.c pim_rp.c \
        pim_static.c pim_br.c pim_register.c pim_routemap.c \
        pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \
-       pim_jp_agg.c
+       pim_jp_agg.c pim_nht.c pim_ssm.c
 
 noinst_HEADERS = \
        pim_memory.h \
@@ -65,8 +65,8 @@ noinst_HEADERS = \
        pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \
        pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
        pim_static.h pim_br.h pim_register.h \
-       pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h \
-       pim_jp_agg.h
+       pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \
+       pim_jp_agg.h pim_ssm.h
 
 pimd_SOURCES = \
        pim_main.c $(libpim_a_SOURCES)
index 465c368f43476e1427d7d49868c9f6dedd3b5279..3c5a16ec68d38233641c287ca19fc573af8284bd 100644 (file)
@@ -54,6 +54,7 @@
 #include "pim_rp.h"
 #include "pim_zlookup.h"
 #include "pim_msdp.h"
+#include "pim_ssm.h"
 
 static struct cmd_node pim_global_node = {
   PIM_NODE,
@@ -1168,7 +1169,8 @@ static void pim_show_join(struct vty *vty, u_char uj)
       json_object_string_add(json_row, "upTime", uptime);
       json_object_string_add(json_row, "expire", expire);
       json_object_string_add(json_row, "prune", prune);
-      json_object_string_add(json_row, "channelJoinName", pim_ifchannel_ifjoin_name(ch->ifjoin_state));
+      json_object_string_add(json_row, "channelJoinName",
+                             pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
       if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
         json_object_int_add(json_row, "SGRpt", 1);
 
@@ -1187,7 +1189,7 @@ static void pim_show_join(struct vty *vty, u_char uj)
              inet_ntoa(ifaddr),
              ch_src_str,
              ch_grp_str,
-             pim_ifchannel_ifjoin_name(ch->ifjoin_state),
+             pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
              uptime,
              expire,
              prune,
@@ -1422,6 +1424,14 @@ pim_show_state(struct vty *vty, const char *src_or_group, const char *group, u_c
       if (!json_ifp_in) {
         json_ifp_in = json_object_new_object();
         json_object_object_add(json_source, in_ifname, json_ifp_in);
+        json_object_int_add (json_source, "Installed", c_oil->installed);
+        json_object_int_add (json_source, "RefCount", c_oil->oil_ref_count);
+        json_object_int_add (json_source, "OilListSize", c_oil->oil_size);
+        json_object_int_add (json_source, "OilRescan", c_oil->oil_inherited_rescan);
+        json_object_int_add (json_source, "LastUsed", c_oil->cc.lastused);
+        json_object_int_add (json_source, "PacketCount", c_oil->cc.pktcnt);
+        json_object_int_add (json_source, "ByteCount", c_oil->cc.bytecnt);
+        json_object_int_add (json_source, "WrongInterface", c_oil->cc.wrong_if);
       }
     } else {
         vty_out(vty, "%-9d %-15s  %-15s  %-7s  ",
@@ -3589,6 +3599,153 @@ DEFUN (no_ip_pim_rp_prefix_list,
   return pim_no_rp_cmd_worker (vty, argv[4]->arg, NULL, argv[6]->arg);
 }
 
+static int
+pim_ssm_cmd_worker (struct vty *vty, const char *plist)
+{
+  int result = pim_ssm_range_set (VRF_DEFAULT, plist);
+
+  if (result == PIM_SSM_ERR_NONE)
+    return CMD_SUCCESS;
+
+  switch (result)
+    {
+    case PIM_SSM_ERR_NO_VRF:
+      vty_out (vty, "%% VRF doesn't exist%s", VTY_NEWLINE);
+      break;
+    case PIM_SSM_ERR_DUP:
+      vty_out (vty, "%% duplicate config%s", VTY_NEWLINE);
+      break;
+    default:
+      vty_out (vty, "%% ssm range config failed%s", VTY_NEWLINE);
+    }
+
+  return CMD_WARNING;
+}
+
+DEFUN (ip_pim_ssm_prefix_list,
+       ip_pim_ssm_prefix_list_cmd,
+       "ip pim ssm prefix-list WORD",
+       IP_STR
+       "pim multicast routing\n"
+       "Source Specific Multicast\n"
+       "group range prefix-list filter\n"
+       "Name of a prefix-list\n")
+{
+  return pim_ssm_cmd_worker (vty, argv[0]->arg);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list,
+       no_ip_pim_ssm_prefix_list_cmd,
+       "no ip pim ssm prefix-list",
+       NO_STR
+       IP_STR
+       "pim multicast routing\n"
+       "Source Specific Multicast\n"
+       "group range prefix-list filter\n")
+{
+  return pim_ssm_cmd_worker (vty, NULL);
+}
+
+DEFUN (no_ip_pim_ssm_prefix_list_name,
+       no_ip_pim_ssm_prefix_list_name_cmd,
+       "no ip pim ssm prefix-list WORD",
+       NO_STR
+       IP_STR
+       "pim multicast routing\n"
+       "Source Specific Multicast\n"
+       "group range prefix-list filter\n"
+       "Name of a prefix-list\n")
+{
+  struct pim_ssm *ssm = pimg->ssm_info;
+
+  if (ssm->plist_name && !strcmp(ssm->plist_name, argv[0]->arg))
+    return pim_ssm_cmd_worker (vty, NULL);
+
+  vty_out (vty, "%% pim ssm prefix-list %s doesn't exist%s",
+           argv[0]->arg, VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+static void
+ip_pim_ssm_show_group_range(struct vty *vty, u_char uj)
+{
+  struct pim_ssm *ssm = pimg->ssm_info;
+  const char *range_str = ssm->plist_name?ssm->plist_name:PIM_SSM_STANDARD_RANGE;
+
+  if (uj)
+    {
+      json_object *json;
+      json = json_object_new_object();
+      json_object_string_add(json, "ssmGroups", range_str);
+      vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+      json_object_free(json);
+    }
+  else
+    vty_out(vty, "SSM group range : %s%s", range_str, VTY_NEWLINE);
+}
+
+DEFUN (show_ip_pim_ssm_range,
+       show_ip_pim_ssm_range_cmd,
+       "show ip pim group-type [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       "PIM group type\n"
+       "JavaScript Object Notation\n")
+{
+  u_char uj = use_json(argc, argv);
+  ip_pim_ssm_show_group_range(vty, uj);
+
+  return CMD_SUCCESS;
+}
+
+static void
+ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, const char *group)
+{
+  struct in_addr group_addr;
+  const char *type_str;
+  int result;
+
+  result = inet_pton(AF_INET, group, &group_addr);
+  if (result <= 0)
+    type_str = "invalid";
+  else
+    {
+      if (pim_is_group_224_4 (group_addr))
+        type_str = pim_is_grp_ssm (group_addr)?"SSM":"ASM";
+      else
+        type_str = "not-multicast";
+    }
+
+  if (uj)
+    {
+      json_object *json;
+      json = json_object_new_object();
+      json_object_string_add(json, "groupType", type_str);
+      vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+      json_object_free(json);
+    }
+  else
+    vty_out(vty, "Group type : %s%s", type_str, VTY_NEWLINE);
+}
+
+DEFUN (show_ip_pim_group_type,
+       show_ip_pim_group_type_cmd,
+       "show ip pim group-type A.B.C.D [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       "multicast group type\n"
+       "group address\n"
+       "JavaScript Object Notation\n")
+{
+  u_char uj = use_json(argc, argv);
+  ip_pim_ssm_show_group_type(vty, uj, argv[0]->arg);
+
+  return CMD_SUCCESS;
+}
+
 DEFUN_HIDDEN (ip_multicast_routing,
               ip_multicast_routing_cmd,
               "ip multicast-routing",
@@ -4283,7 +4440,7 @@ DEFUN (interface_no_ip_pim_drprio,
 }
 
 static int
-pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
+pim_cmd_interface_add (struct interface *ifp)
 {
   struct pim_interface *pim_ifp = ifp->info;
 
@@ -4297,14 +4454,12 @@ pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
     PIM_IF_DO_PIM(pim_ifp->options);
   }
 
-  pim_ifp->itype = itype;
   pim_if_addr_add_all(ifp);
   pim_if_membership_refresh(ifp);
   return 1;
 }
 
-
-DEFUN (interface_ip_pim_ssm,
+DEFUN_HIDDEN (interface_ip_pim_ssm,
        interface_ip_pim_ssm_cmd,
        "ip pim ssm",
        IP_STR
@@ -4313,11 +4468,12 @@ DEFUN (interface_ip_pim_ssm,
 {
   VTY_DECLVAR_CONTEXT(interface, ifp);
 
-  if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SSM)) {
-    vty_out(vty, "Could not enable PIM SSM on interface%s", VTY_NEWLINE);
+  if (!pim_cmd_interface_add(ifp)) {
+    vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
     return CMD_WARNING;
   }
 
+  vty_out(vty, "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed%s", VTY_NEWLINE);
   return CMD_SUCCESS;
 }
 
@@ -4329,7 +4485,7 @@ DEFUN (interface_ip_pim_sm,
        IFACE_PIM_SM_STR)
 {
   VTY_DECLVAR_CONTEXT(interface, ifp);
-  if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SM)) {
+  if (!pim_cmd_interface_add(ifp)) {
     vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
     return CMD_WARNING;
   }
@@ -4365,7 +4521,7 @@ pim_cmd_interface_delete (struct interface *ifp)
   return 1;
 }
 
-DEFUN (interface_no_ip_pim_ssm,
+DEFUN_HIDDEN (interface_no_ip_pim_ssm,
        interface_no_ip_pim_ssm_cmd,
        "no ip pim ssm",
        NO_STR
@@ -4418,7 +4574,7 @@ DEFUN (interface_ip_mroute,
    int               result;
 
    oifname = argv[idx_interface]->arg;
-   oif = if_lookup_by_name(oifname);
+   oif = if_lookup_by_name(oifname, VRF_DEFAULT);
    if (!oif) {
      vty_out(vty, "No such interface name %s%s",
         oifname, VTY_NEWLINE);
@@ -4465,7 +4621,7 @@ DEFUN (interface_ip_mroute_source,
    int               result;
 
    oifname = argv[idx_interface]->arg;
-   oif = if_lookup_by_name(oifname);
+   oif = if_lookup_by_name(oifname, VRF_DEFAULT);
    if (!oif) {
      vty_out(vty, "No such interface name %s%s",
         oifname, VTY_NEWLINE);
@@ -4516,7 +4672,7 @@ DEFUN (interface_no_ip_mroute,
    int               result;
 
    oifname = argv[idx_interface]->arg;
-   oif = if_lookup_by_name(oifname);
+   oif = if_lookup_by_name(oifname, VRF_DEFAULT);
    if (!oif) {
      vty_out(vty, "No such interface name %s%s",
         oifname, VTY_NEWLINE);
@@ -4564,7 +4720,7 @@ DEFUN (interface_no_ip_mroute_source,
    int               result;
 
    oifname = argv[idx_interface]->arg;
-   oif = if_lookup_by_name(oifname);
+   oif = if_lookup_by_name(oifname, VRF_DEFAULT);
    if (!oif) {
      vty_out(vty, "No such interface name %s%s",
         oifname, VTY_NEWLINE);
@@ -6020,6 +6176,9 @@ void pim_cmd_init()
   install_element (CONFIG_NODE, &no_ip_pim_rp_cmd);
   install_element (CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
   install_element (CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
+  install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
   install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
   install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
   install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
@@ -6177,6 +6336,8 @@ void pim_cmd_init()
   install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd);
   install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
   install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
+  install_element (VIEW_NODE, &show_ip_pim_ssm_range_cmd);
+  install_element (VIEW_NODE, &show_ip_pim_group_type_cmd);
   install_element (INTERFACE_NODE, &interface_pim_use_source_cmd);
   install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd);
 }
index 94ee07a0e5fe031399a71bbf003ae74319d06645..086479643166c5b03bc7e145e0ac31da5d3117ef 100644 (file)
@@ -858,7 +858,7 @@ pim_find_primary_addr (struct interface *ifp)
   if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
     {
       struct interface *lo_ifp;
-      lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
+      lo_ifp = if_lookup_by_name ("lo", VRF_DEFAULT);
       if (lo_ifp)
        return pim_find_primary_addr (lo_ifp);
     }
@@ -1005,7 +1005,7 @@ struct interface *pim_if_find_by_vif_index(ifindex_t vif_index)
   struct interface *ifp;
 
   if (vif_index == 0)
-    return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT);
+    return if_lookup_by_name ("pimreg", VRF_DEFAULT);
 
   for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
     if (ifp->info) {
@@ -1028,7 +1028,7 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
   struct pim_interface *pim_ifp;
   struct interface *ifp;
 
-  ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
+  ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
   if (!ifp || !ifp->info)
     return -1;
   pim_ifp = ifp->info;
@@ -1471,7 +1471,7 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp)
 void pim_if_create_pimreg (void)
 {
   if (!pim_regiface) {
-    pim_regiface = if_create("pimreg", strlen("pimreg"));
+    pim_regiface = if_create("pimreg", strlen("pimreg"), VRF_DEFAULT);
     pim_regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
 
     pim_if_new(pim_regiface, 0, 0);
index 8d332c70b08a333458c85df7bdf26241f6b72133..e98c17fed287fc0e902400d60ed256425fce072a 100644 (file)
@@ -58,11 +58,6 @@ struct pim_iface_upstream_switch {
   struct list *us;
 };
 
-enum pim_interface_type {
-  PIM_INTERFACE_SSM,
-  PIM_INTERFACE_SM
-};
-
 enum pim_secondary_addr_flags {
   PIM_SEC_ADDRF_NONE = 0,
   PIM_SEC_ADDRF_STALE = (1 << 0)
@@ -74,7 +69,6 @@ struct pim_secondary_addr {
 };
 
 struct pim_interface {
-  enum pim_interface_type itype;
   uint32_t       options;                            /* bit vector */
   ifindex_t      mroute_vif_index;
   struct in_addr primary_address; /* remember addr to detect change */
index ee75793024386761e9ccd47099565ccd00584141..e6b4ba92a90810a2538178b31f068bf04546e6c0 100644 (file)
@@ -41,6 +41,7 @@
 #include "pim_macro.h"
 #include "pim_oil.h"
 #include "pim_upstream.h"
+#include "pim_ssm.h"
 
 int
 pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
@@ -239,15 +240,15 @@ void pim_ifchannel_ifjoin_switch(const char *caller,
     zlog_debug ("PIM_IFCHANNEL(%s): %s is switching from %s to %s",
                ch->interface->name,
                ch->sg_str,
-               pim_ifchannel_ifjoin_name (ch->ifjoin_state),
-               pim_ifchannel_ifjoin_name (new_state));
+               pim_ifchannel_ifjoin_name (ch->ifjoin_state, ch->flags),
+               pim_ifchannel_ifjoin_name (new_state, 0));
 
 
   if (old_state == new_state) {
     if (PIM_DEBUG_PIM_EVENTS) {
       zlog_debug("%s calledby %s: non-transition on state %d (%s)",
                 __PRETTY_FUNCTION__, caller, new_state,
-                pim_ifchannel_ifjoin_name(new_state));
+                pim_ifchannel_ifjoin_name(new_state, 0));
     }
     return;
   }
@@ -331,15 +332,31 @@ void pim_ifchannel_ifjoin_switch(const char *caller,
   }
 }
 
-const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
+const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state,
+                                      int flags)
 {
   switch (ifjoin_state) {
-  case PIM_IFJOIN_NOINFO:            return "NOINFO";
-  case PIM_IFJOIN_JOIN:              return "JOIN";
-  case PIM_IFJOIN_PRUNE:             return "PRUNE";
-  case PIM_IFJOIN_PRUNE_PENDING:     return "PRUNEP";
-  case PIM_IFJOIN_PRUNE_TMP:         return "PRUNET";
-  case PIM_IFJOIN_PRUNE_PENDING_TMP: return "PRUNEPT";
+  case PIM_IFJOIN_NOINFO:
+     if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+       return "SGRpt";
+     else
+       return "NOINFO";
+     break;
+  case PIM_IFJOIN_JOIN:
+     return "JOIN";
+     break;
+  case PIM_IFJOIN_PRUNE:
+     return "PRUNE";
+     break;
+  case PIM_IFJOIN_PRUNE_PENDING:
+     return "PRUNEP";
+     break;
+  case PIM_IFJOIN_PRUNE_TMP:
+     return "PRUNET";
+     break;
+  case PIM_IFJOIN_PRUNE_PENDING_TMP:
+     return "PRUNEPT";
+     break;
   }
 
   return "ifjoin_bad_state";
@@ -609,7 +626,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
     {
       zlog_warn("%s: IFCHANNEL%s Prune Pending Timer Popped while in %s state",
                __PRETTY_FUNCTION__, pim_str_sg_dump (&ch->sg),
-               pim_ifchannel_ifjoin_name (ch->ifjoin_state));
+               pim_ifchannel_ifjoin_name (ch->ifjoin_state, ch->flags));
     }
 
   return 0;
@@ -882,6 +899,7 @@ void pim_ifchannel_prune(struct interface *ifp,
        THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
                        on_ifjoin_expiry_timer,
                        ch, holdtime);
+        pim_upstream_update_join_desired(ch->upstream);
       }
     break;
   case PIM_IFJOIN_PRUNE_PENDING:
@@ -950,6 +968,18 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
   if (!PIM_IF_TEST_PIM(pim_ifp->options))
     return 0;
 
+  /* skip (*,G) ch creation if G is of type SSM */
+  if (sg->src.s_addr == INADDR_ANY)
+    {
+      if (pim_is_grp_ssm (sg->grp))
+        {
+          if (PIM_DEBUG_PIM_EVENTS)
+            zlog_debug("%s: local membership (S,G)=%s ignored as group is SSM",
+                __PRETTY_FUNCTION__, pim_str_sg_dump (sg));
+          return 1;
+        }
+    }
+
   ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
   if (!ch) {
     return 0;
@@ -1198,7 +1228,7 @@ pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom)
 
   if (PIM_DEBUG_PIM_TRACE)
     zlog_debug ("%s: %s %s eom: %d", __PRETTY_FUNCTION__,
-                pim_ifchannel_ifjoin_name(ch->ifjoin_state),
+                pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
                 ch->sg_str, eom);
   if (!ch->sources)
     return;
index c7084034a0a93c84e15ee8f5cd04c4dff5ebbd89..fe9fb9a7f10d6a086cb9544ccb6e475c9fafa862 100644 (file)
@@ -139,7 +139,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
 void pim_ifchannel_ifjoin_switch(const char *caller,
                                 struct pim_ifchannel *ch,
                                 enum pim_ifjoin_state new_state);
-const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state);
+const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state, int flags);
 const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state);
 
 int pim_ifchannel_isin_oiflist(struct pim_ifchannel *ch);
index e6582e2b175efdd9e6eb05602a5f34fb544ecbc3..ee88e7d8eada2ff6f60b92fb7b109220bdc83893 100644 (file)
@@ -876,10 +876,8 @@ pim_igmp_read (struct thread *t)
          if (errno == EINTR)
            continue;
          if (errno == EWOULDBLOCK || errno == EAGAIN)
-         {
-           cont = 0;
            break;
-         }
+
          goto done;
        }
     }
index ba80db0696c801d3ac137faa3071fe78b56217ad..228d30c5c415b2d763e7877d61b9c7369b1af32f 100644 (file)
@@ -45,6 +45,7 @@ static int pim_igmp_join_source(int fd, ifindex_t ifindex,
   struct sockaddr_in group;
   struct sockaddr_in source;
 
+  memset(&req, 0, sizeof(req));
   memset(&group, 0, sizeof(group));
   group.sin_family = AF_INET;
   group.sin_addr = group_addr;
index c19468da6fcb40143dc5e0c9fb0b01dd36896341..884aa35bc563d3d6b21e1154f71e81a38597dd3f 100644 (file)
@@ -493,8 +493,7 @@ int pim_joinprune_send(struct pim_rpf *rpf,
       curr_ptr += group_size;
       packet_left -= group_size;
       packet_size += group_size;
-      zlog_debug ("\tpl: %zd ps: %zd", packet_left, packet_size);
-      pim_msg_build_jp_groups (grp, group);
+      pim_msg_build_jp_groups (grp, group, group_size);
 
       grp = (struct pim_jp_groups *)curr_ptr;
       if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255)
index 8d4510324c32ac636fcee390dbb3c644a3f0cc6b..251e67a35195e3d33b6b9a1d2fc697c9d64b6d7a 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "linklist.h"
 #include "log.h"
+#include "vrf.h"
+#include "if.h"
 
 #include "pimd.h"
 #include "pim_msg.h"
@@ -40,6 +42,8 @@ pim_jp_agg_group_list_free (struct pim_jp_agg_group *jag)
 static void
 pim_jp_agg_src_free (struct pim_jp_sources *js)
 {
+  struct pim_upstream *up = js->up;
+
   /*
    * When we are being called here, we know
    * that the neighbor is going away start
@@ -47,7 +51,8 @@ pim_jp_agg_src_free (struct pim_jp_sources *js)
    * pick this shit back up when the
    * nbr comes back alive
    */
-  join_timer_start(js->up);
+  if (up)
+    join_timer_start(js->up);
   XFREE (MTYPE_PIM_JP_AGG_SOURCE, js);
 }
 
@@ -72,10 +77,16 @@ pim_jp_agg_src_cmp (void *arg1, void *arg2)
   const struct pim_jp_sources *js1 = (const struct pim_jp_sources *)arg1;
   const struct pim_jp_sources *js2 = (const struct pim_jp_sources *)arg2;
 
-  if (js1->up->sg.src.s_addr < js2->up->sg.src.s_addr)
+  if (js1->is_join && !js2->is_join)
     return -1;
 
-  if (js1->up->sg.src.s_addr > js2->up->sg.src.s_addr)
+  if (!js1->is_join && js2->is_join)
+    return 1;
+
+  if ((uint32_t)js1->up->sg.src.s_addr < (uint32_t)js2->up->sg.src.s_addr)
+    return -1;
+
+  if ((uint32_t)js1->up->sg.src.s_addr > (uint32_t)js2->up->sg.src.s_addr)
     return 1;
 
   return 0;
@@ -100,6 +111,7 @@ pim_jp_agg_clear_group (struct list *group)
       for (ALL_LIST_ELEMENTS(jag->sources, snode, snnode, js))
         {
           listnode_delete(jag->sources, js);
+          js->up = NULL;
           XFREE(MTYPE_PIM_JP_AGG_SOURCE, js);
         }
       jag->sources = NULL;
@@ -126,7 +138,7 @@ pim_jp_agg_get_interface_upstream_switch_list (struct pim_rpf *rpf)
       pius = XCALLOC(MTYPE_PIM_JP_AGG_GROUP, sizeof (struct pim_iface_upstream_switch));
       pius->address.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
       pius->us = list_new();
-      listnode_add (pim_ifp->upstream_switch_list, pius);
+      listnode_add_sort (pim_ifp->upstream_switch_list, pius);
     }
 
   return pius;
@@ -154,15 +166,88 @@ pim_jp_agg_remove_group (struct list *group, struct pim_upstream *up)
         break;
     }
 
-  listnode_delete(jag->sources, js);
-
-  XFREE(MTYPE_PIM_JP_AGG_SOURCE, js);
+  if (js)
+    {
+      js->up = NULL;
+      listnode_delete(jag->sources, js);
+      XFREE(MTYPE_PIM_JP_AGG_SOURCE, js);
+    }
 
   if (jag->sources->count == 0)
     {
       list_delete(jag->sources);
+      jag->sources = NULL;
       listnode_delete(group, jag);
+      XFREE(MTYPE_PIM_JP_AGG_GROUP, jag);
     }
+
+}
+
+int
+pim_jp_agg_is_in_list (struct list *group, struct pim_upstream *up)
+{
+  struct listnode *node, *nnode;
+  struct pim_jp_agg_group *jag = NULL;
+  struct pim_jp_sources *js = NULL;
+
+  for (ALL_LIST_ELEMENTS (group, node, nnode, jag))
+    {
+      if (jag->group.s_addr == up->sg.grp.s_addr)
+        break;
+    }
+
+  if (!jag)
+    return 0;
+
+  for (ALL_LIST_ELEMENTS(jag->sources, node, nnode, js))
+    {
+      if (js->up == up)
+        return 1;
+    }
+
+  return 0;
+ }
+
+//#define PIM_JP_AGG_DEBUG 1
+/*
+ * For the given upstream, check all the neighbor
+ * jp_agg lists and ensure that it is not
+ * in another list
+ *
+ * *IF* ignore is true we can skip
+ * up->rpf.source_nexthop.interface particular interface for checking
+ *
+ * This is a debugging function, Probably
+ * can be safely compiled out in real
+ * builds
+ */
+void
+pim_jp_agg_upstream_verification (struct pim_upstream *up, bool ignore)
+{
+#ifdef PIM_JP_AGG_DEBUG
+  struct listnode *node;
+  struct interface *ifp;
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+    {
+      struct pim_interface *pim_ifp = ifp->info;
+      struct listnode *nnode;
+
+      if (ignore && ifp == up->rpf.source_nexthop.interface)
+        continue;
+
+      if (pim_ifp)
+        {
+          struct pim_neighbor *neigh;
+          for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, nnode, neigh))
+            {
+              assert (!pim_jp_agg_is_in_list(neigh->upstream_jp_agg, up));
+            }
+        }
+    }
+#else
+  return;
+#endif
 }
 
 void
@@ -185,12 +270,12 @@ pim_jp_agg_add_group (struct list *group, struct pim_upstream *up, bool is_join)
       jag->sources = list_new();
       jag->sources->cmp = pim_jp_agg_src_cmp;
       jag->sources->del = (void (*)(void *))pim_jp_agg_src_free;
-      listnode_add (group, jag);
+      listnode_add_sort (group, jag);
     }
 
   for (ALL_LIST_ELEMENTS(jag->sources, node, nnode, js))
     {
-      if (js->up->sg.src.s_addr == up->sg.src.s_addr)
+      if (js->up == up)
         break;
     }
 
@@ -198,10 +283,18 @@ pim_jp_agg_add_group (struct list *group, struct pim_upstream *up, bool is_join)
     {
       js = XCALLOC(MTYPE_PIM_JP_AGG_SOURCE, sizeof (struct pim_jp_sources));
       js->up = up;
-      listnode_add (jag->sources, js);
+      js->is_join = is_join;
+      listnode_add_sort (jag->sources, js);
+    }
+  else
+    {
+      if (js->is_join != is_join)
+        {
+          listnode_delete(jag->sources, js);
+          js->is_join = is_join;
+          listnode_add_sort (jag->sources, js);
+        }
     }
-
-  js->is_join = is_join;
 }
 
 void
index 4c84c120eb0047130602ac732cf9d5a6f95ce4c4..ad014d95208cd8013d9b62fb14546b5a63a923c3 100644 (file)
@@ -30,10 +30,12 @@ struct pim_jp_sources
 struct pim_jp_agg_group
 {
   struct in_addr group;
-  //int onetime;
   struct list *sources;
 };
 
+void pim_jp_agg_upstream_verification (struct pim_upstream *up, bool ignore);
+int pim_jp_agg_is_in_list (struct list *group, struct pim_upstream *up);
+
 void pim_jp_agg_group_list_free (struct pim_jp_agg_group *jag);
 int pim_jp_agg_group_list_cmp (void *arg1, void *arg2);
 
index a0e42aab583c0e851f326deb27cd36ea254521dd..d814af6b2c1ba9b2750f5488f800a8790ad8b750 100644 (file)
@@ -46,7 +46,6 @@
 #include "pim_zebra.h"
 #include "pim_msdp.h"
 #include "pim_iface.h"
-#include "pim_rp.h"
 
 extern struct host host;
 
@@ -89,6 +88,7 @@ FRR_DAEMON_INFO(pimd, PIM,
        .privs = &pimd_privs,
 )
 
+
 int main(int argc, char** argv, char** envp) {
   frr_preinit(&pimd_di, argc, argv);
   frr_opt_add("", longopts, "");
@@ -116,11 +116,11 @@ int main(int argc, char** argv, char** envp) {
   /* 
    * Initializations
    */
-  vrf_init ();
+  pim_vrf_init ();
   access_list_init();
   prefix_list_init ();
-  prefix_list_add_hook (pim_rp_prefix_list_update);
-  prefix_list_delete_hook (pim_rp_prefix_list_update);
+  prefix_list_add_hook (pim_prefix_list_update);
+  prefix_list_delete_hook (pim_prefix_list_update);
 
   pim_route_map_init ();
   pim_init();
index 5af2a8203ff7a810decfc302a8b3455f38917db7..2acca6f49be879483ee3cdc56db6fa8c4eaac0d0 100644 (file)
@@ -49,3 +49,6 @@ DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR,       "PIM MSDP mesh group mbr")
 DEFINE_MTYPE(PIMD, PIM_SEC_ADDR,          "PIM secondary address")
 DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP,      "PIM JP AGG Group")
 DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE,     "PIM JP AGG Source")
+DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE,      "PIM global state")
+DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE,     "PIM nexthop cache state")
+DEFINE_MTYPE(PIMD, PIM_SSM_INFO,          "PIM SSM configuration")
index 0d5f131a4f00b0bd8fb362b075c199489d05852c..02446de46a65f93d48c725d129490a15ba10cb86 100644 (file)
@@ -48,4 +48,8 @@ DECLARE_MTYPE(PIM_MSDP_MG_MBR)
 DECLARE_MTYPE(PIM_SEC_ADDR)
 DECLARE_MTYPE(PIM_JP_AGG_GROUP)
 DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
+DECLARE_MTYPE(PIM_PIM_INSTANCE)
+DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
+DECLARE_MTYPE(PIM_SSM_INFO)
+
 #endif /* _QUAGGA_PIM_MEMORY_H */
index 94014758135dc587b4d18460c7a21e872fd3e3c8..2fb243b9bdbf91958f1a9f7c05d6d715c50ec0ac 100644 (file)
@@ -39,6 +39,7 @@
 #include "pim_register.h"
 #include "pim_ifchannel.h"
 #include "pim_zlookup.h"
+#include "pim_ssm.h"
 
 /* GLOBAL VARS */
 static struct thread *qpim_mroute_socket_reader = NULL;
@@ -118,7 +119,6 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
   struct pim_upstream *up;
   struct pim_rpf *rpg;
   struct prefix_sg sg;
-  struct channel_oil *oil;
 
   rpg = RP(msg->im_dst);
   /*
@@ -128,8 +128,7 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
    */
   if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
       (!pim_ifp) ||
-      (!(PIM_I_am_DR(pim_ifp))) ||
-      (pim_ifp->itype == PIM_INTERFACE_SSM))
+      (!(PIM_I_am_DR(pim_ifp))))
     {
       if (PIM_DEBUG_MROUTE_DETAIL)
        zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
@@ -153,25 +152,17 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
   sg.src = msg->im_src;
   sg.grp = msg->im_dst;
 
-  oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
-  if (!oil) {
-    if (PIM_DEBUG_MROUTE) {
-      zlog_debug("%s: Failure to add channel oil for %s",
-                __PRETTY_FUNCTION__,
-                pim_str_sg_dump (&sg));
-    }
-    return 0;
-  }
-
-  up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__);
-  if (!up) {
-    if (PIM_DEBUG_MROUTE) {
-      zlog_debug("%s: Failure to add upstream information for %s",
-                __PRETTY_FUNCTION__,
-                pim_str_sg_dump (&sg));
+  up = pim_upstream_find_or_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__);
+  if (!up)
+    {
+      if (PIM_DEBUG_MROUTE)
+        {
+          zlog_debug("%s: Failure to add upstream information for %s",
+                     __PRETTY_FUNCTION__,
+                     pim_str_sg_dump (&sg));
+        }
+      return 0;
     }
-    return 0;
-  }
 
   /*
    * I moved this debug till after the actual add because
@@ -185,11 +176,9 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
   PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
   pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
 
-  up->channel_oil = oil;
   up->channel_oil->cc.pktcnt++;
   PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
-  pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
-  up->reg_state = PIM_REG_JOIN;
+  pim_register_join (up);
 
   return 0;
 }
@@ -224,8 +213,7 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
 
   if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
       (!pim_ifp) ||
-      (!(PIM_I_am_DR(pim_ifp))) ||
-      (pim_ifp->itype == PIM_INTERFACE_SSM)) {
+      (!(PIM_I_am_DR(pim_ifp)))) {
     if (PIM_DEBUG_MROUTE) {
       zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
     }
@@ -236,9 +224,18 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
    * If we've received a register suppress
    */
   if (!up->t_rs_timer)
-    pim_register_send((uint8_t *)buf + sizeof(struct ip),
-                      ntohs (ip_hdr->ip_len) - sizeof (struct ip),
-                      pim_ifp->primary_address, rpg, 0, up);
+    {
+      if (pim_is_grp_ssm (sg.grp))
+        {
+          if (PIM_DEBUG_PIM_REG)
+            zlog_debug ("%s register forward skipped as group is SSM",
+                        pim_str_sg_dump (&sg));
+          return 0;
+        }
+      pim_register_send((uint8_t *)buf + sizeof(struct ip),
+                        ntohs (ip_hdr->ip_len) - sizeof (struct ip),
+                        pim_ifp->primary_address, rpg, 0, up);
+    }
   return 0;
 }
 
@@ -452,8 +449,7 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
       pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
       up->channel_oil = oil;
       up->channel_oil->cc.pktcnt++;
-      pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
-      up->reg_state = PIM_REG_JOIN;
+      pim_register_join (up);
       pim_upstream_inherited_olist (up);
 
       // Send the packet to the RP
@@ -581,10 +577,8 @@ static int mroute_read(struct thread *t)
        if (errno == EINTR)
          continue;
        if (errno == EWOULDBLOCK || errno == EAGAIN)
-         {
-           cont = 0;
-           break;
-         }
+          break;
+
        if (PIM_DEBUG_MROUTE)
          zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
                    __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
@@ -759,7 +753,7 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
   ++qpim_mroute_add_events;
 
   /* Do not install route if incoming interface is undefined. */
-  if (c_oil->oil.mfcc_parent == MAXVIFS)
+  if (c_oil->oil.mfcc_parent >= MAXVIFS)
     {
       if (PIM_DEBUG_MROUTE)
         {
index 4018fd639e0c2ecd9bb5ac48dd1be6cac0470a01..e19893f5dab4253f7de1970b64b4b77bbb270b98 100644 (file)
@@ -101,6 +101,7 @@ pim_msg_addr_encode_ipv4_source(uint8_t *buf,
 size_t
 pim_msg_get_jp_group_size (struct list *sources)
 {
+  struct pim_jp_sources *js;
   size_t size = 0;
 
   size += sizeof (struct pim_encoded_group_ipv4);
@@ -108,17 +109,74 @@ pim_msg_get_jp_group_size (struct list *sources)
 
   size += sizeof (struct pim_encoded_source_ipv4) * sources->count;
 
+  js = listgetdata(listhead(sources));
+  if (js && js->up->sg.src.s_addr == INADDR_ANY)
+    {
+      struct pim_upstream *child, *up;
+      struct listnode *up_node;
+
+      up = js->up;
+      if (PIM_DEBUG_PIM_PACKETS)
+        zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
+                    __PRETTY_FUNCTION__, up->sg_str);
+
+      for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+        {
+          if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+            {
+              if (!pim_rpf_is_same(&up->rpf, &child->rpf))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else if (pim_upstream_is_sg_rpt (child))
+            {
+              if (pim_upstream_empty_inherited_olist (child))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
+                                __PRETTY_FUNCTION__, child->sg_str);
+                }
+              else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
+                {
+                  size += sizeof (struct pim_encoded_source_ipv4);
+                  PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags);
+                  if (PIM_DEBUG_PIM_PACKETS)
+                    zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
+                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+                }
+              else
+                if (PIM_DEBUG_PIM_PACKETS)
+                  zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
+                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+            }
+          else
+            if (PIM_DEBUG_PIM_PACKETS)
+              zlog_debug ("%s: SPT bit is not set for (%s)",
+                          __PRETTY_FUNCTION__, child->sg_str);
+        }
+    }
   return size;
 }
 
 size_t
-pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs)
+pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs, size_t size)
 {
   struct listnode *node, *nnode;
   struct pim_jp_sources *source;
+  struct pim_upstream *up = NULL;
   struct in_addr stosend;
   uint8_t bits;
-  size_t size = pim_msg_get_jp_group_size (sgs->sources);
   uint8_t tgroups = 0;
 
   memset (grp, 0, size);
@@ -137,6 +195,7 @@ pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs
           struct pim_rpf *rpf = pim_rp_g (source->up->sg.grp);
           bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
           stosend = rpf->rpf_addr.u.prefix4;
+          up = source->up;
         }
       else
         {
@@ -148,74 +207,26 @@ pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs
       tgroups++;
     }
 
-  grp->joins = htons(grp->joins);
-  grp->prunes = htons(grp->prunes);
-  /*
-   * This is not implemented correctly at this point in time
-   * Make it stop.
-   */
-#if 0
-  if (up->sg.src.s_addr == INADDR_ANY)
+  if (up)
     {
       struct pim_upstream *child;
-      struct listnode *up_node;
-      int send_prune = 0;
 
-      zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
-                  __PRETTY_FUNCTION__, up->sg_str);
-      for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+      for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child))
         {
-          if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
-            {
-              if (!pim_rpf_is_same(&up->rpf, &child->rpf))
-                {
-                  send_prune = 1;
-                  if (PIM_DEBUG_PIM_PACKETS)
-                    zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
-                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-                }
-              else
-                if (PIM_DEBUG_PIM_PACKETS)
-                  zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
-                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-            }
-          else if (pim_upstream_is_sg_rpt (child))
-            {
-              if (pim_upstream_empty_inherited_olist (child))
-                {
-                  send_prune = 1;
-                  if (PIM_DEBUG_PIM_PACKETS)
-                    zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
-                                __PRETTY_FUNCTION__, child->sg_str);
-                }
-              else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
-                {
-                  send_prune = 1;
-                  if (PIM_DEBUG_PIM_PACKETS)
-                    zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
-                                __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-                }
-              else
-                if (PIM_DEBUG_PIM_PACKETS)
-                  zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
-                              __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
-            }
-          else
-            if (PIM_DEBUG_PIM_PACKETS)
-              zlog_debug ("%s: SPT bit is not set for (%s)",
-                          __PRETTY_FUNCTION__, child->sg_str);
-          if (send_prune)
+          if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(child->flags))
             {
-              pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
-                                                              child->sg.src,
-                                                              PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
-              remain = pim_msg_curr - pim_msg;
-              *prunes = htons(ntohs(*prunes) + 1);
-              send_prune = 0;
+              pim_msg_addr_encode_ipv4_source ((uint8_t *)&grp->s[tgroups],
+                                               child->sg.src,
+                                               PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
+              tgroups++;
+              PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(child->flags);
+              grp->prunes++;
             }
         }
     }
-#endif
+
+  grp->joins = htons(grp->joins);
+  grp->prunes = htons(grp->prunes);
 
   return size;
 }
index 9774ef3ed025d4ea68d67bf1ce2bcc15a30b1f00..de663aa3b52007d2e0c7823bda21e3a5ce908a6c 100644 (file)
@@ -96,5 +96,5 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
 
 
 size_t pim_msg_get_jp_group_size (struct list *sources);
-size_t pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs);
+size_t pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_jp_agg_group *sgs, size_t size);
 #endif /* PIM_MSG_H */
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
new file mode 100644 (file)
index 0000000..fe96d01
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include "network.h"
+#include "zclient.h"
+#include "stream.h"
+#include "nexthop.h"
+#include "if.h"
+#include "hash.h"
+#include "jhash.h"
+
+#include "pimd.h"
+#include "pimd/pim_nht.h"
+#include "log.h"
+#include "pim_time.h"
+#include "pim_oil.h"
+#include "pim_ifchannel.h"
+#include "pim_mroute.h"
+#include "pim_zebra.h"
+#include "pim_upstream.h"
+#include "pim_join.h"
+#include "pim_jp_agg.h"
+#include "pim_zebra.h"
+
+/**
+ * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
+ *   command to Zebra.
+ */
+static void
+pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
+                       int command)
+{
+  struct stream *s;
+  struct prefix *p;
+  int ret;
+
+  /* Check socket. */
+  if (!zclient || zclient->sock < 0)
+    return;
+
+  p = &(pnc->rpf.rpf_addr);
+  s = zclient->obuf;
+  stream_reset (s);
+  zclient_create_header (s, command, VRF_DEFAULT);
+  /* get update for all routes for a prefix */
+  stream_putc (s, 0);
+
+  stream_putw (s, PREFIX_FAMILY (p));
+  stream_putc (s, p->prefixlen);
+  switch (PREFIX_FAMILY (p))
+    {
+    case AF_INET:
+      stream_put_in_addr (s, &p->u.prefix4);
+      break;
+    case AF_INET6:
+      stream_put (s, &(p->u.prefix6), 16);
+      break;
+    default:
+      break;
+    }
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  ret = zclient_send_message (zclient);
+  if (ret < 0)
+    zlog_warn ("sendmsg_nexthop: zclient_send_message() failed");
+
+
+  if (PIM_DEBUG_TRACE)
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str (p, buf, sizeof (buf));
+      zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ",
+                  __PRETTY_FUNCTION__, buf,
+                  (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret);
+    }
+
+  return;
+}
+
+struct pim_nexthop_cache *
+pim_nexthop_cache_find (struct pim_rpf *rpf)
+{
+  struct pim_nexthop_cache *pnc = NULL;
+  struct pim_nexthop_cache lookup;
+
+  lookup.rpf.rpf_addr.family = rpf->rpf_addr.family;
+  lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen;
+  lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
+
+  pnc = hash_lookup (pimg->rpf_hash, &lookup);
+
+  return pnc;
+
+}
+
+struct pim_nexthop_cache *
+pim_nexthop_cache_add (struct pim_rpf *rpf_addr)
+{
+  struct pim_nexthop_cache *pnc;
+
+  pnc = XCALLOC (MTYPE_PIM_NEXTHOP_CACHE, sizeof (struct pim_nexthop_cache));
+  if (!pnc)
+    {
+      zlog_err ("%s: NHT PIM XCALLOC failure ", __PRETTY_FUNCTION__);
+      return NULL;
+    }
+  pnc->rpf.rpf_addr.family = rpf_addr->rpf_addr.family;
+  pnc->rpf.rpf_addr.prefixlen = rpf_addr->rpf_addr.prefixlen;
+  pnc->rpf.rpf_addr.u.prefix4.s_addr = rpf_addr->rpf_addr.u.prefix4.s_addr;
+
+  pnc = hash_get (pimg->rpf_hash, pnc, hash_alloc_intern);
+
+  pnc->rp_list = list_new ();
+  pnc->rp_list->cmp = pim_rp_list_cmp;
+
+  pnc->upstream_list = list_new ();
+  pnc->upstream_list->cmp = pim_upstream_compare;
+
+  if (PIM_DEBUG_ZEBRA)
+    {
+      char rpf_str[PREFIX_STRLEN];
+      pim_addr_dump ("<nht?>", &rpf_addr->rpf_addr, rpf_str,
+                     sizeof (rpf_str));
+      zlog_debug ("%s: NHT hash node, RP and UP lists allocated for %s ",
+                  __PRETTY_FUNCTION__, rpf_str);
+    }
+
+  return pnc;
+}
+
+/* This API is used to Register an address with Zebra */
+int
+pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
+                           struct rp_info *rp)
+{
+  struct pim_nexthop_cache *pnc = NULL;
+  struct pim_rpf rpf;
+  struct listnode *ch_node = NULL;
+  struct zclient *zclient = NULL;
+
+  zclient = pim_zebra_zclient_get ();
+  memset (&rpf, 0, sizeof (struct pim_rpf));
+  rpf.rpf_addr.family = addr->family;
+  rpf.rpf_addr.prefixlen = addr->prefixlen;
+  rpf.rpf_addr.u.prefix4 = addr->u.prefix4;
+
+  pnc = pim_nexthop_cache_find (&rpf);
+  if (!pnc)
+    {
+      if (PIM_DEBUG_ZEBRA)
+        {
+          char buf[PREFIX2STR_BUFFER];
+          prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
+          zlog_debug ("%s: NHT New PNC allocated for addr %s ",
+                      __PRETTY_FUNCTION__, buf);
+        }
+      pnc = pim_nexthop_cache_add (&rpf);
+      if (pnc)
+        pim_sendmsg_zebra_rnh (zclient, pnc,
+                               ZEBRA_NEXTHOP_REGISTER);
+      else
+        {
+          zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__);
+        }
+    }
+
+  if (rp != NULL)
+    {
+      ch_node = listnode_lookup (pnc->rp_list, rp);
+      if (ch_node == NULL)
+        {
+          if (PIM_DEBUG_ZEBRA)
+            {
+              char rp_str[PREFIX_STRLEN];
+              pim_addr_dump ("<rp?>", &rp->rp.rpf_addr, rp_str,
+                             sizeof (rp_str));
+              zlog_debug ("%s: NHT add RP %s node to cached list",
+                          __PRETTY_FUNCTION__, rp_str);
+            }
+          listnode_add_sort (pnc->rp_list, rp);
+        }
+    }
+
+  if (up != NULL)
+    {
+      ch_node = listnode_lookup (pnc->upstream_list, up);
+      if (ch_node == NULL)
+        {
+          if (PIM_DEBUG_ZEBRA)
+            {
+              char buf[PREFIX2STR_BUFFER];
+              prefix2str (addr, buf, sizeof (buf));
+              zlog_debug
+                ("%s: NHT add upstream %s node to cached list, rpf %s",
+                 __PRETTY_FUNCTION__, up->sg_str, buf);
+            }
+          listnode_add_sort (pnc->upstream_list, up);
+        }
+    }
+
+  if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
+    return 1;
+
+  return 0;
+}
+
+void
+pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
+                            struct rp_info *rp)
+{
+  struct pim_nexthop_cache *pnc = NULL;
+  struct pim_nexthop_cache lookup;
+  struct zclient *zclient = NULL;
+
+  zclient = pim_zebra_zclient_get ();
+
+  /* Remove from RPF hash if it is the last entry */
+  lookup.rpf.rpf_addr = *addr;
+  pnc = hash_lookup (pimg->rpf_hash, &lookup);
+  if (pnc)
+    {
+      if (rp)
+        listnode_delete (pnc->rp_list, rp);
+      if (up)
+        listnode_delete (pnc->upstream_list, up);
+
+      if (PIM_DEBUG_ZEBRA)
+        zlog_debug ("%s: NHT rp_list count:%d upstream_list count:%d ",
+                    __PRETTY_FUNCTION__, pnc->rp_list->count,
+                    pnc->upstream_list->count);
+
+      if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
+        {
+          pim_sendmsg_zebra_rnh (zclient, pnc,
+                                 ZEBRA_NEXTHOP_UNREGISTER);
+
+          list_delete (pnc->rp_list);
+          list_delete (pnc->upstream_list);
+
+          hash_release (pimg->rpf_hash, pnc);
+          if (pnc->nexthop)
+            nexthops_free (pnc->nexthop);
+          XFREE (MTYPE_PIM_NEXTHOP_CACHE, pnc);
+        }
+    }
+}
+
+/* Update RP nexthop info based on Nexthop update received from Zebra.*/
+static int
+pim_update_rp_nh (struct pim_nexthop_cache *pnc)
+{
+  struct listnode *node = NULL;
+  struct rp_info *rp_info = NULL;
+  int ret = 0;
+
+  /*Traverse RP list and update each RP Nexthop info */
+  for (ALL_LIST_ELEMENTS_RO (pnc->rp_list, node, rp_info))
+    {
+      if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
+        continue;
+
+      if (pim_nexthop_lookup (&rp_info->rp.source_nexthop,
+                              rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
+        {
+          if (PIM_DEBUG_PIM_TRACE)
+            zlog_debug ("Unable to lookup nexthop for rp specified");
+          ret++;
+          continue;
+        }
+
+      if (PIM_DEBUG_TRACE)
+        {
+          char rp_str[PREFIX_STRLEN];
+          pim_addr_dump ("<rp?>", &rp_info->rp.rpf_addr, rp_str,
+                         sizeof (rp_str));
+          zlog_debug ("%s: NHT update nexthop for RP %s to interface %s ",
+                      __PRETTY_FUNCTION__, rp_str,
+                      rp_info->rp.source_nexthop.interface->name);
+        }
+    }
+
+  if (ret)
+    return 0;
+
+  return 1;
+
+}
+
+/* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
+static int
+pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
+{
+  struct listnode     *up_node;
+  struct listnode     *ifnode;
+  struct listnode     *up_nextnode;
+  struct listnode     *node;
+  struct pim_upstream *up;
+  struct interface    *ifp;
+  int                 vif_index = 0;
+
+  for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
+    {
+      enum pim_rpf_result rpf_result;
+      struct pim_rpf old;
+
+      old.source_nexthop.interface = up->rpf.source_nexthop.interface;
+      rpf_result = pim_rpf_update (up, &old, 0);
+      if (rpf_result == PIM_RPF_FAILURE)
+        continue;
+
+      if (rpf_result == PIM_RPF_CHANGED)
+        {
+          struct pim_neighbor *nbr;
+
+          nbr = pim_neighbor_find (old.source_nexthop.interface,
+                                   old.rpf_addr.u.prefix4);
+          if (nbr)
+            pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
+
+          /*
+           * We have detected a case where we might need to rescan
+           * the inherited o_list so do it.
+           */
+          if (up->channel_oil && up->channel_oil->oil_inherited_rescan)
+            {
+              pim_upstream_inherited_olist_decide (up);
+              up->channel_oil->oil_inherited_rescan = 0;
+            }
+
+          if (up->join_state == PIM_UPSTREAM_JOINED)
+            {
+              /*
+               * If we come up real fast we can be here
+               * where the mroute has not been installed
+               * so install it.
+               */
+              if (up->channel_oil && !up->channel_oil->installed)
+                pim_mroute_add (up->channel_oil, __PRETTY_FUNCTION__);
+
+              /*
+                 RFC 4601: 4.5.7.  Sending (S,G) Join/Prune Messages
+
+                 Transitions from Joined State
+
+                 RPF'(S,G) changes not due to an Assert
+
+                 The upstream (S,G) state machine remains in Joined
+                 state. Send Join(S,G) to the new upstream neighbor, which is
+                 the new value of RPF'(S,G).  Send Prune(S,G) to the old
+                 upstream neighbor, which is the old value of RPF'(S,G).  Set
+                 the Join Timer (JT) to expire after t_periodic seconds.
+               */
+              pim_jp_agg_switch_interface (&old, &up->rpf, up);
+
+              pim_upstream_join_timer_restart (up, &old);
+            }                   /* up->join_state == PIM_UPSTREAM_JOINED */
+
+          /* FIXME can join_desired actually be changed by pim_rpf_update()
+             returning PIM_RPF_CHANGED ? */
+          pim_upstream_update_join_desired (up);
+
+        } /* PIM_RPF_CHANGED */
+
+      if (PIM_DEBUG_TRACE)
+        {
+          zlog_debug ("%s: NHT upstream %s old ifp %s new ifp %s",
+                      __PRETTY_FUNCTION__, up->sg_str,
+                      old.source_nexthop.interface->name,
+                      up->rpf.source_nexthop.interface->name);
+        }
+      /* update kernel multicast forwarding cache (MFC) */
+      if (up->channel_oil)
+        {
+          vif_index =
+            pim_if_find_vifindex_by_ifindex (up->rpf.
+                                             source_nexthop.interface->
+                                             ifindex);
+          /* Pass Current selected NH vif index to mroute download */
+          if (vif_index)
+            pim_scan_individual_oil (up->channel_oil, vif_index);
+          else
+            {
+              if (PIM_DEBUG_ZEBRA)
+                zlog_debug ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+                      __PRETTY_FUNCTION__, up->sg_str,
+                      up->rpf.source_nexthop.interface->name);
+            }
+        }
+
+    } /* for (pnc->upstream_list) */
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
+    if (ifp->info)
+      {
+        struct pim_interface *pim_ifp = ifp->info;
+        struct pim_iface_upstream_switch *us;
+
+        for (ALL_LIST_ELEMENTS_RO (pim_ifp->upstream_switch_list, node, us))
+          {
+            struct pim_rpf rpf;
+            rpf.source_nexthop.interface = ifp;
+            rpf.rpf_addr.u.prefix4 = us->address;
+            pim_joinprune_send (&rpf, us->us);
+            pim_jp_agg_clear_group (us->us);
+          }
+      }
+
+  return 0;
+}
+
+/*
+ * This API is used to parse Registered address nexthop update
+ * coming from Zebra
+ */
+int
+pim_parse_nexthop_update (int command, struct zclient *zclient,
+                          zebra_size_t length, vrf_id_t vrf_id)
+{
+  struct stream *s;
+  struct prefix p;
+  struct nexthop *nexthop;
+  struct nexthop *oldnh;
+  struct nexthop *nhlist_head = NULL;
+  struct nexthop *nhlist_tail = NULL;
+  uint32_t metric, distance;
+  u_char nexthop_num = 0;
+  int i;
+  struct pim_rpf rpf;
+  struct pim_nexthop_cache *pnc = NULL;
+  struct pim_neighbor *nbr = NULL;
+  struct interface *ifp = NULL;
+
+  s = zclient->ibuf;
+  memset (&p, 0, sizeof (struct prefix));
+  p.family = stream_getw (s);
+  p.prefixlen = stream_getc (s);
+  switch (p.family)
+    {
+    case AF_INET:
+      p.u.prefix4.s_addr = stream_get_ipv4 (s);
+      break;
+    case AF_INET6:
+      stream_get (&p.u.prefix6, s, 16);
+      break;
+    default:
+      break;
+    }
+
+  if (command == ZEBRA_NEXTHOP_UPDATE)
+    {
+      rpf.rpf_addr.family = p.family;
+      rpf.rpf_addr.prefixlen = p.prefixlen;
+      rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr;
+      pnc = pim_nexthop_cache_find (&rpf);
+      if (!pnc)
+        {
+          if (PIM_DEBUG_TRACE)
+            {
+              char buf[PREFIX2STR_BUFFER];
+              prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
+              zlog_debug ("%s: NHT addr %s is not in local cached DB.",
+                          __PRETTY_FUNCTION__, buf);
+            }
+          return 0;
+        }
+    }
+  else
+    {
+      /*
+       * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
+       */
+      return 0;
+    }
+
+  pnc->last_update = pim_time_monotonic_sec ();
+  distance = stream_getc (s);
+  metric = stream_getl (s);
+  nexthop_num = stream_getc (s);
+
+  if (PIM_DEBUG_TRACE)
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str (&p, buf, sizeof (buf));
+      zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
+                  __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
+                  listcount (pnc->upstream_list), listcount (pnc->rp_list));
+    }
+
+  if (nexthop_num)
+    {
+      pnc->flags |= PIM_NEXTHOP_VALID;
+      pnc->distance = distance;
+      pnc->metric = metric;
+      pnc->nexthop_num = nexthop_num;
+
+      for (i = 0; i < nexthop_num; i++)
+        {
+          nexthop = nexthop_new ();
+          nexthop->type = stream_getc (s);
+          switch (nexthop->type)
+            {
+            case NEXTHOP_TYPE_IPV4:
+              nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+              nexthop->ifindex = stream_getl (s);
+              break;
+            case NEXTHOP_TYPE_IFINDEX:
+              nexthop->ifindex = stream_getl (s);
+              break;
+            case NEXTHOP_TYPE_IPV4_IFINDEX:
+              nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+              nexthop->ifindex = stream_getl (s);
+              break;
+            case NEXTHOP_TYPE_IPV6:
+              stream_get (&nexthop->gate.ipv6, s, 16);
+              break;
+            case NEXTHOP_TYPE_IPV6_IFINDEX:
+              stream_get (&nexthop->gate.ipv6, s, 16);
+              nexthop->ifindex = stream_getl (s);
+              nbr =
+                pim_neighbor_find_if (if_lookup_by_index
+                                      (nexthop->ifindex, VRF_DEFAULT));
+              /* Overwrite with Nbr address as NH addr */
+              if (nbr)
+                nexthop->gate.ipv4 = nbr->source_addr;
+
+              break;
+            default:
+              /* do nothing */
+              break;
+            }
+
+          if (PIM_DEBUG_TRACE)
+            {
+              char p_str[PREFIX2STR_BUFFER];
+              prefix2str (&p, p_str, sizeof (p_str));
+              zlog_debug ("%s: NHT addr %s %d-nhop via %s type %d",
+                          __PRETTY_FUNCTION__, p_str, i + 1,
+                          inet_ntoa (nexthop->gate.ipv4), nexthop->type);
+            }
+
+          ifp = if_lookup_by_index (nexthop->ifindex, VRF_DEFAULT);
+          if (!ifp)
+            {
+              if (PIM_DEBUG_ZEBRA)
+                {
+                  char buf[NEXTHOP_STRLEN];
+                  zlog_debug("%s: could not find interface for ifindex %d (addr %s)",
+                         __PRETTY_FUNCTION__,
+                         nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf)));
+                }
+              nexthop_free (nexthop);
+              continue;
+            }
+
+          if (!ifp->info)
+            {
+              if (PIM_DEBUG_ZEBRA)
+                {
+                  char buf[NEXTHOP_STRLEN];
+                  zlog_debug
+                    ("%s: multicast not enabled on input interface %s (ifindex=%d, addr %s)",
+                     __PRETTY_FUNCTION__, ifp->name, nexthop->ifindex,
+                     nexthop2str (nexthop, buf, sizeof (buf)));
+                }
+              nexthop_free (nexthop);
+              continue;
+            }
+
+          if (nhlist_tail)
+            {
+              nhlist_tail->next = nexthop;
+              nhlist_tail = nexthop;
+            }
+          else
+            {
+              nhlist_tail = nexthop;
+              nhlist_head = nexthop;
+            }
+
+          for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next)
+            if (nexthop_same_no_recurse (oldnh, nexthop))
+              break;
+        }
+      /* Reset existing pnc->nexthop before assigning new list */
+      nexthops_free (pnc->nexthop);
+      pnc->nexthop = nhlist_head;
+    }
+  else
+    {
+      pnc->flags &= ~PIM_NEXTHOP_VALID;
+      pnc->nexthop_num = nexthop_num;
+      nexthops_free (pnc->nexthop);
+      pnc->nexthop = NULL;
+    }
+
+  pim_rpf_set_refresh_time ();
+
+  if (listcount (pnc->rp_list))
+    pim_update_rp_nh (pnc);
+  if (listcount (pnc->upstream_list))
+    pim_update_upstream_nh (pnc);
+
+  return 0;
+}
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
new file mode 100644 (file)
index 0000000..5348ec3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef PIM_NHT_H
+#define PIM_NHT_H
+
+#include "prefix.h"
+#include <zebra.h>
+#include "zclient.h"
+#include "vrf.h"
+
+#include "pimd.h"
+#include "pim_rp.h"
+#include "pim_rpf.h"
+
+/* PIM nexthop cache value structure. */
+struct pim_nexthop_cache
+{
+  struct pim_rpf rpf;
+  /* IGP route's metric. */
+  u_int32_t metric;
+  uint32_t  distance;
+  /* Nexthop number and nexthop linked list. */
+  u_char nexthop_num;
+  struct nexthop *nexthop;
+  int64_t last_update;
+  u_int16_t flags;
+#define PIM_NEXTHOP_VALID             (1 << 0)
+
+  struct list *rp_list;
+  struct list *upstream_list;
+};
+
+int pim_parse_nexthop_update (int command, struct zclient *zclient,
+                              zebra_size_t length, vrf_id_t vrf_id);
+int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
+                               struct rp_info *rp);
+void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
+                                 struct rp_info *rp);
+struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr);
+struct pim_nexthop_cache *pim_nexthop_cache_find (struct pim_rpf *rpf);
+
+#endif
index 471d8aa39e232fda505f993dbaf098448b8a40fe..b2f858b7d96c87c758cfcf567d4c68e2623021ea 100644 (file)
@@ -310,10 +310,8 @@ static int pim_sock_read(struct thread *t)
          if (errno == EINTR)
            continue;
          if (errno == EWOULDBLOCK || errno == EAGAIN)
-           {
-             cont = 0;
-             break;
-           }
+            break;
+
          if (PIM_DEBUG_PIM_PACKETS)
            zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
          goto done;
@@ -331,7 +329,7 @@ static int pim_sock_read(struct thread *t)
        if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
          sprintf(to_str, "<to?>");
 
-       recv_ifp = if_lookup_by_index(ifindex);
+       recv_ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
        if (recv_ifp) {
          zassert(ifindex == (int) recv_ifp->ifindex);
        }
index 46d8e3ec2e7ca55e1de8c5ecb8be9f86a6efdd11..65a3e8714f87481060e7636e6dc5c1f0e380f705 100644 (file)
 #include "pim_zebra.h"
 #include "pim_join.h"
 #include "pim_util.h"
+#include "pim_ssm.h"
 
 struct thread *send_test_packet_timer = NULL;
 
+void
+pim_register_join (struct pim_upstream *up)
+{
+  if (pim_is_grp_ssm (up->sg.grp))
+    {
+      if (PIM_DEBUG_PIM_EVENTS)
+       zlog_debug ("%s register setup skipped as group is SSM", up->sg_str);
+      return;
+    }
+
+  pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+  up->reg_state = PIM_REG_JOIN;
+}
+
 void
 pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
                        struct in_addr src, struct in_addr originator)
@@ -332,34 +347,16 @@ pim_register_recv (struct interface *ifp,
      */
     if (!upstream)
       {
-       upstream = pim_upstream_add (&sg, ifp,
-                                    PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
-                                    __PRETTY_FUNCTION__);
+        upstream = pim_upstream_add (&sg, ifp,
+                                     PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
+                                     __PRETTY_FUNCTION__);
         if (!upstream)
           {
             zlog_warn ("Failure to create upstream state");
             return 1;
           }
-        PIM_UPSTREAM_FLAG_SET_SRC_STREAM(upstream->flags);
 
         upstream->upstream_register = src_addr;
-       pim_rp_set_upstream_addr (&upstream->upstream_addr, sg.src, sg.grp);
-       if (pim_nexthop_lookup (&upstream->rpf.source_nexthop,
-                               upstream->upstream_addr, 1) != 0)
-          {
-            if (PIM_DEBUG_PIM_REG)
-              {
-                zlog_debug ("Received Register(%s), for which I have no path back", upstream->sg_str);
-              }
-            PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(upstream->flags);
-            pim_upstream_del (upstream, __PRETTY_FUNCTION__);
-            return 1;
-          }
-       upstream->sg.src = sg.src;
-       upstream->rpf.rpf_addr = upstream->rpf.source_nexthop.mrib_nexthop_addr;
-
-       upstream->join_state = PIM_UPSTREAM_NOTJOINED;
-
       }
 
     if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
index 42a908b225af702efff0b0afdbbfb3f31098b691..210a904ae9488af0133458b5de04076b90efb229 100644 (file)
@@ -40,5 +40,6 @@ int pim_register_recv (struct interface *ifp,
 
 void pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up);
 void pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, struct in_addr src, struct in_addr originator);
+void pim_register_join (struct pim_upstream *up);
 
 #endif
index dc19002a4285cae0f8abef3b914a2604969b4a0c..78bbd14405566540d67434e2c9e7aa33fef64711 100644 (file)
 #include "pim_memory.h"
 #include "pim_iface.h"
 #include "pim_msdp.h"
+#include "pim_nht.h"
 
-struct rp_info
-{
-  struct prefix group;
-  struct pim_rpf rp;
-  int i_am_rp;
-  char *plist;
-};
 
 static struct list *qpim_rp_list = NULL;
 static struct rp_info *tail = NULL;
@@ -60,21 +54,12 @@ pim_rp_info_free (struct rp_info *rp_info)
   XFREE (MTYPE_PIM_RP, rp_info);
 }
 
-static int
+int
 pim_rp_list_cmp (void *v1, void *v2)
 {
   struct rp_info *rp1 = (struct rp_info *)v1;
   struct rp_info *rp2 = (struct rp_info *)v2;
 
-  if (rp1 == rp2)
-    return 0;
-
-  if (!rp1 && rp2)
-    return -1;
-
-  if (rp1 && !rp2)
-    return 1;
-
   /*
    * Sort by RP IP address
    */
@@ -93,10 +78,7 @@ pim_rp_list_cmp (void *v1, void *v2)
   if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
     return 1;
 
-  if (rp1 == tail)
-    return 1;
-
-  return -1;
+  return 0;
 }
 
 void
@@ -305,6 +287,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
   struct listnode *node, *nnode;
   struct rp_info *tmp_rp_info;
   char buffer[BUFSIZ];
+  struct prefix nht_p;
 
   rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
   if (!rp_info)
@@ -401,6 +384,19 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
           rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
           XFREE (MTYPE_PIM_RP, rp_info);
 
+          /* Register addr with Zebra NHT */
+          nht_p.family = AF_INET;
+          nht_p.prefixlen = IPV4_MAX_BITLEN;
+          nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4;
+          if (PIM_DEBUG_PIM_TRACE)
+            {
+              char buf[PREFIX2STR_BUFFER];
+              prefix2str (&nht_p, buf, sizeof (buf));
+              zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
+                        __PRETTY_FUNCTION__, buf);
+            }
+          pim_find_or_track_nexthop (&nht_p, NULL, rp_all);
+
           if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
             return PIM_RP_NO_PATH;
 
@@ -448,11 +444,23 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
 
   listnode_add_sort (qpim_rp_list, rp_info);
 
+  /* Register addr with Zebra NHT */
+  nht_p.family = AF_INET;
+  nht_p.prefixlen = IPV4_MAX_BITLEN;
+  nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+  if (PIM_DEBUG_PIM_TRACE)
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str (&nht_p, buf, sizeof (buf));
+      zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf);
+    }
+  pim_find_or_track_nexthop (&nht_p, NULL, rp_info);
+
   if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
     return PIM_RP_NO_PATH;
 
   pim_rp_check_interfaces (rp_info);
-  pim_rp_refresh_group_to_rp_mapping();
+  pim_rp_refresh_group_to_rp_mapping ();
   return PIM_SUCCESS;
 }
 
@@ -465,6 +473,7 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
   struct rp_info *rp_info;
   struct rp_info *rp_all;
   int result;
+  struct prefix nht_p;
 
   if (group_range == NULL)
     result = str2prefix ("224.0.0.0/4", &group);
@@ -492,6 +501,18 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
       rp_info->plist = NULL;
     }
 
+  /* Deregister addr with Zebra NHT */
+  nht_p.family = AF_INET;
+  nht_p.prefixlen = IPV4_MAX_BITLEN;
+  nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+  if (PIM_DEBUG_PIM_TRACE)
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str (&nht_p, buf, sizeof (buf));
+      zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf);
+    }
+  pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
+
   str2prefix ("224.0.0.0/4", &g_all);
   rp_all = pim_rp_find_match_group (&g_all);
 
@@ -504,7 +525,7 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
     }
 
   listnode_delete (qpim_rp_list, rp_info);
-  pim_rp_refresh_group_to_rp_mapping();
+  pim_rp_refresh_group_to_rp_mapping ();
   return PIM_SUCCESS;
 }
 
@@ -752,9 +773,9 @@ pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr)
        return 1;
     }
 
-  if (if_lookup_exact_address (&dest_addr, AF_INET))
+  if (if_lookup_exact_address (&dest_addr, AF_INET, VRF_DEFAULT))
     return 1;
-    
+
   return 0;
 }
 
index b32228ed49daa5e7df48b408c100089eacc67881..84ab9be4824978b09a9687d0a539c20d961813c1 100644 (file)
 #ifndef PIM_RP_H
 #define PIM_RP_H
 
+#include <zebra.h>
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
+#include "pim_iface.h"
+#include "pim_rpf.h"
+
+struct rp_info
+{
+  struct prefix group;
+  struct pim_rpf rp;
+  int i_am_rp;
+  char *plist;
+};
+
 void pim_rp_init (void);
 void pim_rp_free (void);
 
@@ -46,4 +61,6 @@ struct pim_rpf *pim_rp_g (struct in_addr group);
 #define RP(G)       pim_rp_g ((G))
 
 void pim_rp_show_information (struct vty *vty, u_char uj);
+
+int pim_rp_list_cmp (void *v1, void *v2);
 #endif
index ff8a6054cf05b18719101ec0e8445a73dcb318bd..400048738a6a32da0e8c9abbaf2898866cae9354 100644 (file)
 #include "pim_zlookup.h"
 #include "pim_ifchannel.h"
 #include "pim_time.h"
+#include "pim_nht.h"
 
 static long long last_route_change_time = -1;
 long long nexthop_lookups_avoided = 0;
 
-static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
+static struct in_addr pim_rpf_find_rpf_addr (struct pim_upstream *up);
 
 void
 pim_rpf_set_refresh_time (void)
@@ -106,7 +107,7 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int nei
     {
       first_ifindex = nexthop_tab[i].ifindex;
 
-      ifp = if_lookup_by_index(first_ifindex);
+      ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT);
       if (!ifp)
         {
           if (PIM_DEBUG_ZEBRA)
@@ -184,14 +185,31 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1,
     (nh1->mrib_route_metric != nh2->mrib_route_metric);
 }
 
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old)
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new)
 {
   struct pim_rpf     *rpf = &up->rpf;
   struct pim_rpf     saved;
+  struct prefix     nht_p;
 
   saved.source_nexthop = rpf->source_nexthop;
   saved.rpf_addr = rpf->rpf_addr;
 
+  if (is_new)
+    {
+      if (PIM_DEBUG_ZEBRA)
+        {
+          char source_str[INET_ADDRSTRLEN];
+          pim_inet4_dump("<source?>", up->upstream_addr, source_str, sizeof(source_str));
+          zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
+                __PRETTY_FUNCTION__, up->sg_str, source_str);
+        }
+      /* Register addr with Zebra NHT */
+      nht_p.family = AF_INET;
+      nht_p.prefixlen = IPV4_MAX_BITLEN;
+      nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+      pim_find_or_track_nexthop (&nht_p, up, NULL);
+    }
+
   if (pim_nexthop_lookup(&rpf->source_nexthop,
                          up->upstream_addr,
                          !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) && 
@@ -245,7 +263,9 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old)
   }
 
   /* detect change in RPF'(S,G) */
-  if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
+  if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr ||
+      saved.source_nexthop.interface != rpf->source_nexthop.interface)
+    {
 
     /* return old rpf to caller ? */
     if (old)
index f4a987793ebfb738d43738bbf68bd15ff25d00ee..85fb1ed8976ff96e6b6a7a9b816f11b458bb6b24 100644 (file)
@@ -64,7 +64,7 @@ struct pim_upstream;
 extern long long nexthop_lookups_avoided;
 
 int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed);
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old);
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new);
 
 int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf);
 int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf);
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
new file mode 100644 (file)
index 0000000..41bf1e5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * IP SSM ranges for FRR
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include <lib/linklist.h>
+#include <lib/prefix.h>
+#include <lib/vty.h>
+#include <lib/vrf.h>
+#include <lib/plist.h>
+
+#include "pimd.h"
+#include "pim_ssm.h"
+#include "pim_zebra.h"
+
+static void
+pim_ssm_range_reevaluate (void)
+{
+  /* 1. Setup register state for (S,G) entries if G has changed from SSM to
+   *    ASM.
+   * 2. check existing (*,G) IGMP registrations to see if they are
+   * still ASM. if they are now SSM delete them.
+   * 3. Allow channel setup for IGMP (*,G) members if G is now ASM
+   * 4. I could tear down all (*,G), (S,G,rpt) states. But that is an
+   * unnecessary sladge hammer and may not be particularly useful as it is
+   * likely the SPT switchover has already happened for flows along such RPTs.
+   * As for the RPT states it seems that the best thing to do is let them age
+   * out gracefully. As long as the FHR and LHR do the right thing RPTs will
+   * disappear in time for SSM groups.
+   */
+  pim_upstream_register_reevaluate ();
+  igmp_source_forward_reevaluate_all ();
+}
+
+void
+pim_ssm_prefix_list_update (struct prefix_list *plist)
+{
+  struct pim_ssm *ssm = pimg->ssm_info;
+
+  if (!ssm->plist_name || strcmp (ssm->plist_name, prefix_list_name (plist)))
+    {
+      /* not ours */
+      return;
+    }
+
+  pim_ssm_range_reevaluate ();
+}
+
+static int
+pim_is_grp_standard_ssm (struct prefix *group)
+{
+  static int first = 1;
+  static struct prefix group_ssm;
+
+  if (first)
+    {
+      str2prefix (PIM_SSM_STANDARD_RANGE, &group_ssm);
+      first = 0;
+    }
+
+  return prefix_match (&group_ssm, group);
+}
+
+int
+pim_is_grp_ssm (struct in_addr group_addr)
+{
+  struct pim_ssm *ssm;
+  struct prefix group;
+  struct prefix_list *plist;
+
+  memset (&group, 0, sizeof (group));
+  group.family = AF_INET;
+  group.u.prefix4 = group_addr;
+  group.prefixlen = 32;
+
+  ssm = pimg->ssm_info;
+  if (!ssm->plist_name)
+    {
+      return pim_is_grp_standard_ssm (&group);
+    }
+
+  plist = prefix_list_lookup (AFI_IP, ssm->plist_name);
+  if (!plist)
+    return 0;
+
+  return (prefix_list_apply (plist, &group) == PREFIX_PERMIT);
+}
+
+int
+pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name)
+{
+  struct pim_ssm *ssm;
+  int change = 0;
+
+  if (vrf_id != VRF_DEFAULT)
+    return PIM_SSM_ERR_NO_VRF;
+
+  ssm = pimg->ssm_info;
+  if (plist_name)
+    {
+      if (ssm->plist_name)
+        {
+          if (!strcmp (ssm->plist_name, plist_name))
+            return PIM_SSM_ERR_DUP;
+          XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+        }
+      ssm->plist_name = XSTRDUP (MTYPE_PIM_FILTER_NAME, plist_name);
+      change = 1;
+    }
+  else
+    {
+      if (ssm->plist_name)
+        {
+          change = 1;
+          XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+        }
+    }
+
+  if (change)
+    pim_ssm_range_reevaluate ();
+
+  return PIM_SSM_ERR_NONE;
+}
+
+void *
+pim_ssm_init (vrf_id_t vrf_id)
+{
+  struct pim_ssm *ssm;
+
+  ssm = XCALLOC (MTYPE_PIM_SSM_INFO, sizeof (*ssm));
+  ssm->vrf_id = vrf_id;
+
+  return ssm;
+}
+
+void
+pim_ssm_terminate (struct pim_ssm *ssm)
+{
+  if (ssm && ssm->plist_name)
+    XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+}
diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h
new file mode 100644 (file)
index 0000000..ca82d33
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * IP SSM ranges for FRR
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef PIM_SSM_H
+#define PIM_SSM_H
+
+#define PIM_SSM_STANDARD_RANGE "232.0.0.0/8"
+
+/* SSM error codes */
+enum pim_ssm_err
+{
+  PIM_SSM_ERR_NONE = 0,
+  PIM_SSM_ERR_NO_VRF = -1,
+  PIM_SSM_ERR_DUP = -2,
+};
+
+struct pim_ssm
+{
+  vrf_id_t vrf_id;
+  char *plist_name; /* prefix list of group ranges */
+};
+
+void pim_ssm_prefix_list_update (struct prefix_list *plist);
+int pim_is_grp_ssm (struct in_addr group_addr);
+int pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name);
+void *pim_ssm_init (vrf_id_t vrf_id);
+void pim_ssm_terminate (struct pim_ssm *ssm);
+#endif
index 035408333218e9c0383dcde21c5823b9c00f1f6e..76b327ab071210a9714107581400af0867a8adfc 100644 (file)
@@ -24,6 +24,7 @@
 #include "log.h"
 #include "memory.h"
 #include "sockopt.h"
+#include "vrf.h"
 
 #include "pimd.h"
 #include "pim_ssmpingd.h"
@@ -259,7 +260,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
     return -1;
   }
 
-  ifp = if_lookup_by_index(ifindex);
+  ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
 
   if (buf[0] != PIM_SSMPINGD_REQUEST) {
     char source_str[INET_ADDRSTRLEN];
index 19f7d3336cb99c94303202e32ecc9301d61cd1c3..172d0d21c985f97086f3165d39880e510f0499ea 100644 (file)
@@ -52,6 +52,8 @@
 #include "pim_register.h"
 #include "pim_msdp.h"
 #include "pim_jp_agg.h"
+#include "pim_nht.h"
+#include "pim_ssm.h"
 
 struct hash *pim_upstream_hash = NULL;
 struct list *pim_upstream_list = NULL;
@@ -142,6 +144,7 @@ pim_upstream_find_parent (struct pim_upstream *child)
 void pim_upstream_free(struct pim_upstream *up)
 {
   XFREE(MTYPE_PIM_UPSTREAM, up);
+  up = NULL;
 }
 
 static void upstream_channel_oil_detach(struct pim_upstream *up)
@@ -152,19 +155,20 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
   }
 }
 
-void
+struct pim_upstream *
 pim_upstream_del(struct pim_upstream *up, const char *name)
 {
   bool notify_msdp = false;
+  struct prefix nht_p;
 
   if (PIM_DEBUG_TRACE)
-    zlog_debug ("%s(%s): Delete %s ref count: %d",
-               __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
+    zlog_debug ("%s(%s): Delete %s ref count: %d, flags: %d (Pre decrement)",
+               __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count, up->flags);
 
   --up->ref_count;
 
   if (up->ref_count >= 1)
-    return;
+    return up;
 
   THREAD_OFF(up->t_ka_timer);
   THREAD_OFF(up->t_rs_timer);
@@ -181,6 +185,7 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   }
 
   join_timer_stop(up);
+  pim_jp_agg_upstream_verification (up, false);
   up->rpf.source_nexthop.interface = NULL;
 
   if (up->sg.src.s_addr != INADDR_ANY) {
@@ -209,10 +214,27 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   listnode_delete (pim_upstream_list, up);
   hash_release (pim_upstream_hash, up);
 
-  if (notify_msdp) {
-    pim_msdp_up_del(&up->sg);
-  }
-  pim_upstream_free(up);
+  if (notify_msdp)
+    {
+      pim_msdp_up_del (&up->sg);
+    }
+
+  /* Deregister addr with Zebra NHT */
+  nht_p.family = AF_INET;
+  nht_p.prefixlen = IPV4_MAX_BITLEN;
+  nht_p.u.prefix4 = up->upstream_addr;
+  if (PIM_DEBUG_TRACE)
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str (&nht_p, buf, sizeof (buf));
+      zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
+                __PRETTY_FUNCTION__, up->sg_str, buf);
+    }
+  pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
+  pim_upstream_free (up);
+
+  return NULL;
 }
 
 void
@@ -267,13 +289,15 @@ static void join_timer_stop(struct pim_upstream *up)
 {
   struct pim_neighbor *nbr;
 
+  THREAD_OFF (up->t_join_timer);
+
   nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
                            up->rpf.rpf_addr.u.prefix4);
 
   if (nbr)
     pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
 
-  THREAD_OFF (up->t_join_timer);
+  pim_jp_agg_upstream_verification (up, false);
 }
 
 void
@@ -303,6 +327,7 @@ join_timer_start(struct pim_upstream *up)
                       on_join_timer,
                       up, qpim_t_periodic);
     }
+  pim_jp_agg_upstream_verification (up, true);
 }
 
 /*
@@ -314,13 +339,6 @@ join_timer_start(struct pim_upstream *up)
  */
 void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old)
 {
-  struct pim_neighbor *nbr;
-
-  nbr = pim_neighbor_find (old->source_nexthop.interface,
-                           old->rpf_addr.u.prefix4);
-  if (nbr)
-    pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
-
   //THREAD_OFF(up->t_join_timer);
   join_timer_start(up);
 }
@@ -459,6 +477,51 @@ pim_upstream_could_register (struct pim_upstream *up)
   return 0;
 }
 
+/* Source registration is supressed for SSM groups. When the SSM range changes
+ * we re-revaluate register setup for existing upstream entries */
+void
+pim_upstream_register_reevaluate (void)
+{
+  struct listnode *upnode;
+  struct pim_upstream *up;
+
+  for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, upnode, up))
+    {
+      /* If FHR is set CouldRegister is True. Also check if the flow
+       * is actually active; if it is not kat setup will trigger source
+       * registration whenever the flow becomes active. */
+      if (!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) || !up->t_ka_timer)
+        continue;
+
+      if (pim_is_grp_ssm (up->sg.grp))
+        {
+          /* clear the register state  for SSM groups */
+          if (up->reg_state != PIM_REG_NOINFO)
+            {
+              if (PIM_DEBUG_PIM_EVENTS)
+                zlog_debug ("Clear register for %s as G is now SSM",
+                            up->sg_str);
+              /* remove regiface from the OIL if it is there*/
+              pim_channel_del_oif (up->channel_oil, pim_regiface,
+                                   PIM_OIF_FLAG_PROTO_PIM);
+              up->reg_state = PIM_REG_NOINFO;
+            }
+        }
+      else
+        {
+          /* register ASM sources with the RP */
+          if (up->reg_state == PIM_REG_NOINFO)
+            {
+              if (PIM_DEBUG_PIM_EVENTS)
+                zlog_debug ("Register %s as G is now ASM", up->sg_str);
+              pim_channel_add_oif (up->channel_oil, pim_regiface,
+                                   PIM_OIF_FLAG_PROTO_PIM);
+              up->reg_state = PIM_REG_JOIN;
+            }
+        }
+    }
+}
+
 void
 pim_upstream_switch(struct pim_upstream *up,
                    enum pim_upstream_state new_state)
@@ -490,9 +553,8 @@ pim_upstream_switch(struct pim_upstream *up,
             PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
             if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
               {
-                up->reg_state = PIM_REG_JOIN;
                 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
-               pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+                pim_register_join (up);
               }
          }
        else
@@ -517,7 +579,7 @@ pim_upstream_switch(struct pim_upstream *up,
   }
 }
 
-static int
+int
 pim_upstream_compare (void *arg1, void *arg2)
 {
   const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
@@ -548,11 +610,12 @@ pim_upstream_new (struct prefix_sg *sg,
   struct pim_upstream *up;
 
   up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
-  if (!up) {
-    zlog_err("%s: PIM XCALLOC(%zu) failure",
+  if (!up)
+    {
+      zlog_err("%s: PIM XCALLOC(%zu) failure",
             __PRETTY_FUNCTION__, sizeof(*up));
-    return NULL;
-  }
+      return NULL;
+    }
   
   up->sg                          = *sg;
   pim_str_sg_set (sg, up->sg_str);
@@ -600,12 +663,19 @@ pim_upstream_new (struct prefix_sg *sg,
   if (up->sg.src.s_addr != INADDR_ANY)
     wheel_add_item (pim_upstream_sg_wheel, up);
 
-  rpf_result = pim_rpf_update(up, NULL);
+  rpf_result = pim_rpf_update(up, NULL, 1);
   if (rpf_result == PIM_RPF_FAILURE) {
+    struct prefix nht_p;
+
     if (PIM_DEBUG_TRACE)
       zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
                   up->sg_str);
 
+    nht_p.family = AF_INET;
+    nht_p.prefixlen = IPV4_MAX_BITLEN;
+    nht_p.u.prefix4 = up->upstream_addr;
+    pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
     if (up->parent)
       {
        listnode_delete (up->parent->sources, up);
@@ -631,7 +701,11 @@ pim_upstream_new (struct prefix_sg *sg,
   listnode_add_sort(pim_upstream_list, up);
 
   if (PIM_DEBUG_TRACE)
-    zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
+    {
+      zlog_debug ("%s: Created Upstream %s upstream_addr %s",
+            __PRETTY_FUNCTION__, up->sg_str,
+            inet_ntoa (up->upstream_addr));
+    }
 
   return up;
 }
@@ -646,7 +720,31 @@ struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
   return up;
 }
 
-static void pim_upstream_ref(struct pim_upstream *up, int flags)
+struct pim_upstream *
+pim_upstream_find_or_add(struct prefix_sg *sg,
+                         struct interface *incoming,
+                         int flags, const char *name)
+{
+  struct pim_upstream *up;
+
+  up = pim_upstream_find(sg);
+
+  if (up)
+    {
+      if (!(up->flags & flags))
+        {
+          up->flags |= flags;
+          up->ref_count++;
+        }
+    }
+  else
+    up = pim_upstream_add (sg, incoming, flags, name);
+
+  return up;
+}
+
+void
+pim_upstream_ref(struct pim_upstream *up, int flags)
 {
   up->flags |= flags;
   ++up->ref_count;
@@ -691,11 +789,11 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
 
   if (ch->upstream == up)
     {
-      if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
-       return 1;
-
       if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
        return 0;
+
+      if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
+       return 1;
     }
 
   /*
@@ -703,6 +801,16 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
    */
   if (parent && ch->upstream == parent)
     {
+      struct listnode *ch_node;
+      struct pim_ifchannel *child;
+      for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child))
+        {
+          if (child->upstream == up)
+            {
+               if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
+                 return 0;
+             }
+        }
       if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
        return 1;
     }
@@ -955,10 +1063,8 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
       zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
 
     PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
-    if (up->reg_state == PIM_REG_NOINFO) {
-      pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
-      up->reg_state = PIM_REG_JOIN;
-    }
+    if (up->reg_state == PIM_REG_NOINFO)
+      pim_register_join (up);
   }
 }
 
@@ -1403,7 +1509,7 @@ pim_upstream_find_new_rpf (void)
          if (PIM_DEBUG_TRACE)
            zlog_debug ("Upstream %s without a path to send join, checking",
                        up->sg_str);
-         pim_rpf_update (up, NULL);
+         pim_rpf_update (up, NULL, 1);
        }
     }
 }
index b191fe94044cfb8472f8e8466dc831e562a517cb..6f7556f323e84746950a8312036ecf7e93b20c7f 100644 (file)
@@ -33,6 +33,7 @@
 #define PIM_UPSTREAM_FLAG_MASK_SRC_PIM                 (1 << 4)
 #define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM              (1 << 5)
 #define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP                (1 << 6)
+#define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE       (1 << 7)
 
 #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -41,6 +42,7 @@
 #define PIM_UPSTREAM_FLAG_TEST_SRC_PIM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+#define PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -49,6 +51,7 @@
 #define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+#define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -57,6 +60,7 @@
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+#define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
 
 enum pim_upstream_state {
   PIM_UPSTREAM_NOTJOINED,
@@ -129,10 +133,14 @@ struct hash *pim_upstream_hash;
 
 void pim_upstream_free(struct pim_upstream *up);
 struct pim_upstream *pim_upstream_find (struct prefix_sg *sg);
+struct pim_upstream *pim_upstream_find_or_add (struct prefix_sg *sg,
+                                               struct interface *ifp, int flags,
+                                               const char *name);
 struct pim_upstream *pim_upstream_add (struct prefix_sg *sg,
                                       struct interface *ifp, int flags,
                                       const char *name);
-void pim_upstream_del(struct pim_upstream *up, const char *name);
+void pim_upstream_ref (struct pim_upstream *up, int flags);
+struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name);
 
 int pim_upstream_evaluate_join_desired(struct pim_upstream *up);
 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
@@ -183,4 +191,6 @@ void pim_upstream_init (void);
 void pim_upstream_terminate (void);
 
 void join_timer_start (struct pim_upstream *up);
+int pim_upstream_compare (void *arg1, void *arg2);
+void pim_upstream_register_reevaluate (void);
 #endif /* PIM_UPSTREAM_H */
index 5b6a79b95a0a22daaeee7d07dd546c626a41a1ea..f4bfcc5ce004b414d045e9701b5637a86e490982 100644 (file)
@@ -38,6 +38,7 @@
 #include "pim_static.h"
 #include "pim_rp.h"
 #include "pim_msdp.h"
+#include "pim_ssm.h"
 
 int
 pim_debug_config_write (struct vty *vty)
@@ -145,6 +146,7 @@ pim_debug_config_write (struct vty *vty)
 int pim_global_config_write(struct vty *vty)
 {
   int writes = 0;
+  struct pim_ssm *ssm = pimg->ssm_info;
 
   writes += pim_msdp_config_write (vty);
 
@@ -174,6 +176,12 @@ int pim_global_config_write(struct vty *vty)
               qpim_packet_process, VTY_NEWLINE);
       ++writes;
     }
+  if (ssm->plist_name)
+    {
+      vty_out (vty, "ip pim ssm prefix-list %s%s",
+               ssm->plist_name, VTY_NEWLINE);
+      ++writes;
+    }
 
   if (qpim_ssmpingd_list) {
     struct listnode *node;
@@ -206,12 +214,8 @@ int pim_interface_config_write(struct vty *vty)
     if (ifp->info) {
       struct pim_interface *pim_ifp = ifp->info;
 
-      /* IF ip pim ssm */
       if (PIM_IF_TEST_PIM(pim_ifp->options)) {
-       if (pim_ifp->itype == PIM_INTERFACE_SSM)
-         vty_out(vty, " ip pim ssm%s", VTY_NEWLINE);
-       else
-         vty_out(vty, " ip pim sm%s", VTY_NEWLINE);
+       vty_out(vty, " ip pim sm%s", VTY_NEWLINE);
        ++writes;
       }
 
index 1db6616c58845cb83cd5bee814fafd403e713f7c..4e18c478d6a184c9f5efbe324ccdc935a8285aae 100644 (file)
@@ -45,6 +45,8 @@
 #include "pim_rp.h"
 #include "pim_igmpv3.h"
 #include "pim_jp_agg.h"
+#include "pim_nht.h"
+#include "pim_ssm.h"
 
 #undef PIM_DEBUG_IFADDR_DUMP
 #define PIM_DEBUG_IFADDR_DUMP
@@ -52,9 +54,6 @@
 static struct zclient *zclient = NULL;
 
 static int fib_lookup_if_vif_index(struct in_addr addr);
-static int del_oif(struct channel_oil *channel_oil,
-                  struct interface *oif,
-                  uint32_t proto_mask);
 
 /* Router-id update message from zebra. */
 static int pim_router_id_update_zebra(int command, struct zclient *zclient,
@@ -337,26 +336,27 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
     return 0;
   
   p = c->address;
-  if (p->family != AF_INET)
-    return 0;
-  
-  if (PIM_DEBUG_ZEBRA) {
-    char buf[BUFSIZ];
-    prefix2str(p, buf, BUFSIZ);
-    zlog_debug("%s: %s disconnected IP address %s flags %u %s",
-              __PRETTY_FUNCTION__,
-              c->ifp->name, buf, c->flags,
-              CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
-    
+  if (p->family == AF_INET)
+    {
+        if (PIM_DEBUG_ZEBRA) {
+          char buf[BUFSIZ];
+          prefix2str(p, buf, BUFSIZ);
+          zlog_debug("%s: %s disconnected IP address %s flags %u %s",
+                     __PRETTY_FUNCTION__,
+                     c->ifp->name, buf, c->flags,
+                     CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
+
 #ifdef PIM_DEBUG_IFADDR_DUMP
-    dump_if_address(c->ifp);
+          dump_if_address(c->ifp);
 #endif
-  }
+        }
 
-  pim_if_addr_del(c, 0);
-  pim_rp_setup();
-  pim_i_am_rp_re_evaluate();
-  
+        pim_if_addr_del(c, 0);
+        pim_rp_setup();
+        pim_i_am_rp_re_evaluate();
+    }
+
+  connected_free (c);
   return 0;
 }
 
@@ -375,12 +375,19 @@ static void scan_upstream_rpf_cache()
 
     old.source_nexthop.interface = up->rpf.source_nexthop.interface;
     old.source_nexthop.nbr       = up->rpf.source_nexthop.nbr;
-    rpf_result = pim_rpf_update(up, &old);
-    zlog_debug ("Looking at upstream: %s %d", up->sg_str, rpf_result);
+    rpf_result = pim_rpf_update(up, &old, 0);
+
     if (rpf_result == PIM_RPF_FAILURE)
       continue;
 
     if (rpf_result == PIM_RPF_CHANGED) {
+      struct pim_neighbor *nbr;
+
+      nbr = pim_neighbor_find (old.source_nexthop.interface,
+                               old.rpf_addr.u.prefix4);
+      if (nbr)
+        pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
+
       /*
        * We have detected a case where we might need to rescan
        * the inherited o_list so do it.
@@ -444,7 +451,7 @@ static void scan_upstream_rpf_cache()
 }
 
 void
-pim_scan_individual_oil (struct channel_oil *c_oil)
+pim_scan_individual_oil (struct channel_oil *c_oil, int in_vif_index)
 {
   struct in_addr vif_source;
   int input_iface_vif_index;
@@ -453,7 +460,10 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
   if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp))
     return;
 
-  input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
+  if (in_vif_index)
+    input_iface_vif_index = in_vif_index;
+  else
+    input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
   if (input_iface_vif_index < 1)
     {
       if (PIM_DEBUG_ZEBRA)
@@ -509,8 +519,6 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
                   source_str, group_str,
                   new_iif->name, input_iface_vif_index);
       }
-
-      //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
     }
 
     /* update iif vif_index */
@@ -548,7 +556,7 @@ void pim_scan_oil()
   ++qpim_scan_oil_events;
 
   for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
-    pim_scan_individual_oil (c_oil);
+    pim_scan_individual_oil (c_oil, 0);
 }
 
 static int on_rpf_cache_refresh(struct thread *t)
@@ -594,127 +602,6 @@ void sched_rpf_cache_refresh(void)
                        0, qpim_rpf_cache_refresh_delay_msec);
 }
 
-static int redist_read_ipv4_route(int command, struct zclient *zclient,
-                                 zebra_size_t length, vrf_id_t vrf_id)
-{
-  struct stream *s;
-  struct zapi_ipv4 api;
-  ifindex_t ifindex;
-  struct in_addr nexthop;
-  struct prefix_ipv4 p;
-  int min_len = 4;
-
-  if (length < min_len) {
-    zlog_warn("%s %s: short buffer: length=%d min=%d",
-             __FILE__, __PRETTY_FUNCTION__,
-             length, min_len);
-    return -1;
-  }
-
-  s = zclient->ibuf;
-  ifindex = 0;
-  nexthop.s_addr = 0;
-
-  /* Type, flags, message. */
-  api.type = stream_getc(s);
-  api.instance = stream_getw (s);
-  api.flags = stream_getl(s);
-  api.message = stream_getc(s);
-
-  /* IPv4 prefix length. */
-  memset(&p, 0, sizeof(struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = stream_getc(s);
-
-  min_len +=
-    PSIZE(p.prefixlen) +
-    CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
-    CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
-    CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
-    CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
-
-  if (PIM_DEBUG_ZEBRA) {
-    zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
-              __FILE__, __PRETTY_FUNCTION__,
-              length, min_len,
-              CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
-              CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
-              CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
-              CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
-  }
-
-  /* IPv4 prefix. */
-  stream_get(&p.prefix, s, PSIZE(p.prefixlen));
-
-  /* Nexthop, ifindex, distance, metric. */
-  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
-    api.nexthop_num = stream_getc(s);
-    nexthop.s_addr = stream_get_ipv4(s);
-  }
-  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
-    api.ifindex_num = stream_getc(s);
-    ifindex = stream_getl(s);
-  }
-
-  api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
-    stream_getc(s) :
-    0;
-
-  api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
-    stream_getl(s) :
-    0;
-
-  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
-    api.tag = stream_getl (s);
-  else
-    api.tag = 0;
-
-  switch (command) {
-  case ZEBRA_REDISTRIBUTE_IPV4_ADD:
-    if (PIM_DEBUG_ZEBRA) {
-      char buf[2][INET_ADDRSTRLEN];
-      zlog_debug("%s: add %s %s/%d "
-                "nexthop %s ifindex %d metric%s %u distance%s %u",
-                __PRETTY_FUNCTION__,
-                zebra_route_string(api.type),
-                inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
-                p.prefixlen,
-                inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
-                ifindex,
-                CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
-                api.metric,
-                CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
-                api.distance);
-    }
-    break;
-  case ZEBRA_REDISTRIBUTE_IPV4_DEL:
-    if (PIM_DEBUG_ZEBRA) {
-      char buf[2][INET_ADDRSTRLEN];
-      zlog_debug("%s: delete %s %s/%d "
-                "nexthop %s ifindex %d metric%s %u distance%s %u",
-                __PRETTY_FUNCTION__,
-                zebra_route_string(api.type),
-                inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
-                p.prefixlen,
-                inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
-                ifindex,
-                CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
-                api.metric,
-                CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
-                api.distance);
-    }
-    break;
-  default:
-    zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
-    return -1;
-  }
-
-  sched_rpf_cache_refresh();
-
-  pim_rp_setup ();
-  return 0;
-}
-
 static void
 pim_zebra_connected (struct zclient *zclient)
 {
@@ -742,8 +629,7 @@ void pim_zebra_init(void)
   zclient->interface_down           = pim_zebra_if_state_down;
   zclient->interface_address_add    = pim_zebra_if_address_add;
   zclient->interface_address_delete = pim_zebra_if_address_del;
-  zclient->redistribute_route_ipv4_add    = redist_read_ipv4_route;
-  zclient->redistribute_route_ipv4_del    = redist_read_ipv4_route;
+  zclient->nexthop_update           = pim_parse_nexthop_update;
 
   zclient_init(zclient, ZEBRA_ROUTE_PIM, 0);
   if (PIM_DEBUG_PIM_TRACE) {
@@ -847,7 +733,7 @@ static int fib_lookup_if_vif_index(struct in_addr addr)
     pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
     zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
               __FILE__, __PRETTY_FUNCTION__,
-              first_ifindex, ifindex2ifname(first_ifindex), addr_str);
+              first_ifindex, ifindex2ifname(first_ifindex, VRF_DEFAULT), addr_str);
   }
 
   vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
@@ -867,135 +753,82 @@ static int fib_lookup_if_vif_index(struct in_addr addr)
   return vif_index;
 }
 
-static int del_oif(struct channel_oil *channel_oil,
-                  struct interface *oif,
-                  uint32_t proto_mask)
+static void
+igmp_source_forward_reevaluate_one(struct igmp_source *source)
 {
-  struct pim_interface *pim_ifp;
-  int old_ttl;
-
-  pim_ifp = oif->info;
-
-  if (PIM_DEBUG_MROUTE) {
-    char group_str[INET_ADDRSTRLEN]; 
-    char source_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-    zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
-              __FILE__, __PRETTY_FUNCTION__,
-              source_str, group_str,
-              proto_mask, oif->name, pim_ifp->mroute_vif_index);
-  }
-
-  /* Prevent single protocol from unsubscribing same interface from
-     channel (S,G) multiple times */
-  if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
-    if (PIM_DEBUG_MROUTE)
-      {
-       char group_str[INET_ADDRSTRLEN]; 
-       char source_str[INET_ADDRSTRLEN];
-       pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-       pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-       zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
-                  __FILE__, __PRETTY_FUNCTION__,
-                  proto_mask, oif->name, pim_ifp->mroute_vif_index,
-                  channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
-                  source_str, group_str);
-      }
-    return -2;
-  }
+  struct prefix_sg sg;
+  struct igmp_group *group = source->source_group;
+  struct pim_ifchannel *ch;
 
-  /* Mark that protocol is no longer interested in this OIF */
-  channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
+  if ((source->source_addr.s_addr != INADDR_ANY) ||
+      !IGMP_SOURCE_TEST_FORWARDING (source->source_flags))
+    return;
 
-  /* Allow multiple protocols to unsubscribe same interface from
-     channel (S,G) multiple times, by silently ignoring requests while
-     there is at least one protocol interested in the channel */
-  if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
+  memset (&sg, 0, sizeof (struct prefix_sg));
+  sg.src = source->source_addr;
+  sg.grp = group->group_addr;
 
-    /* Check the OIF keeps existing before returning, and only log
-       warning otherwise */
-    if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
-      if (PIM_DEBUG_MROUTE)
-       {
-         char group_str[INET_ADDRSTRLEN];
-         char source_str[INET_ADDRSTRLEN];
-         pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-         pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-         zlog_debug("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
-                    __FILE__, __PRETTY_FUNCTION__,
-                    proto_mask, oif->name, pim_ifp->mroute_vif_index,
-                    channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
-                    source_str, group_str);
-       }
+  ch = pim_ifchannel_find (group->group_igmp_sock->interface, &sg);
+  if (pim_is_grp_ssm (group->group_addr))
+    {
+      /* If SSM group withdraw local membership */
+      if (ch && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE))
+        {
+          if (PIM_DEBUG_PIM_EVENTS)
+            zlog_debug ("local membership del for %s as G is now SSM",
+                        pim_str_sg_dump (&sg));
+          pim_ifchannel_local_membership_del (group->group_igmp_sock->interface, &sg);
+        }
     }
+  else
+    {
+      /* If ASM group add local membership */
+      if (!ch || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO))
+        {
+          if (PIM_DEBUG_PIM_EVENTS)
+            zlog_debug ("local membership add for %s as G is now ASM",
+                        pim_str_sg_dump (&sg));
+          pim_ifchannel_local_membership_add (group->group_igmp_sock->interface, &sg);
+        }
+    }
+}
 
-    return 0;
-  }
-
-  old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
-
-  if (old_ttl < 1) {
-    if (PIM_DEBUG_MROUTE)
-      {
-       char group_str[INET_ADDRSTRLEN];
-       char source_str[INET_ADDRSTRLEN];
-       pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-       pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-       zlog_debug("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
-                  __FILE__, __PRETTY_FUNCTION__,
-                  oif->name, pim_ifp->mroute_vif_index,
-                  source_str, group_str);
-      }
-    return -3;
-  }
-
-  channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
-
-  if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
-    char group_str[INET_ADDRSTRLEN];
-    char source_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-    zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
-             __FILE__, __PRETTY_FUNCTION__,
-             oif->name, pim_ifp->mroute_vif_index,
-             source_str, group_str);
-    
-    channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
-    return -4;
-  }
-
-  --channel_oil->oil_size;
+void
+igmp_source_forward_reevaluate_all(void)
+{
+  struct listnode *ifnode;
+  struct interface *ifp;
 
-  if (channel_oil->oil_size < 1) {
-    if (pim_mroute_del(channel_oil, __PRETTY_FUNCTION__)) {
-      if (PIM_DEBUG_MROUTE)
-       {
-         /* just log a warning in case of failure */
-         char group_str[INET_ADDRSTRLEN];
-         char source_str[INET_ADDRSTRLEN];
-         pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-         pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-         zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
-                    __FILE__, __PRETTY_FUNCTION__,
-                    source_str, group_str);
-       }
-    }
-  }
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
+    {
+      struct pim_interface *pim_ifp = ifp->info;
+      struct listnode  *sock_node;
+      struct igmp_sock *igmp;
 
-  if (PIM_DEBUG_MROUTE) {
-    char group_str[INET_ADDRSTRLEN]; 
-    char source_str[INET_ADDRSTRLEN];
-    pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-    pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-    zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
-              __FILE__, __PRETTY_FUNCTION__,
-              source_str, group_str,
-              proto_mask, oif->name, pim_ifp->mroute_vif_index);
-  }
+      if (!pim_ifp)
+        continue;
 
-  return 0;
+      /* scan igmp sockets */
+      for (ALL_LIST_ELEMENTS_RO (pim_ifp->igmp_socket_list, sock_node, igmp))
+        {
+          struct listnode *grpnode;
+          struct igmp_group *grp;
+
+          /* scan igmp groups */
+          for (ALL_LIST_ELEMENTS_RO (igmp->igmp_group_list, grpnode, grp))
+            {
+              struct listnode    *srcnode;
+              struct igmp_source *src;
+
+              /* scan group sources */
+              for (ALL_LIST_ELEMENTS_RO (grp->group_source_list,
+                                        srcnode, src))
+                {
+                  igmp_source_forward_reevaluate_one (src);
+                } /* scan group sources */
+            } /* scan igmp groups */
+        } /* scan igmp sockets */
+    } /* scan interfaces */
 }
 
 void igmp_source_forward_start(struct igmp_source *source)
@@ -1152,16 +985,16 @@ void igmp_source_forward_stop(struct igmp_source *source)
    Possibly because of multiple calls. When that happens, we
    enter the below if statement and this function returns early
    which in turn triggers the calling function to assert.
-   Making the call to del_oif and ignoring the return code 
-   fixes the issue without ill effect, similar to 
-   pim_forward_stop below.   
+   Making the call to pim_channel_del_oif and ignoring the return code
+   fixes the issue without ill effect, similar to
+   pim_forward_stop below.
   */
-  result = del_oif(source->source_channel_oil,
-                  group->group_igmp_sock->interface,
-                  PIM_OIF_FLAG_PROTO_IGMP);
+  result = pim_channel_del_oif(source->source_channel_oil,
+                               group->group_igmp_sock->interface,
+                               PIM_OIF_FLAG_PROTO_IGMP);
   if (result) {
     if (PIM_DEBUG_IGMP_TRACE)
-      zlog_debug("%s: del_oif() failed with return=%d",
+      zlog_debug("%s: pim_channel_del_oif() failed with return=%d",
                 __func__, result);
     return;
   }
@@ -1235,18 +1068,9 @@ void pim_forward_stop(struct pim_ifchannel *ch)
               ch->sg_str, ch->interface->name);
   }
 
-  if (!up->channel_oil) {
-    if (PIM_DEBUG_PIM_TRACE)
-      zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
-                __PRETTY_FUNCTION__,
-                ch->sg_str, ch->interface->name);
-
-    return;
-  }
-
-  del_oif(up->channel_oil,
-         ch->interface,
-         PIM_OIF_FLAG_PROTO_PIM);
+  pim_channel_del_oif(up->channel_oil,
+                      ch->interface,
+                      PIM_OIF_FLAG_PROTO_PIM);
 }
 
 void
@@ -1262,3 +1086,11 @@ pim_zebra_zclient_update (struct vty *vty)
     vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
   }
 }
+
+struct zclient *pim_zebra_zclient_get (void)
+{
+  if (zclient)
+    return zclient;
+  else
+    return NULL;
+}
index 751a7be25dbd08cad52ae479cd14d9dfd2d683d4..2ed463efaad14c842997efedd4e2303b03dbe8a4 100644 (file)
 #ifndef PIM_ZEBRA_H
 #define PIM_ZEBRA_H
 
+#include <zebra.h>
+#include "zclient.h"
+
 #include "pim_igmp.h"
 #include "pim_ifchannel.h"
 
 void pim_zebra_init(void);
 void pim_zebra_zclient_update (struct vty *vty);
 
-void pim_scan_individual_oil (struct channel_oil *c_oil);
+void pim_scan_individual_oil (struct channel_oil *c_oil, int in_vif_index);
 void pim_scan_oil(void);
 
 void igmp_anysource_forward_start(struct igmp_group *group);
@@ -35,9 +38,11 @@ void igmp_anysource_forward_stop(struct igmp_group *group);
 
 void igmp_source_forward_start(struct igmp_source *source);
 void igmp_source_forward_stop(struct igmp_source *source);
+void igmp_source_forward_reevaluate_all(void);
 
 void pim_forward_start(struct pim_ifchannel *ch);
 void pim_forward_stop(struct pim_ifchannel *ch);
 
 void sched_rpf_cache_refresh(void);
+struct zclient *pim_zebra_zclient_get (void);
 #endif /* PIM_ZEBRA_H */
index 7ec31c7d50a16d738c88fe3b0b1cfdba1d2e056b..f77990ab5ab81faa3b7e05ec34f850ce65e330aa 100644 (file)
@@ -253,7 +253,7 @@ static int zclient_read_nexthop(struct zclient *zlookup,
       nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
       stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16);
       nexthop_tab[num_ifindex].ifindex = stream_getl (s);
-      nbr = pim_neighbor_find_if (if_lookup_by_index_vrf (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
+      nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
       if (nbr)
         {
           nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
index c8a0efc401b8819e9fb541528c3b500a9478f336..bdbd251e209722581d7f44539524863db9404312 100644 (file)
@@ -26,6 +26,8 @@
 #include "prefix.h"
 #include "vty.h"
 #include "plist.h"
+#include "hash.h"
+#include "jhash.h"
 
 #include "pimd.h"
 #include "pim_cmd.h"
@@ -39,7 +41,9 @@
 #include "pim_ssmpingd.h"
 #include "pim_static.h"
 #include "pim_rp.h"
+#include "pim_ssm.h"
 #include "pim_zlookup.h"
+#include "pim_nht.h"
 
 const char *const PIM_ALL_SYSTEMS      = MCAST_ALL_SYSTEMS;
 const char *const PIM_ALL_ROUTERS      = MCAST_ALL_ROUTERS;
@@ -71,10 +75,147 @@ unsigned int              qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
 signed int                qpim_rp_keep_alive_time = 0;
 int64_t                   qpim_nexthop_lookups = 0;
 int                       qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
+struct pim_instance          *pimg = NULL;
 
 int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
 int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
 
+static struct pim_instance *pim_instance_init (vrf_id_t vrf_id, afi_t afi);
+static void pim_instance_terminate (void);
+
+static int
+pim_vrf_new (struct vrf *vrf)
+{
+  zlog_debug ("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
+  return 0;
+}
+
+static int
+pim_vrf_delete (struct vrf *vrf)
+{
+  zlog_debug ("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
+  return 0;
+}
+
+static int
+pim_vrf_enable (struct vrf *vrf)
+{
+
+  if (!vrf) // unexpected
+    return -1;
+
+  if (vrf->vrf_id == VRF_DEFAULT)
+    {
+      pimg = pim_instance_init (VRF_DEFAULT, AFI_IP);
+      if (pimg == NULL)
+        {
+          zlog_err ("%s %s: pim class init failure ", __FILE__,
+                    __PRETTY_FUNCTION__);
+          /*
+           * We will crash and burn otherwise
+           */
+          exit(1);
+        }
+    }
+  return 0;
+}
+
+static int
+pim_vrf_disable (struct vrf *vrf)
+{
+  if (vrf->vrf_id == VRF_DEFAULT)
+    return 0;
+
+  if (vrf->vrf_id == VRF_DEFAULT)
+    pim_instance_terminate ();
+
+  /* Note: This is a callback, the VRF will be deleted by the caller. */
+  return 0;
+}
+
+void
+pim_vrf_init (void)
+{
+  vrf_add_hook (VRF_NEW_HOOK, pim_vrf_new);
+  vrf_add_hook (VRF_ENABLE_HOOK, pim_vrf_enable);
+  vrf_add_hook (VRF_DISABLE_HOOK, pim_vrf_disable);
+  vrf_add_hook (VRF_DELETE_HOOK, pim_vrf_delete);
+
+  vrf_init ();
+}
+
+static void
+pim_vrf_terminate (void)
+{
+  vrf_add_hook (VRF_NEW_HOOK, NULL);
+  vrf_add_hook (VRF_ENABLE_HOOK, NULL);
+  vrf_add_hook (VRF_DISABLE_HOOK, NULL);
+  vrf_add_hook (VRF_DELETE_HOOK, NULL);
+
+  vrf_terminate ();
+}
+
+/* Key generate for pim->rpf_hash */
+static unsigned int
+pim_rpf_hash_key (void *arg)
+{
+  struct pim_nexthop_cache *r = (struct pim_nexthop_cache *) arg;
+
+  return jhash_1word (r->rpf.rpf_addr.u.prefix4.s_addr, 0);
+}
+
+/* Compare pim->rpf_hash node data */
+static int
+pim_rpf_equal (const void *arg1, const void *arg2)
+{
+  const struct pim_nexthop_cache *r1 =
+    (const struct pim_nexthop_cache *) arg1;
+  const struct pim_nexthop_cache *r2 =
+    (const struct pim_nexthop_cache *) arg2;
+
+  return prefix_same (&r1->rpf.rpf_addr, &r2->rpf.rpf_addr);
+}
+
+/* Cleanup pim->rpf_hash each node data */
+static void
+pim_rp_list_hash_clean (void *data)
+{
+  struct pim_nexthop_cache *pnc;
+
+  pnc = (struct pim_nexthop_cache *) data;
+  if (pnc->rp_list->count)
+    list_delete_all_node (pnc->rp_list);
+  if (pnc->upstream_list->count)
+    list_delete_all_node (pnc->upstream_list);
+}
+
+void
+pim_prefix_list_update (struct prefix_list *plist)
+{
+    pim_rp_prefix_list_update (plist);
+    pim_ssm_prefix_list_update (plist);
+}
+
+static void
+pim_instance_terminate (void)
+{
+  /* Traverse and cleanup rpf_hash */
+  if (pimg->rpf_hash)
+    {
+      hash_clean (pimg->rpf_hash, (void *) pim_rp_list_hash_clean);
+      hash_free (pimg->rpf_hash);
+      pimg->rpf_hash = NULL;
+    }
+
+  if (pimg->ssm_info)
+    {
+      pim_ssm_terminate (pimg->ssm_info);
+      pimg->ssm_info = NULL;
+    }
+
+  XFREE (MTYPE_PIM_PIM_INSTANCE, pimg);
+}
+
 static void pim_free()
 {
   pim_ssmpingd_destroy();
@@ -96,6 +237,32 @@ static void pim_free()
   zprivs_terminate(&pimd_privs);
 }
 
+static struct pim_instance *
+pim_instance_init (vrf_id_t vrf_id, afi_t afi)
+{
+  struct pim_instance *pim;
+
+  pim = XCALLOC (MTYPE_PIM_PIM_INSTANCE, sizeof (struct pim_instance));
+  if (!pim)
+    return NULL;
+
+  pim->vrf_id = vrf_id;
+  pim->afi = afi;
+
+  pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
+
+  if (PIM_DEBUG_ZEBRA)
+    zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
+
+  pim->ssm_info = pim_ssm_init (vrf_id);
+  if (!pim->ssm_info) {
+    pim_instance_terminate ();
+    return NULL;
+  }
+
+  return pim;
+}
+
 void pim_init()
 {
   qpim_rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
@@ -147,4 +314,11 @@ void pim_init()
 void pim_terminate()
 {
   pim_free();
+
+  /* reverse prefix_list_init */
+  prefix_list_add_hook (NULL);
+  prefix_list_delete_hook (NULL);
+  prefix_list_reset ();
+
+  pim_vrf_terminate ();
 }
index 09060163000b446ce0a17ad670f97598db12e855..69aee28f8f86cbca70ee5edd902978e9e1d53fca 100644 (file)
 #define PIMD_H
 
 #include <stdint.h>
+#include "zebra.h"
+#include "libfrr.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
 
 #include "pim_str.h"
 #include "pim_memory.h"
@@ -232,10 +237,23 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DONT_DEBUG_MSDP_PACKETS        (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
 #define PIM_DONT_DEBUG_MSDP_INTERNAL       (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
 
+/* Per VRF PIM DB */
+struct pim_instance
+{
+  afi_t afi;
+  vrf_id_t vrf_id;
+  struct hash *rpf_hash;
+  void *ssm_info; /* per-vrf SSM configuration */
+};
+
+extern struct pim_instance *pimg; //Pim Global Instance
+
 void pim_init(void);
 void pim_terminate(void);
 
 extern void pim_route_map_init (void);
 extern void pim_route_map_terminate(void);
+void pim_vrf_init (void);
+void pim_prefix_list_update (struct prefix_list *plist);
 
 #endif /* PIMD_H */
index db3c7d45c83f8e97702ee86a67fc83d7a2d45902..6bec5d65cd3f2a4ed9542aae15a78481d591ee80 100644 (file)
@@ -1,4 +1,4 @@
-Building your own FreeRangeRouting RPM
+Building your own FRRouting RPM
 ======================================
 (Tested on CentOS 6, CentOS 7 and Fedora 22.)
 
@@ -12,7 +12,7 @@ Building your own FreeRangeRouting RPM
        
 2. Checkout FRR under a **unpriviledged** user account
 
-               git clone https://github.com/freerangerouting/frr.git frr
+               git clone https://github.com/frrouting/frr.git frr
 
 3. Run Bootstrap and make distribution tar.gz
 
index bb23931b13f3204b5606ec869b719d7ad92ca8fb..c32e3e3af8138d41e87b58c9f038376c849249d7 100644 (file)
@@ -8,7 +8,7 @@
 # rpms again and again on the same day, so the newer rpms can be installed.
 # bumping the number each time.
 
-####################### FreeRangeRouting (FRR) configure options #########################
+####################### FRRouting (FRR) configure options #########################
 # with-feature options
 %{!?with_tcp_zebra:            %global with_tcp_zebra          0 }
 %{!?with_pam:                  %global with_pam                0 }
@@ -73,7 +73,7 @@
 %{!?frr_gid:           %global         frr_gid      92 }
 %{!?vty_gid:           %global         vty_gid         85 }
 
-%define                daemon_list     zebra ripd ospfd bgpd isisd pimd ripngd ospfd6d
+%define                daemon_list     zebra ripd ospfd bgpd isisd pimd ripngd ospf6d
 
 %if %{with_ldpd}
 %define         daemon_ldpd    ldpd
@@ -107,8 +107,8 @@ Version:            %{rpmversion}
 Release:               @CONFDATE@%{release_rev}%{?dist}
 License:               GPLv2+
 Group:                 System Environment/Daemons
-Source0:               http://www.freerangerouting.org/releases/frr/%{name}-%{frrversion}.tar.gz
-URL:                   http://www.freerangerouting.org
+Source0:               http://www.frrouting.org/releases/frr/%{name}-%{frrversion}.tar.gz
+URL:                   http://www.frrouting.org
 Requires:              ncurses json-c
 Requires(pre): /sbin/install-info
 Requires(preun): /sbin/install-info
@@ -135,14 +135,14 @@ BuildRoot:                        %{_tmppath}/%{name}-%{version}-root
 Obsoletes:                     bird gated mrt zebra frr-sysvinit
 
 %description
-FreeRangeRouting is a free software that manages TCP/IP based routing
+FRRouting is a free software that manages TCP/IP based routing
 protocol. It takes multi-server and multi-thread approach to resolve
 the current complexity of the Internet.
 
-FreeRangeRouting supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM,
-LDP and NHRP.
+FRRouting supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM, LDP
+and NHRP.
 
-FreeRangeRouting is a fork of Quagga.
+FRRouting is a fork of Quagga.
 
 %package contrib
 Summary: contrib tools for frr
@@ -315,7 +315,7 @@ if getent group %frr_user >/dev/null; then : ; else \
 fi
 if getent passwd %frr_user >/dev/null ; then : ; else \
  /usr/sbin/useradd  -u %frr_uid -g %frr_gid \
-  -M -r -s /sbin/nologin -c "FreeRangeRouting suite" \
+  -M -r -s /sbin/nologin -c "FRRouting suite" \
   -d %_localstatedir %frr_user 2> /dev/null || : ; \
 fi
 %if 0%{?vty_group:1}
@@ -594,8 +594,8 @@ rm -rf %{buildroot}
 * Tue Feb 14 2017 Timo Teräs <timo.teras@iki.fi> - %{version}
 - add nhrpd
 
-* Fri Jan  6 2017 Martin Winter <mwinter@opensourcerouting.org>
-- Renamed to frr for FreeRangeRouting fork of Quagga
+* Fri Jan  6 2017 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+- Renamed to frr for FRRouting fork of Quagga
 
 * Thu Feb 11 2016 Paul Jakma <paul@jakma.org> 
 - remove with_ipv6 conditionals, always build v6
index 7967ff1535767e3d9ca6a3862f58fa19558785b9..9c034f0c381f72758dfb67a18c6863d67af3d886 100644 (file)
@@ -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,14 @@ 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_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ripd_snmp_la_LIBADD = ../lib/libfrrsnmp.la
+
 examplesdir = $(exampledir)
 dist_examples_DATA = ripd.conf.sample
 
index 4c750faf4c7526bf00f6492ffd8fb07e131cf87b..a4ee2ba57053ed2acd966850ecd022003be83c89 100644 (file)
@@ -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);
index 6fd647596cf1fe6052bd9874b5a858dd287e96dd..baba9592e04578270e1f3dce80288fd3ee8ab469 100644 (file)
@@ -31,6 +31,7 @@
 #include "log.h"
 #include "sockunion.h"         /* for inet_aton () */
 #include "plist.h"
+#include "vrf.h"
 
 #include "ripd/ripd.h"
 
@@ -136,7 +137,7 @@ route_match_interface (void *rule, struct prefix *prefix,
   if (type == RMAP_RIP)
     {
       ifname = rule;
-      ifp = if_lookup_by_name(ifname);
+      ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
 
       if (!ifp)
        return RMAP_NOMATCH;
index c28b9379ccb864d5584a8c36271f7c70d6cda105..06cd3cef6c6af0c625bfa7d4def82dd39e515cfa 100644 (file)
 
 #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 *
@@ -255,7 +261,7 @@ rip2IfLookup (struct variable *v, oid name[], size_t *length,
 
       oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
 
-      return if_lookup_exact_address ((void *)addr, AF_INET);
+      return if_lookup_exact_address ((void *)addr, AF_INET, VRF_DEFAULT);
     }
   else
     {
@@ -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,
+)
index e0f96f9aaf3eca22d6c90240b0e453b9878747db..b668b0a0b41b942e91c6edaf76fd01c63a98d26f 100644 (file)
@@ -1129,7 +1129,7 @@ rip_response_process (struct rip_packet *packet, int size,
   /* The datagram's IPv4 source address should be checked to see
      whether the datagram is from a valid neighbor; the source of the
      datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
-  if (if_lookup_address((void *)&from->sin_addr, AF_INET) == NULL)
+  if (if_lookup_address((void *)&from->sin_addr, AF_INET, VRF_DEFAULT) == NULL)
     {
       zlog_info ("This datagram doesn't came from a valid neighbor: %s",
                 inet_ntoa (from->sin_addr));
@@ -1215,7 +1215,7 @@ rip_response_process (struct rip_packet *packet, int size,
              continue;
            }
 
-         if (! if_lookup_address ((void *)&rte->nexthop, AF_INET))
+         if (! if_lookup_address ((void *)&rte->nexthop, AF_INET, VRF_DEFAULT))
            {
              struct route_node *rn;
              struct rip_info *rinfo;
@@ -1552,12 +1552,12 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
   if (IS_RIP_DEBUG_EVENT) {
     if (!nexthop)
       zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
-                 inet_ntoa(p->prefix), p->prefixlen,
-                 ifindex2ifname(ifindex));
+                  inet_ntoa(p->prefix), p->prefixlen,
+                  ifindex2ifname(ifindex, VRF_DEFAULT));
     else
       zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
-                 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
-                 ifindex2ifname(ifindex));
+                  inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
+                  ifindex2ifname(ifindex, VRF_DEFAULT));
   }
 
   rip_event (RIP_TRIGGERED_UPDATE, 0);
@@ -1600,7 +1600,7 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
                 zlog_debug ("Poisone %s/%d on the interface %s with an "
                             "infinity metric [delete]",
                             inet_ntoa(p->prefix), p->prefixlen,
-                            ifindex2ifname(ifindex));
+                            ifindex2ifname(ifindex, VRF_DEFAULT));
 
               rip_event (RIP_TRIGGERED_UPDATE, 0);
             }
@@ -1816,7 +1816,7 @@ rip_read (struct thread *t)
     }
 
   /* Which interface is this packet comes from. */
-  ifc = if_lookup_address ((void *)&from.sin_addr, AF_INET);
+  ifc = if_lookup_address ((void *)&from.sin_addr, AF_INET, VRF_DEFAULT);
   if (ifc)
     ifp = ifc->ifp;
 
@@ -2517,7 +2517,7 @@ rip_update_process (int route_type)
       {
        p = &rp->p;
 
-       connected = if_lookup_address (&p->u.prefix4, AF_INET);
+       connected = if_lookup_address (&p->u.prefix4, AF_INET, VRF_DEFAULT);
        if (! connected)
          {
            zlog_warn ("Neighbor %s doesnt have connected interface!",
@@ -2660,8 +2660,8 @@ rip_redistribute_withdraw (int type)
               struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
 
               zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
-                         inet_ntoa(p->prefix), p->prefixlen,
-                         ifindex2ifname(rinfo->ifindex));
+                          inet_ntoa(p->prefix), p->prefixlen,
+                          ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
            }
 
            rip_event (RIP_TRIGGERED_UPDATE, 0);
@@ -2802,7 +2802,7 @@ rip_event (enum rip_event event, int sock)
     }
 }
 
-DEFUN (router_rip,
+DEFUN_NOSH (router_rip,
        router_rip_cmd,
        "router rip",
        "Enable a routing process\n"
@@ -3763,7 +3763,7 @@ rip_distribute_update (struct distribute *dist)
   if (! dist->ifname)
     return;
 
-  ifp = if_lookup_by_name (dist->ifname);
+  ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
   if (ifp == NULL)
     return;
 
@@ -3962,7 +3962,7 @@ rip_if_rmap_update (struct if_rmap *if_rmap)
   struct rip_interface *ri;
   struct route_map *rmap;
 
-  ifp = if_lookup_by_name (if_rmap->ifname);
+  ifp = if_lookup_by_name (if_rmap->ifname, VRF_DEFAULT);
   if (ifp == NULL)
     return;
 
@@ -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);
index 68b3d1fc6ec6d6c07adc32f9f13940b3f814150b..eeb008e3d5c35432e6a671aecd4217c1dddea1cc 100644 (file)
@@ -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 */
index 7cab5861bfe4fc6a9d5d88aeb8c33bd1bedcc6ee..ad8dbc92f39329b061f2ac4ff7954e28e78a5493 100644 (file)
@@ -110,7 +110,7 @@ route_match_interface (void *rule, struct prefix *prefix,
   if (type == RMAP_RIPNG)
     {
       ifname = rule;
-      ifp = if_lookup_by_name(ifname);
+      ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
 
       if (!ifp)
        return RMAP_NOMATCH;
index 108da21c115964ba26c90ea89db824ec16d9ded5..a883bec3c43f491f9fa468b87c7e8e1405678e31 100644 (file)
@@ -979,12 +979,12 @@ ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
   if (IS_RIPNG_DEBUG_EVENT) {
     if (!nexthop)
       zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
-                 inet6_ntoa(p->prefix), p->prefixlen,
-                 ifindex2ifname(ifindex));
+                  inet6_ntoa(p->prefix), p->prefixlen,
+                  ifindex2ifname(ifindex, VRF_DEFAULT));
     else
       zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
-                 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
-                 ifindex2ifname(ifindex));
+                  inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
+                  ifindex2ifname(ifindex, VRF_DEFAULT));
   }
 
   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
@@ -1032,7 +1032,7 @@ ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
                 zlog_debug ("Poisone %s/%d on the interface %s with an "
                             "infinity metric [delete]",
                             inet6_ntoa (p->prefix), p->prefixlen,
-                            ifindex2ifname (ifindex));
+                            ifindex2ifname (ifindex, VRF_DEFAULT));
 
               ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
             }
@@ -1074,8 +1074,8 @@ ripng_redistribute_withdraw (int type)
              struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
 
              zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
-                        inet6_ntoa(p->prefix), p->prefixlen,
-                        ifindex2ifname(rinfo->ifindex));
+                          inet6_ntoa(p->prefix), p->prefixlen,
+                          ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
            }
 
            ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
@@ -1348,7 +1348,7 @@ ripng_read (struct thread *thread)
     }
 
   packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
-  ifp = if_lookup_by_index (ifindex);
+  ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
 
   /* RIPng packet received. */
   if (IS_RIPNG_DEBUG_EVENT)
@@ -2066,7 +2066,7 @@ DEFUN (show_ipv6_ripng,
          if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 
            (rinfo->sub_type == RIPNG_ROUTE_RTE))
          {
-           len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
+           len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
          } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
          {
            len = vty_out (vty, "kill");
@@ -2215,7 +2215,7 @@ DEFUN (clear_ipv6_rip,
   return CMD_SUCCESS;
 }
 
-DEFUN (router_ripng,
+DEFUN_NOSH (router_ripng,
        router_ripng_cmd,
        "router ripng",
        "Enable a routing process\n"
@@ -2814,7 +2814,7 @@ ripng_distribute_update (struct distribute *dist)
   if (! dist->ifname)
     return;
 
-  ifp = if_lookup_by_name (dist->ifname);
+  ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
   if (ifp == NULL)
     return;
 
@@ -3009,7 +3009,7 @@ ripng_if_rmap_update (struct if_rmap *if_rmap)
   struct ripng_interface *ri;
   struct route_map *rmap;
 
-  ifp = if_lookup_by_name (if_rmap->ifname);
+  ifp = if_lookup_by_name (if_rmap->ifname, VRF_DEFAULT);
   if (ifp == NULL)
     return;
 
index 15813be72f2849da2df0876e6f29fda9f6bce8b5..75f768e942b896aa169746af592bfa901502dcfb 100644 (file)
@@ -1,11 +1,25 @@
 EXTRA_DIST = snapcraft.yaml \
-   scripts/Makefile scripts/zebra-service scripts/bgpd-service \
-   scripts/isisd-service scripts/ripd-service scripts/ripngd-service \
-   scripts/ospf6d-service scripts/ospfd-service \
-   scripts/isisd-service scripts/pimd-service \
-   scripts/ldpd-service \
-   defaults/bgpd.conf.default defaults/isisd.conf.default \
-   defaults/ospf6d.conf.default defaults/ospfd.conf.default \
-   defaults/pimd.conf.default defaults/zebra.conf.default \
-   defaults/ripd.conf.default defaults/ripngd.conf.default \
-   defaults/ldpd.conf.default defaults/vtysh.conf.default
+       README.snap_build.md \
+       README.usage.md \
+       scripts/Makefile \
+       scripts/bgpd-service \
+       scripts/isisd-service \
+       scripts/ldpd-service \
+       scripts/ospf6d-service \
+       scripts/ospfd-service \
+       scripts/pimd-service \
+       scripts/ripd-service \
+       scripts/ripngd-service \
+       scripts/zebra-service \
+       defaults/bgpd.conf.default \
+       defaults/isisd.conf.default \
+       defaults/ldpd.conf.default \
+       defaults/ospf6d.conf.default \
+       defaults/ospfd.conf.default \
+       defaults/pimd.conf.default \
+       defaults/ripd.conf.default \
+       defaults/ripngd.conf.default \
+       defaults/vtysh.conf.default \
+       defaults/zebra.conf.default \
+       helpers \
+       snap
index 341b210f71e2e044beffd6401e93fa7c99769c5b..c4db51bd6aa02a717fd54b2694b6c1d7a6ecd79b 100644 (file)
@@ -1,4 +1,4 @@
-Building your own FreeRangeRouting Snap
+Building your own FRRouting Snap
 ========================================
 (Tested on Ubuntu 16.04 with Snap Version 2, does not work on Ubuntu 15.x
 which uses earlier versions of snaps)
@@ -7,9 +7,9 @@ which uses earlier versions of snaps)
 
         sudo apt-get install snapcraft
        
-2. Checkout FreeRangeRouting under a **unpriviledged** user account
+2. Checkout FRRouting under a **unpriviledged** user account
 
-        git clone https://github.com/freerangerouting/frr.git
+        git clone https://github.com/frrouting/frr.git
         cd frr
 
 3. Run Bootstrap and make distribution tar.gz
@@ -56,8 +56,8 @@ The Snap will be auto-started and running.
 Operations
 ==========
 
-### FreeRangeRouting Daemons
-At this time, all FreeRangeRouting daemons are auto-started.
+### FRRouting Daemons
+At this time, all FRRouting daemons are auto-started.
 
 A daemon can be stopped/started with (ie ospf6d)
 
@@ -69,7 +69,7 @@ or disabled/enabled with
     systemctl disable snap.frr.ospf6d.service
     systemctl enable snap.frr.ospf6d.service
 
-### FreeRangeRouting Commands
+### FRRouting Commands
 All the commands are prefixed with frr.
 
     frr.vtysh       -> vtysh
index 2d2b32b6b7fb0ff112a01d92c089960936661c7b..aaff59438aec660eee5af0ad75c210c4a9ac9c47 100644 (file)
@@ -1,14 +1,14 @@
-Using the FreeRangeRouting Snap
+Using the FRRouting Snap
 ===============================
 
 After installing the Snap, the priviledged plug need to be connected:
 
     snap connect frr:network-control ubuntu-core:network-control
 
-Enabling/Disabling FreeRangeRouting Daemons
+Enabling/Disabling FRRouting Daemons
 -------------------------------------------
 
-By default (at this time), all FreeRangeRouting daemons will be enabled
+By default (at this time), all FRRouting daemons will be enabled
 on installation. If you want to disable a specific daemon, then use 
 the systemctl commands
 
@@ -24,7 +24,7 @@ Commands defined by this snap
 -----------------------------
 
 - `frr.vtysh`:
-       FreeRangeRouting VTY Shell (configuration tool)
+       FRRouting VTY Shell (configuration tool)
 - `frr.version`:
        Returns output of `zebra --version` to display version and configured 
        options
@@ -62,10 +62,10 @@ FAQ
 Sourcecode available
 ====================
 
-The source for this SNAP is available as part of the FreeRangeRouting
+The source for this SNAP is available as part of the FRRouting
 Source Code Distribution. 
 
-    https://github.com/freerangerouting/frr.git
+    https://github.com/frrouting/frr.git
 
 Instructions for rebuilding the snap are in `README.snap_build.md`
 
diff --git a/snapcraft/setup/gui/icon.png b/snapcraft/setup/gui/icon.png
deleted file mode 100644 (file)
index e8f68e6..0000000
Binary files a/snapcraft/setup/gui/icon.png and /dev/null differ
diff --git a/snapcraft/snap/gui/icon.png b/snapcraft/snap/gui/icon.png
new file mode 100644 (file)
index 0000000..3ab3f8f
Binary files /dev/null and b/snapcraft/snap/gui/icon.png differ
index a703766f0b92cebc2e8016975da8ae743485c977..a20a1d0392f297ec8524878e5f16532463104b5a 100644 (file)
@@ -1,11 +1,11 @@
 name: frr
 version: @VERSION@
-summary: FreeRangeRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP routing daemon
+summary: FRRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP routing daemon
 description: BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM routing daemon
- FreeRangeRouting (FRR) is free software which manages TCP/IP based routing 
+ FRRouting (FRR) is free software which manages TCP/IP based routing 
  protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, 
  RIPng, PIM and LDP as well as the IPv6 versions of these.
- FreeRangeRouting (frr) is a fork of Quagga.
+ FRRouting (frr) is a fork of Quagga.
 confinement: strict
 grade: devel
 
index 01f725b8fadc954545522c5587ca685579dd111c..589570d881ca7b60a5ef979eb166cad7912fa76d 100644 (file)
@@ -15,13 +15,13 @@ Requirements:
   
   i.manifest must be at least version 1.5. Place these scripts in
   this directory if you are using Solaris 10 GA (which does not ship with
-  these scripts), or in the solaris/ directory in the FreeRangeRouting source.
+  these scripts), or in the solaris/ directory in the FRRouting source.
 
 
 Package creation instructions:
 ------------------------------
 
-1. Configure and build FreeRangeRouting (frr) in the top level build directory as per normal, eg:
+1. Configure and build FRRouting (frr) in the top level build directory as per normal, eg:
 
        ./configure --prefix=/usr/local/frr \
                --localstatedir=/var/run/frr \
@@ -102,7 +102,7 @@ Install and post-install configuration notes:
     
     # # svcs -l ripd
     fmri         svc:/network/routing/frr:ripd
-    name         FreeRangeRouting: ripd, RIPv1/2 IPv4 routing protocol daemon.
+    name         FRRouting: ripd, RIPv1/2 IPv4 routing protocol daemon.
     enabled      true
     state        online
     next_state   none
@@ -117,7 +117,7 @@ Install and post-install configuration notes:
 
   - Configuration of startup options is by way of SMF properties in a
     property group named 'frr'. The defaults should automatically be
-    inline with how you configured FreeRangeRouting in Step 1 above. 
+    inline with how you configured FRRouting in Step 1 above. 
   
   - By default the VTY interface is disabled. To change this, see below for
     how to set the 'frr/vty_port' property as appropriate for
@@ -176,11 +176,11 @@ Install and post-install configuration notes:
   - As SMF is dependency aware, restarting network/zebra will restart all the
     other daemons.
   
-  - To upgrade from one set of FreeRangeRouting packages to a newer release,
+  - To upgrade from one set of FRRouting packages to a newer release,
     one must first pkgrm the installed packages. When one pkgrm's FRRsmf all
     property configuration will be lost, and any customisations will have to
     redone after installing the updated FRRsmf package.
   
 - These packages are not supported by Sun Microsystems, report bugs via the
-  usual FreeRangeRouting channels, ie Issue Tracker. Improvements/contributions of course would be greatly appreciated.
+  usual FRRouting channels, ie Issue Tracker. Improvements/contributions of course would be greatly appreciated.
 
index 64fb03ac198cac3afc394483797b6886051faa0b..a8ce943e31d5c67ee9f8f1b585b80d1bf7be00be 100644 (file)
@@ -1,4 +1,4 @@
-P FRRlibs FreeRangeRouting common runtime libraries
+P FRRlibs FRRouting common runtime libraries
        @PACKAGE_VERSION@,REV=@CONFDATE@
 P SUNWcsu Core Solaris, (Usr)
 P SUNWcsr Core Solaris Libraries (Root)
index 5d8bf16ed6b3cc5400c3b3ca39b4a44199181a8a..1b65724a0454a9892955e10c90948d76f37acb0d 100644 (file)
@@ -1,2 +1,2 @@
-P FRRlibs FreeRangeRouting common runtime libraries
+P FRRlibs FRRouting common runtime libraries
        @PACKAGE_VERSION@,REV=@CONFDATE@
index 6ead0b2867edbde7f394bb169d4872916e06535a..04f04efd01999dd16609a4f68ca2fa8b3b69c6f9 100644 (file)
@@ -1,5 +1,5 @@
 P SUNWcslr  Core Solaris Libraries (Root)
 P SUNWcsl Core Solaris, (Shared Libs)
 P SUNWlibmsr Math & Microtasking Libraries (Root)
-R FRRdaemons FreeRangeRouting daemons
+R FRRdaemons FRRouting daemons
 R FRRdev
index 66b11eba2a578e05f7d6f68387d624525288743f..b3b1bd778c770489e67a2a0eb91464b179b7b96d 100644 (file)
@@ -1,4 +1,4 @@
-P FRRaemons FreeRangeRouting daemons
+P FRRaemons FRRouting daemons
        @PACKAGE_VERSION@,REV=@CONFDATE@
 P SUNWcsu Core Solaris, (Usr)
 P SUNWcsr Core Solaris Libraries (Root)
index 580fd9b35cd5b9b65af41573a5da5cf23e3786f8..bd9ab85e6918e462638301c8021515a17cd51614 100755 (executable)
@@ -3,20 +3,20 @@
 # Copyright 2007 Sun Microsystems, Inc. All rights reserved.
 # Use is subject to license terms.
 #
-# This file is part of FreeRangeRouting.
+# This file is part of FRRouting.
 #
-# FreeRangeRouting is free software; you can redistribute it and/or modify 
+# FRRouting 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.
 #
-# FreeRangeRouting is distributed in the hope that it will be useful, but
+# FRRouting 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 FreeRangeRouting; see the file COPYING.  If not, write to 
+# along with FRRouting; see the file COPYING.  If not, write to 
 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 # Boston, MA 02111-1307, USA.
 #
@@ -74,7 +74,7 @@ handle_routeadm_upgrade () {
 
 upgrade_config () {
        DAEMON=$1
-       # handle upgrade of SUNWzebra to FreeRangeRouting
+       # handle upgrade of SUNWzebra to FRRouting
        if [ -d "/etc/frr" -a ! -f "/etc/frr/${DAEMON}.conf" ] ; then
                if [ -f "/etc/sfw/zebra/${DAEMON}.conf" ] ; then
                        cp "/etc/sfw/zebra/${DAEMON}.conf" \
@@ -216,7 +216,7 @@ case "${DAEMON}" in
        ;;
 esac
 
-# Older FreeRangeRouting SMF packages pass daemon args on the commandline
+# Older FRRouting SMF packages pass daemon args on the commandline
 # Newer SMF routeadm model uses properties for each argument
 # so we must handle that.
 if [ smf_present -a -f "$ROUTEADMINCLUDE" ]; then
index 5ac7e527211ecb717a7ae7fef66c45e44d72a0f3..08a9a11c0f8bc60849a2bb37127e5decf5368d14 100644 (file)
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
-       This file is part of FreeRangeRouting (FRR)
+       This file is part of FRRouting (FRR)
 
-       FreeRangeRouting is free software; you can redistribute it and/or 
+       FRRouting 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) anylater version.
 
-       FreeRangeRouting is distributed in the hope that it will be useful, 
+       FRRouting 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 FreeRangeRouting; see the file COPYING.  If not, write to 
+       along with FRRouting; see the file COPYING.  If not, write to 
        the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
        Boston, MA 02111-1307, USA.
 
                <propval name='value_authorization' type='astring' 
                         value='solaris.smf.value.routing' />
                
-               <!-- Options common to FreeRangeRouting daemons
+               <!-- Options common to FRRouting daemons
                     Property names are equivalent to the long
-                    option name, consult FreeRangeRouting documentation -->
+                    option name, consult FRRouting documentation -->
                <!-- The config file to use, if not the default -->
                <propval name='config_file' type='astring' value=''/>
                <!-- The vty_port to listen on if not the default.
        <template>
                <common_name>
                        <loctext xml:lang='C'>
-                       FreeRangeRouting: zebra, RIB, kernel intermediary and misc daemon
+                       FRRouting: zebra, RIB, kernel intermediary and misc daemon
                        </loctext>
                </common_name>
                <documentation>
                        <manpage title='zebra' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
                <propval name='value_authorization' type='astring' 
                         value='solaris.smf.value.routing' />
 
-               <!-- Options common to FreeRangeRouting daemons -->
+               <!-- Options common to FRRouting daemons -->
                <!-- The config file to use, if not the default -->
                <propval name='config_file' type='astring' value=''/>
                <!-- The vty_port to listen on if not the default.
        <template>
                <common_name>
                        <loctext xml:lang='C'>
-                       FreeRangeRouting: ripd, RIPv1/2 IPv4 routing protocol daemon.
+                       FRRouting: ripd, RIPv1/2 IPv4 routing protocol daemon.
                        </loctext>
                </common_name>
                <documentation>
                        <manpage title='ripd' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
                <documentation>
                        <manpage title='ripngd' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
                <documentation>
                        <manpage title='ospfd' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
                <documentation>
                        <manpage title='ospf6d' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
                <documentation>
                        <manpage title='bgpd' section='1M'
                                manpath='@mandir@' />
-                       <doc_link name='freerangerouting.org' 
-                               uri='http://www.freerangerouting.org/' />
+                       <doc_link name='frrouting.org' 
+                               uri='http://www.frrouting.org/' />
                </documentation>
        </template>
        </instance>
index 02abb0f96bf16b04f37d8403cf5936b03cf822d5..89a281ceb6824cc33c637792d8aaa72877e108fd 100644 (file)
@@ -1,9 +1,9 @@
 ARCH="@target_cpu@"
 CATEGORY="system"
 VERSION="@PACKAGE_VERSION@,REV=@CONFDATE@"
-VENDOR="http://www.freerangerouting.org/"
+VENDOR="http://www.frrouting.org/"
 HOTLINE="@PACKAGE_BUGREPORT@"
-EMAIL=maintainers@freerangerouting.org
+EMAIL=maintainers@frrouting.org
 DESC="@PACKAGE_NAME@ Routing Protocols"
 MAXINST=1
 CLASSES="none preserve renamenew manifest"
index 20c854f66c26040088253782851f50dcbc1d334f..a7ef1c56b7d2d8c30ba70d62877fd755eae1bad6 100644 (file)
@@ -4,7 +4,7 @@
 # Copyright (C) 2017 by David Lamparter & Christian Franke,
 #                       Open Source Routing / NetDEF Inc.
 #
-# This file is part of FreeRangeRouting (FRR)
+# This file is part of FRRouting (FRR)
 #
 # FRR is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by the
@@ -27,6 +27,7 @@ import sys
 import re
 import inspect
 import os
+import difflib
 
 import frrsix
 
@@ -154,7 +155,18 @@ class TestMultiOut(_TestMultiOut):
 #
 
 class TestRefMismatch(Exception):
-    pass
+    def __init__(self, _test, outtext, reftext):
+        self.outtext = outtext.decode('utf8') if type(outtext) is bytes else outtext
+        self.reftext = reftext.decode('utf8') if type(reftext) is bytes else reftext
+
+    def __str__(self):
+        rv = 'Expected output and actual output differ:\n'
+        rv += '\n'.join(difflib.unified_diff(self.reftext.splitlines(),
+                                             self.outtext.splitlines(),
+                                             'outtext', 'reftext',
+                                             lineterm=''))
+        return rv
+
 class TestExitNonzero(Exception):
     pass
 
diff --git a/tests/lib/cli/.gitignore b/tests/lib/cli/.gitignore
new file mode 100644 (file)
index 0000000..682e95f
--- /dev/null
@@ -0,0 +1 @@
+/test_cli.refout
diff --git a/tests/lib/cli/test_cli.refout b/tests/lib/cli/test_cli.refout
deleted file mode 100644 (file)
index 8b438ba..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-test# echo this is a  test message\r
-this is a test message\r
-test# echo  foo bla  \r
-% There is no matched command.\r
-test# echo  foo bla    baz\r
-foo bla baz\r
-test# echo\r
-% Command incomplete.\r
-test# \r
-test# arg ipv4 1.2.3.4\r
-cmd0 with 3 args.\r
-[00]: arg\r
-[01]: ipv4\r
-[02]: 1.2.3.4\r
-test# arg ipv4 1.2.\r
-  A.B.C.D  02\r
-test# arg ipv4 1.2.3.4\r
-cmd0 with 3 args.\r
-[00]: arg\r
-[01]: ipv4\r
-[02]: 1.2.3.4\r
-test# arg ipv4 1.2.3\r
-% [NONE] Unknown command: arg ipv4 1.2.3\r
-test# arg ipv4 1.2.3.4.5\r
-% [NONE] Unknown command: arg ipv4 1.2.3.4.5\r
-test# arg ipv4 1.a.3.4\r
-% [NONE] Unknown command: arg ipv4 1.a.3.4\r
-test# arg ipv4 blah\r
-% [NONE] Unknown command: arg ipv4 blah\r
-test# \r
-test# arg ipv4m 1.2.3.0/24\r
-cmd1 with 3 args.\r
-[00]: arg\r
-[01]: ipv4m\r
-[02]: 1.2.3.0/24\r
-test# arg ipv4m 1.2.\r
-  A.B.C.D/M  02\r
-test# arg ipv4m 1.2.3.0/24\r
-cmd1 with 3 args.\r
-[00]: arg\r
-[01]: ipv4m\r
-[02]: 1.2.3.0/24\r
-test# arg ipv4m 1.2.3/9\r
-% [NONE] Unknown command: arg ipv4m 1.2.3/9\r
-test# arg ipv4m 1.2.3.4.5/6\r
-% [NONE] Unknown command: arg ipv4m 1.2.3.4.5/6\r
-test# arg ipv4m 1.a.3.4\r
-% [NONE] Unknown command: arg ipv4m 1.a.3.4\r
-test# arg ipv4m blah\r
-% [NONE] Unknown command: arg ipv4m blah\r
-test# arg ipv4m 1.2.3.0/999\r
-% [NONE] Unknown command: arg ipv4m 1.2.3.0/999\r
-test# arg ipv4m 1.2.3.0/a9\r
-% [NONE] Unknown command: arg ipv4m 1.2.3.0/a9\r
-test# arg ipv4m 1.2.3.0/9a\r
-% [NONE] Unknown command: arg ipv4m 1.2.3.0/9a\r
-test# \r
-test# arg ipv6 de4d:b33f::cafe\r
-cmd2 with 3 args.\r
-[00]: arg\r
-[01]: ipv6\r
-[02]: de4d:b33f::cafe\r
-test# arg ipv6 de4d:b3\r
-% There is no matched command.\r
-test# arg ipv6 de4d:b33f::caf\r
-  X:X::X:X  02\r
-test# arg ipv6 de4d:b33f::cafe\r
-cmd2 with 3 args.\r
-[00]: arg\r
-[01]: ipv6\r
-[02]: de4d:b33f::cafe\r
-test# arg ipv6 de4d:b3\r
-test# arg ipv6 de4d:b33f::caf\r
-  X:X::X:X  02\r
-test# arg ipv6 de4d:b33f::cafe\r
-cmd2 with 3 args.\r
-[00]: arg\r
-[01]: ipv6\r
-[02]: de4d:b33f::cafe\r
-test# arg ipv6 de4d:b33f:z::cafe\r
-% [NONE] Unknown command: arg ipv6 de4d:b33f:z::cafe\r
-test# arg ipv6 de4d:b33f:cafe:\r
-% [NONE] Unknown command: arg ipv6 de4d:b33f:cafe:\r
-test# arg ipv6 ::\r
-cmd2 with 3 args.\r
-[00]: arg\r
-[01]: ipv6\r
-[02]: ::\r
-test# arg ipv6 ::/\r
-% [NONE] Unknown command: arg ipv6 ::/\r
-test# arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0\r
-% [NONE] Unknown command: arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0\r
-test# arg ipv6 12::34::56\r
-% [NONE] Unknown command: arg ipv6 12::34::56\r
-test# arg ipv6m dead:beef:cafe::/64\r
-cmd3 with 3 args.\r
-[00]: arg\r
-[01]: ipv6m\r
-[02]: dead:beef:cafe::/64\r
-test# arg ipv6m dead:be\r
-  X:X::X:X/M  02\r
-test# arg ipv6m dead:beef:cafe:\r
-  X:X::X:X/M  02\r
-test# arg ipv6m dead:beef:cafe::/64\r
-cmd3 with 3 args.\r
-[00]: arg\r
-[01]: ipv6m\r
-[02]: dead:beef:cafe::/64\r
-test# \r
-test# arg range 4\r
-% [NONE] Unknown command: arg range 4\r
-test# arg range 5\r
-cmd4 with 3 args.\r
-[00]: arg\r
-[01]: range\r
-[02]: 5\r
-test# arg range 9\r
-  (5-15)  02\r
-test# arg range 9\r
-cmd4 with 3 args.\r
-[00]: arg\r
-[01]: range\r
-[02]: 9\r
-test# arg range 15\r
-cmd4 with 3 args.\r
-[00]: arg\r
-[01]: range\r
-[02]: 15\r
-test# arg range 16\r
-% [NONE] Unknown command: arg range 16\r
-test# arg range -1\r
-% [NONE] Unknown command: arg range -1\r
-test# arg range 99999999999999999999999999999999999999999\r
-% [NONE] Unknown command: arg range 99999999999999999999999999999999999999999\r
-test# \r
-test# arg \r
-  ipv4   01\r
-  ipv4m  01\r
-  ipv6   01\r
-  ipv6m  01\r
-  range  01\r
-test# arg \r
-% Command incomplete.\r
-test# \r
-test# pa\r
-test# pa\b\bpat \r
-% Command incomplete.\r
-test# pat \r
-a          c          d          e          f          \r
-test# pat \r
-% Command incomplete.\r
-test# \r
-test# pat a\r
-% Command incomplete.\r
-test# pat a a\r
-cmd5 with 3 args.\r
-[00]: pat\r
-[01]: a\r
-[02]: a\r
-test# pat a \r
-  a  02\r
-  b  03\r
-test# pat a b\r
-cmd5 with 3 args.\r
-[00]: pat\r
-[01]: a\r
-[02]: b\r
-test# pat a c\r
-% There is no matched command.\r
-test# pat a c\r
-% [NONE] Unknown command: pat a c\r
-test# pat a a x\r
-% [NONE] Unknown command: pat a a x\r
-test# \r
-test# pat c a\r
-% Command incomplete.\r
-test# pat c a 1.2.3.4\r
-cmd7 with 4 args.\r
-[00]: pat\r
-[01]: c\r
-[02]: a\r
-[03]: 1.2.3.4\r
-test# pat c b 2.3.4\r
-% [NONE] Unknown command: pat c b 2.3.4\r
-test# pat c c \r
-  A.B.C.D  05\r
-test# pat c c x\r
-% [NONE] Unknown command: pat c c x\r
-test# \r
-test# pat d\r
-% Command incomplete.\r
-test# pat d \r
-bar        baz        foo        \r
-test# pat d \r
-% Command incomplete.\r
-test# pat d foo 1.2.3.4\r
-cmd8 with 4 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: foo\r
-[03]: 1.2.3.4\r
-test# pat d foo\r
-% Command incomplete.\r
-test# pat d noooo\r
-% [NONE] Unknown command: pat d noooo\r
-test# pat d bar 1::2\r
-cmd8 with 4 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: bar\r
-[03]: 1::2\r
-test# pat d bar 1::2 foo 3.4.5.6\r
-cmd8 with 6 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: bar\r
-[03]: 1::2\r
-[04]: foo\r
-[05]: 3.4.5.6\r
-test# pat d ba\r
-  bar  04\r
-  baz  06\r
-test# pat d baz\r
-cmd8 with 3 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: baz\r
-test# pat d foo 3.4.5.6 baz\r
-cmd8 with 5 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: foo\r
-[03]: 3.4.5.6\r
-[04]: baz\r
-test# \r
-test# pat e\r
-cmd9 with 2 args.\r
-[00]: pat\r
-[01]: e\r
-test# pat e f\r
-cmd9 with 3 args.\r
-[00]: pat\r
-[01]: e\r
-[02]: f\r
-test# pat e f g\r
-% [NONE] Unknown command: pat e f g\r
-test# pat e 1.2.3.4\r
-cmd9 with 3 args.\r
-[00]: pat\r
-[01]: e\r
-[02]: 1.2.3.4\r
-test# \r
-test# pat f\r
-cmd10 with 2 args.\r
-[00]: pat\r
-[01]: f\r
-test# pat f foo\r
-% [NONE] Unknown command: pat f foo\r
-test# pat f key\r
-cmd10 with 3 args.\r
-[00]: pat\r
-[01]: f\r
-[02]: key\r
-test# \r
-test# alt a \r
-test# alt a a\r
-  WORD  02\r
-test# alt a ab\r
-cmd11 with 3 args.\r
-[00]: alt\r
-[01]: a\r
-[02]: ab\r
-test# alt a 1\r
-test# alt a 1.2\r
-  A.B.C.D  02\r
-  WORD     02\r
-test# alt a 1.2.3.4\r
-cmd12 with 3 args.\r
-[00]: alt\r
-[01]: a\r
-[02]: 1.2.3.4\r
-test# alt a 1\r
-test# alt a 1:2\r
-  WORD  02\r
-test# alt a 1:2\r
-test# alt a 1:2::\r
-  WORD      02\r
-  X:X::X:X  02\r
-test# alt a 1:2::3\r
-cmd13 with 3 args.\r
-[00]: alt\r
-[01]: a\r
-[02]: 1:2::3\r
-test# \r
-test# conf t\r
-test(config)# do pat d baz\r
-cmd8 with 3 args.\r
-[00]: pat\r
-[01]: d\r
-[02]: baz\r
-test(config)# exit\r
-test# \r
-test# show run\r
-\r
-Current configuration:\r
-!\r
-hostname test\r
-!\r
-!\r
-line vty\r
-!\r
-end\r
-test# conf t\r
-test(config)# hostname foohost\r
-foohost(config)# do show run\r
-\r
-Current configuration:\r
-!\r
-hostname foohost\r
-!\r
-!\r
-line vty\r
-!\r
-end\r
-foohost(config)# 
-end.
diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in
new file mode 100644 (file)
index 0000000..18822c1
--- /dev/null
@@ -0,0 +1,332 @@
+test# echo this is a  test message\r
+this is a test message\r
+test# echo  foo bla  \r
+% There is no matched command.\r
+test# echo  foo bla    baz\r
+foo bla baz\r
+test# echo\r
+% Command incomplete.\r
+test# \r
+test# arg ipv4 1.2.3.4\r
+cmd0 with 3 args.\r
+[00]: arg\r
+[01]: ipv4\r
+[02]: 1.2.3.4\r
+test# arg ipv4 1.2.\r
+  A.B.C.D  02\r
+test# arg ipv4 1.2.3.4\r
+cmd0 with 3 args.\r
+[00]: arg\r
+[01]: ipv4\r
+[02]: 1.2.3.4\r
+test# arg ipv4 1.2.3\r
+% [NONE] Unknown command: arg ipv4 1.2.3\r
+test# arg ipv4 1.2.3.4.5\r
+% [NONE] Unknown command: arg ipv4 1.2.3.4.5\r
+test# arg ipv4 1.a.3.4\r
+% [NONE] Unknown command: arg ipv4 1.a.3.4\r
+test# arg ipv4 blah\r
+% [NONE] Unknown command: arg ipv4 blah\r
+test# \r
+test# arg ipv4m 1.2.3.0/24\r
+cmd1 with 3 args.\r
+[00]: arg\r
+[01]: ipv4m\r
+[02]: 1.2.3.0/24\r
+test# arg ipv4m 1.2.\r
+  A.B.C.D/M  02\r
+test# arg ipv4m 1.2.3.0/24\r
+cmd1 with 3 args.\r
+[00]: arg\r
+[01]: ipv4m\r
+[02]: 1.2.3.0/24\r
+test# arg ipv4m 1.2.3/9\r
+% [NONE] Unknown command: arg ipv4m 1.2.3/9\r
+test# arg ipv4m 1.2.3.4.5/6\r
+% [NONE] Unknown command: arg ipv4m 1.2.3.4.5/6\r
+test# arg ipv4m 1.a.3.4\r
+% [NONE] Unknown command: arg ipv4m 1.a.3.4\r
+test# arg ipv4m blah\r
+% [NONE] Unknown command: arg ipv4m blah\r
+test# arg ipv4m 1.2.3.0/999\r
+% [NONE] Unknown command: arg ipv4m 1.2.3.0/999\r
+test# arg ipv4m 1.2.3.0/a9\r
+% [NONE] Unknown command: arg ipv4m 1.2.3.0/a9\r
+test# arg ipv4m 1.2.3.0/9a\r
+% [NONE] Unknown command: arg ipv4m 1.2.3.0/9a\r
+test# \r
+test# arg ipv6 de4d:b33f::cafe\r
+cmd2 with 3 args.\r
+[00]: arg\r
+[01]: ipv6\r
+[02]: de4d:b33f::cafe\r
+test# arg ipv6 de4d:b3\r
+% There is no matched command.\r
+test# arg ipv6 de4d:b33f::caf\r
+  X:X::X:X  02\r
+test# arg ipv6 de4d:b33f::cafe\r
+cmd2 with 3 args.\r
+[00]: arg\r
+[01]: ipv6\r
+[02]: de4d:b33f::cafe\r
+test# arg ipv6 de4d:b3\r
+test# arg ipv6 de4d:b33f::caf\r
+  X:X::X:X  02\r
+test# arg ipv6 de4d:b33f::cafe\r
+cmd2 with 3 args.\r
+[00]: arg\r
+[01]: ipv6\r
+[02]: de4d:b33f::cafe\r
+test# arg ipv6 de4d:b33f:z::cafe\r
+% [NONE] Unknown command: arg ipv6 de4d:b33f:z::cafe\r
+test# arg ipv6 de4d:b33f:cafe:\r
+% [NONE] Unknown command: arg ipv6 de4d:b33f:cafe:\r
+test# arg ipv6 ::\r
+cmd2 with 3 args.\r
+[00]: arg\r
+[01]: ipv6\r
+[02]: ::\r
+test# arg ipv6 ::/\r
+% [NONE] Unknown command: arg ipv6 ::/\r
+test# arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0\r
+% [NONE] Unknown command: arg ipv6 1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0:1:2:3:4:5:6:7:8:9:0\r
+test# arg ipv6 12::34::56\r
+% [NONE] Unknown command: arg ipv6 12::34::56\r
+test# arg ipv6m dead:beef:cafe::/64\r
+cmd3 with 3 args.\r
+[00]: arg\r
+[01]: ipv6m\r
+[02]: dead:beef:cafe::/64\r
+test# arg ipv6m dead:be\r
+  X:X::X:X/M  02\r
+test# arg ipv6m dead:beef:cafe:\r
+  X:X::X:X/M  02\r
+test# arg ipv6m dead:beef:cafe::/64\r
+cmd3 with 3 args.\r
+[00]: arg\r
+[01]: ipv6m\r
+[02]: dead:beef:cafe::/64\r
+test# \r
+test# arg range 4\r
+% [NONE] Unknown command: arg range 4\r
+test# arg range 5\r
+cmd4 with 3 args.\r
+[00]: arg\r
+[01]: range\r
+[02]: 5\r
+test# arg range 9\r
+  (5-15)  02\r
+test# arg range 9\r
+cmd4 with 3 args.\r
+[00]: arg\r
+[01]: range\r
+[02]: 9\r
+test# arg range 15\r
+cmd4 with 3 args.\r
+[00]: arg\r
+[01]: range\r
+[02]: 15\r
+test# arg range 16\r
+% [NONE] Unknown command: arg range 16\r
+test# arg range -1\r
+% [NONE] Unknown command: arg range -1\r
+test# arg range 99999999999999999999999999999999999999999\r
+% [NONE] Unknown command: arg range 99999999999999999999999999999999999999999\r
+test# \r
+test# arg \r
+  ipv4   01\r
+  ipv4m  01\r
+  ipv6   01\r
+  ipv6m  01\r
+  range  01\r
+test# arg \r
+% Command incomplete.\r
+test# \r
+test# pa\r
+test# pa\b\bpat \r
+% Command incomplete.\r
+test# pat \r
+a          c          d          e          f          \r
+test# pat \r
+% Command incomplete.\r
+test# \r
+test# pat a\r
+% Command incomplete.\r
+test# pat a a\r
+cmd5 with 3 args.\r
+[00]: pat\r
+[01]: a\r
+[02]: a\r
+test# pat a \r
+  a  02\r
+  b  03\r
+test# pat a b\r
+cmd5 with 3 args.\r
+[00]: pat\r
+[01]: a\r
+[02]: b\r
+test# pat a c\r
+% There is no matched command.\r
+test# pat a c\r
+% [NONE] Unknown command: pat a c\r
+test# pat a a x\r
+% [NONE] Unknown command: pat a a x\r
+test# \r
+test# pat c a\r
+% Command incomplete.\r
+test# pat c a 1.2.3.4\r
+cmd7 with 4 args.\r
+[00]: pat\r
+[01]: c\r
+[02]: a\r
+[03]: 1.2.3.4\r
+test# pat c b 2.3.4\r
+% [NONE] Unknown command: pat c b 2.3.4\r
+test# pat c c \r
+  A.B.C.D  05\r
+test# pat c c x\r
+% [NONE] Unknown command: pat c c x\r
+test# \r
+test# pat d\r
+% Command incomplete.\r
+test# pat d \r
+bar        baz        foo        \r
+test# pat d \r
+% Command incomplete.\r
+test# pat d foo 1.2.3.4\r
+cmd8 with 4 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: foo\r
+[03]: 1.2.3.4\r
+test# pat d foo\r
+% Command incomplete.\r
+test# pat d noooo\r
+% [NONE] Unknown command: pat d noooo\r
+test# pat d bar 1::2\r
+cmd8 with 4 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: bar\r
+[03]: 1::2\r
+test# pat d bar 1::2 foo 3.4.5.6\r
+cmd8 with 6 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: bar\r
+[03]: 1::2\r
+[04]: foo\r
+[05]: 3.4.5.6\r
+test# pat d ba\r
+  bar  04\r
+  baz  06\r
+test# pat d baz\r
+cmd8 with 3 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: baz\r
+test# pat d foo 3.4.5.6 baz\r
+cmd8 with 5 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: foo\r
+[03]: 3.4.5.6\r
+[04]: baz\r
+test# \r
+test# pat e\r
+cmd9 with 2 args.\r
+[00]: pat\r
+[01]: e\r
+test# pat e f\r
+cmd9 with 3 args.\r
+[00]: pat\r
+[01]: e\r
+[02]: f\r
+test# pat e f g\r
+% [NONE] Unknown command: pat e f g\r
+test# pat e 1.2.3.4\r
+cmd9 with 3 args.\r
+[00]: pat\r
+[01]: e\r
+[02]: 1.2.3.4\r
+test# \r
+test# pat f\r
+cmd10 with 2 args.\r
+[00]: pat\r
+[01]: f\r
+test# pat f foo\r
+% [NONE] Unknown command: pat f foo\r
+test# pat f key\r
+cmd10 with 3 args.\r
+[00]: pat\r
+[01]: f\r
+[02]: key\r
+test# \r
+test# alt a \r
+test# alt a a\r
+  WORD  02\r
+test# alt a ab\r
+cmd11 with 3 args.\r
+[00]: alt\r
+[01]: a\r
+[02]: ab\r
+test# alt a 1\r
+test# alt a 1.2\r
+  A.B.C.D  02\r
+  WORD     02\r
+test# alt a 1.2.3.4\r
+cmd12 with 3 args.\r
+[00]: alt\r
+[01]: a\r
+[02]: 1.2.3.4\r
+test# alt a 1\r
+test# alt a 1:2\r
+  WORD  02\r
+test# alt a 1:2\r
+test# alt a 1:2::\r
+  WORD      02\r
+  X:X::X:X  02\r
+test# alt a 1:2::3\r
+cmd13 with 3 args.\r
+[00]: alt\r
+[01]: a\r
+[02]: 1:2::3\r
+test# \r
+test# conf t\r
+test(config)# do pat d baz\r
+cmd8 with 3 args.\r
+[00]: pat\r
+[01]: d\r
+[02]: baz\r
+test(config)# exit\r
+test# \r
+test# show run\r
+\r
+Current configuration:\r
+!\r
+frr version @PACKAGE_VERSION@\r
+frr defaults @DFLT_NAME@\r
+!\r
+hostname test\r
+!\r
+!\r
+line vty\r
+!\r
+end\r
+test# conf t\r
+test(config)# hostname foohost\r
+foohost(config)# do show run\r
+\r
+Current configuration:\r
+!\r
+frr version @PACKAGE_VERSION@\r
+frr defaults @DFLT_NAME@\r
+!\r
+hostname foohost\r
+!\r
+!\r
+line vty\r
+!\r
+end\r
+foohost(config)# 
+end.
diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c
new file mode 100644 (file)
index 0000000..4a4aaa0
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Label Manager Test
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ *                       Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "lib/stream.h"
+#include "lib/zclient.h"
+
+#define ZSERV_PATH "/tmp/zserv.api" // TODO!!
+#define KEEP 0 /* change to 1 to avoid garbage collection */
+#define CHUNK_SIZE 32
+
+struct zclient *zclient;
+u_short instance = 1;
+
+const char *sequence = "GGRGGGRRG";
+
+static int zebra_send_get_label_chunk (void);
+static int zebra_send_release_label_chunk (uint32_t start, uint32_t end);
+
+static void
+process_next_call (uint32_t start, uint32_t end)
+{
+               sleep (3);
+               if (!*sequence)
+                               exit (0);
+               if (*sequence == 'G')
+                               zebra_send_get_label_chunk ();
+               else if (*sequence == 'R')
+                               zebra_send_release_label_chunk (start, end);
+}
+
+/* Connect to Label Manager */
+
+static int
+zebra_send_label_manager_connect ()
+{
+               int ret;
+
+               printf("Connect to Label Manager\n");
+
+               ret = lm_label_manager_connect (zclient);
+               printf ("Label Manager connection result: %u \n", ret);
+               if (ret != 0 ) {
+                               fprintf (stderr, "Error %d connecting to Label Manager %s\n", ret,
+                                                strerror(errno));
+                               exit (1);
+               }
+
+               process_next_call (0, 0);
+}
+
+/* Get Label Chunk */
+
+static int
+zebra_send_get_label_chunk ()
+{
+               uint32_t start;
+               uint32_t end;
+               int ret;
+
+               printf("Ask for label chunk \n");
+
+               ret = lm_get_label_chunk (zclient, KEEP, CHUNK_SIZE, &start, &end);
+               if (ret != 0 ) {
+                               fprintf (stderr, "Error %d requesting label chunk %s\n", ret, strerror(errno));
+                               exit (1);
+               }
+
+               sequence++;
+
+               printf ("Label Chunk assign: %u - %u \n",
+                               start, end);
+
+               process_next_call (start, end);
+}
+
+/* Release Label Chunk */
+
+static int
+zebra_send_release_label_chunk (uint32_t start, uint32_t end)
+{
+               struct stream *s;
+               int ret;
+
+               printf("Release label chunk: %u - %u\n", start, end);
+
+               ret = lm_release_label_chunk (zclient, start, end);
+               if (ret != 0 ) {
+                               fprintf (stderr, "Error releasing label chunk\n");
+                               exit (1);
+               }
+
+               sequence++;
+
+               process_next_call (start-CHUNK_SIZE, end-CHUNK_SIZE);
+}
+
+
+void init_zclient (struct thread_master *master, char *lm_zserv_path)
+{
+               if (lm_zserv_path)
+                               zclient_serv_path_set(lm_zserv_path);
+
+               zclient = zclient_new(master);
+               /* zclient_init(zclient, ZEBRA_LABEL_MANAGER, 0); */
+               zclient->sock = -1;
+               zclient->redist_default = ZEBRA_ROUTE_LDP;
+               zclient->instance = instance;
+               if (zclient_socket_connect (zclient) < 0) {
+                               printf ("Error connecting synchronous zclient!\n");
+                               exit (1);
+               }
+
+}
+
+int main (int argc, char *argv[])
+{
+               struct thread_master *master;
+               struct thread            thread;
+               int ret;
+
+               printf ("Sequence to be tested: %s\n", sequence);
+
+               master = thread_master_create();
+               init_zclient (master, ZSERV_PATH);
+
+               zebra_send_label_manager_connect ();
+
+               return 0;
+}
index 4c2630009987e442469c549bd18a692e83903f4a..c91392da15cf0e0afa3a8c106937167a08850f82 100755 (executable)
@@ -988,6 +988,21 @@ if __name__ == '__main__':
         # the "neighbor 1.1.1.1 route-map FOO out" line...so we compare the
         # configs again to put this line back.
 
+        # There are many keywords in quagga that can only appear one time under
+        # a context, take "bgp router-id" for example. If the config that we are
+        # reloading against has the following:
+        #
+        # router bgp 10
+        #   bgp router-id 1.1.1.1
+        #   bgp router-id 2.2.2.2
+        #
+        # The final config needs to contain "bgp router-id 2.2.2.2". On the
+        # first pass we will add "bgp router-id 2.2.2.2" but then on the second
+        # pass we will see that "bgp router-id 1.1.1.1" is missing and add that
+        # back which cancels out the "bgp router-id 2.2.2.2". The fix is for the
+        # second pass to include all of the "adds" from the first pass.
+        lines_to_add_first_pass = []
+
         for x in range(2):
             running = Config()
             running.load_from_show_running()
@@ -995,6 +1010,11 @@ if __name__ == '__main__':
 
             (lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
 
+            if x == 0:
+                lines_to_add_first_pass = lines_to_add
+            else:
+                lines_to_add.extend(lines_to_add_first_pass)
+
             # Only do deletes on the first pass. The reason being if we
             # configure a bgp neighbor via "neighbor swp1 interface" quagga
             # will automatically add:
index c28b9cb71a801f709a32824dc11163b02cb9d3d1..44fbafc3373a08944bf6bd06ee22a5685857a48b 100644 (file)
@@ -44,27 +44,67 @@ vtysh_scan += $(top_srcdir)/pimd/pim_cmd.c
 endif
 
 if BGPD
-vtysh_scan += $(top_srcdir)/bgpd/*.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_bfd.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_debug.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_dump.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_encap.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_evpn_vty.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_filter.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_mplsvpn.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_route.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_routemap.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_vty.c
 endif
 
 if ISISD
-vtysh_scan += $(top_srcdir)/isisd/*.c
+vtysh_scan += $(top_srcdir)/isisd/isis_redist.c
+vtysh_scan += $(top_srcdir)/isisd/isis_spf.c
+vtysh_scan += $(top_srcdir)/isisd/isis_te.c
+vtysh_scan += $(top_srcdir)/isisd/isis_vty.c
+vtysh_scan += $(top_srcdir)/isisd/isisd.c
 endif
 
 if OSPFD
-vtysh_scan += $(top_srcdir)/ospfd/*.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_bfd.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_dump.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_opaque.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_ri.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_routemap.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_te.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_vty.c
 endif
 
 if OSPF6D
-vtysh_scan += $(top_srcdir)/ospf6d/*.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_abr.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_area.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_bfd.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_flood.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_interface.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_intra.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_lsa.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_message.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_neighbor.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_route.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_spf.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_top.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6_zebra.c
+vtysh_scan += $(top_srcdir)/ospf6d/ospf6d.c
 endif
 
 if RIPD
-vtysh_scan += $(top_srcdir)/ripd/*.c
+vtysh_scan += $(top_srcdir)/ripd/rip_debug.c
+vtysh_scan += $(top_srcdir)/ripd/rip_interface.c
+vtysh_scan += $(top_srcdir)/ripd/rip_offset.c
+vtysh_scan += $(top_srcdir)/ripd/rip_zebra.c
+vtysh_scan += $(top_srcdir)/ripd/ripd.c
 endif
 
 if RIPNGD
-vtysh_scan += $(top_srcdir)/ripngd/*.c
+vtysh_scan += $(top_srcdir)/ripngd/ripng_debug.c
+vtysh_scan += $(top_srcdir)/ripngd/ripng_interface.c
+vtysh_scan += $(top_srcdir)/ripngd/ripng_offset.c
+vtysh_scan += $(top_srcdir)/ripngd/ripng_zebra.c
+vtysh_scan += $(top_srcdir)/ripngd/ripngd.c
 endif
 
 if NHRPD
index 4dddb809a0d9f190c41f56e7ce9635d570ee965a..169220c772ad69a3cb5364163e44e6979bf8faf2 100755 (executable)
@@ -33,63 +33,6 @@ print <<EOF;
 
 EOF
 
-$ignore{'"interface IFNAME"'} = "ignore";
-$ignore{'"interface IFNAME " "vrf (0-65535)"'} = "ignore";
-$ignore{'"interface IFNAME " "vrf NAME"'} = "ignore";
-$ignore{'"link-params"'} = "ignore";
-$ignore{'"vrf NAME"'} = "ignore";
-$ignore{'"ip vrf NAME"'} = "ignore";
-$ignore{'"router rip"'} = "ignore";
-$ignore{'"router ripng"'} = "ignore";
-$ignore{'"router ospf"'} = "ignore";
-$ignore{'"router ospf (1-65535)"'} = "ignore";
-$ignore{'"router ospf6"'} = "ignore";
-$ignore{'"mpls ldp"'} = "ignore";
-$ignore{'"l2vpn WORD type vpls"'} = "ignore";
-$ignore{'"member pseudowire IFNAME"'} = "ignore";
-$ignore{'"router bgp"'} = "ignore";
-$ignore{'"router bgp " "(1-4294967295)"'} = "ignore";
-$ignore{'"router bgp " "(1-4294967295)" " <view|vrf> WORD"'} = "ignore";
-$ignore{'"router bgp [(1-4294967295) [<view|vrf> WORD]]"'} = "ignore";
-$ignore{'"router isis WORD"'} = "ignore";
-$ignore{'"router eigrp (1-65535)"'} = "ignore";
-$ignore{'"router zebra"'} = "ignore";
-$ignore{'"address-family ipv4"'} = "ignore";
-$ignore{'"address-family ipv4 [<unicast|multicast|vpn|encap>]"'} = "ignore";
-$ignore{'"address-family ipv6"'} = "ignore";
-$ignore{'"address-family ipv6 [<unicast|multicast|vpn|encap>]"'} = "ignore";
-$ignore{'"address-family vpnv4"'} = "ignore";
-$ignore{'"address-family vpnv4 unicast"'} = "ignore";
-$ignore{'"address-family ipv4 vrf NAME"'} = "ignore";
-$ignore{'"address-family <encap|encapv4>"'} = "ignore";
-$ignore{'"address-family encapv6"'} = "ignore";
-$ignore{'"address-family ipv4 encap"'} = "ignore";
-$ignore{'"address-family ipv6 encap"'} = "ignore";
-$ignore{'"address-family ipv6 vpn"'} = "ignore";
-$ignore{'"address-family vpnv6"'} = "ignore";
-$ignore{'"address-family vpnv6 unicast"'} = "ignore";
-$ignore{'"exit-address-family"'} = "ignore";
-$ignore{'"exit-link-params"'} = "ignore";
-$ignore{'"vnc defaults"'} = "ignore";
-$ignore{'"vnc l2-group NAME"'} = "ignore";
-$ignore{'"vnc nve-group NAME"'} = "ignore";
-$ignore{'"exit-vnc"'} = "ignore";
-$ignore{'"key chain WORD"'} = "ignore";
-$ignore{'"key (0-2147483647)"'} = "ignore";
-$ignore{'"route-map WORD <deny|permit> (1-65535)"'} = "ignore";
-$ignore{'"show route-map"'} = "ignore";
-$ignore{'"line vty"'} = "ignore";
-$ignore{'"who"'} = "ignore";
-$ignore{'"terminal monitor"'} = "ignore";
-$ignore{'"terminal no monitor"'} = "ignore";
-$ignore{'"show history"'} = "ignore";
-$ignore{'"router ospf [(1-65535)]"'} = "ignore";
-$ignore{'"address-family vpnv6 [unicast]"'} = "ignore";
-$ignore{'"address-family vpnv4 [unicast]"'} = "ignore";
-$ignore{'"logical-router (1-65535) ns NAME"'} = "ignore";
-$ignore{'"vrf-policy NAME"' } = "ignore";
-$ignore{'"exit-vrf-policy"' } = "ignore";
-
 my $cli_stomp = 0;
 
 foreach (@ARGV) {
@@ -139,10 +82,10 @@ foreach (@ARGV) {
             $protocol = "VTYSH_RIPD";
         }
         elsif ($file =~ /lib\/routemap\.c$/) {
-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD";
+            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD";
         }
         elsif ($file =~ /lib\/vrf\.c$/) {
-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
         }
         elsif ($file =~ /lib\/filter\.c$/) {
             $protocol = "VTYSH_ALL";
@@ -154,7 +97,7 @@ foreach (@ARGV) {
             if ($defun_array[1] =~ m/ipv6/) {
                 $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
             } else {
-                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD";
+                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD";
             }
         }
         elsif ($file =~ /lib\/distribute\.c$/) {
@@ -216,8 +159,7 @@ foreach (@ARGV) {
         $ecmd =~ s/\s+$//g;
 
         # Register $ecmd
-        if (defined ($cmd2str{$ecmd})
-            && ! defined ($ignore{$cmd2str{$ecmd}})) {
+        if (defined ($cmd2str{$ecmd})) {
             my ($key);
             $key = $enode . "," . $cmd2str{$ecmd};
             $ocmd{$key} = $ecmd;
index afb742d903740165a910741d27da6e4f0cd1128b..0473b244a72bbd9df8db2f00df4c246553eeb9ec 100644 (file)
@@ -1837,7 +1837,7 @@ DEFUNSH (VTYSH_INTERFACE,
 }
 
 /* TODO Implement "no interface command in isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD|VTYSH_LDPD,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD,
        vtysh_no_interface_cmd,
        "no interface IFNAME",
        NO_STR
@@ -1921,8 +1921,8 @@ DEFUNSH (VTYSH_VRF,
 
 /* TODO Implement interface description commands in ripngd, ospf6d
  * and isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD|VTYSH_LDPD,
-       vtysh_interface_desc_cmd,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD,
+      vtysh_interface_desc_cmd,
        "description LINE...",
        "Interface specific description\n"
        "Characters describing this interface\n")
@@ -2048,29 +2048,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,
@@ -3432,6 +3446,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);
index 11b678fe4ded8f58eb26923d7206c3ac7832af45..ad45abcdf33185b7eee6bdbe50453cde0feef6a3 100644 (file)
@@ -45,7 +45,7 @@ DECLARE_MGROUP(MVTYSH)
  * things like prefix lists are not even initialised) */
 #define VTYSH_ALL        VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
 #define VTYSH_RMAP       VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD
-#define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
+#define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
 #define VTYSH_NS          VTYSH_ZEBRA
 #define VTYSH_VRF        VTYSH_ZEBRA
 
index ca52d65bc1ba82486808f0c11517de4dbf314663..06e856934100e571eddcc7177c41deca37e879e3 100644 (file)
@@ -276,6 +276,7 @@ vtysh_config_parse_line (const char *line)
        {
          if (strncmp (line, "log", strlen ("log")) == 0
              || strncmp (line, "hostname", strlen ("hostname")) == 0
+             || strncmp (line, "frr", strlen ("frr")) == 0
             )
            config_add_line_uniq (config_top, line);
          else
index 1910e7b80f0871e02df885870d70f1eff83bd71b..3e0de3b4631c7b913b111f7f46760e0d999a7ffa 100644 (file)
@@ -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)
+       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,42 @@ 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
+       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_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+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 \
index 2e9fef292ba7e91e45a090c5420915acfd9fd7ae..f21778276ef75af9653759eeb656b1eca721e934 100644 (file)
@@ -399,6 +399,11 @@ config_write_debug (struct vty *vty)
       vty_out (vty, "debug zebra fpm%s", VTY_NEWLINE);
       write++;
     }
+  if (IS_ZEBRA_DEBUG_NHT)
+    {
+      vty_out (vty, "debug zebra nht%s", VTY_NEWLINE);
+      write++;
+    }
   if (IS_ZEBRA_DEBUG_MPLS)
     {
       vty_out (vty, "debug zebra mpls%s", VTY_NEWLINE);
index a4498a84f6fb07959341c72aafd4f5fbd47d9210..5333f0331ed064403d64455caaaf9e7cb8da5d0a 100644 (file)
@@ -110,7 +110,8 @@ interface_list_ioctl (void)
       ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
       ifp = if_get_by_name_len(ifreq->ifr_name,
                               strnlen(ifreq->ifr_name,
-                                      sizeof(ifreq->ifr_name)));
+                                      sizeof(ifreq->ifr_name)),
+                               VRF_DEFAULT, 0);
       if_add_update (ifp);
       size = ifreq->ifr_addr.sa_len;
       if (size < sizeof (ifreq->ifr_addr))
@@ -123,7 +124,8 @@ interface_list_ioctl (void)
     {
       ifp = if_get_by_name_len(ifreq->ifr_name,
                               strnlen(ifreq->ifr_name,
-                                      sizeof(ifreq->ifr_name)));
+                                      sizeof(ifreq->ifr_name)),
+                               VRF_DEFAULT, 0);
       if_add_update (ifp);
       ifreq++;
     }
@@ -201,7 +203,7 @@ if_getaddrs (void)
           continue;
         }
        
-      ifp = if_lookup_by_name (ifap->ifa_name);
+      ifp = if_lookup_by_name (ifap->ifa_name, VRF_DEFAULT);
       if (ifp == NULL)
        {
          zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
index 339e00b22cc21d89ab3b2d07c1c90b32665d6897..dbc4109913819c7f23492152635498a2d1f0cb8f 100644 (file)
@@ -170,7 +170,7 @@ calculate_lifc_len:     /* must hold privileges to enter here */
              && ( *(lifreq->lifr_name + normallen) != ':') )
         normallen++;
       
-      ifp = if_get_by_name_len(lifreq->lifr_name, normallen);
+      ifp = if_get_by_name_len(lifreq->lifr_name, normallen, VRF_DEFAULT, 0);
 
       if (lifreq->lifr_addr.ss_family == AF_INET)
         ifp->flags |= IFF_IPV4;
index 65fc8789f9064c571d2319816034a637f9e59e93..28538fabdf6770748190e8d2947e72dbba5ea812 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <zebra.h>
 #include <net/if_arp.h>
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
 
 #include "linklist.h"
 #include "if.h"
@@ -298,6 +300,47 @@ netlink_vrf_change (struct nlmsghdr *h, struct rtattr *tb, const char *name)
     }
 }
 
+static int
+get_iflink_speed (const char *ifname)
+{
+  struct ifreq ifdata;
+  struct ethtool_cmd ecmd;
+  int sd;
+  int rc;
+
+  /* initialize struct */
+  memset(&ifdata, 0, sizeof(ifdata));
+
+  /* set interface name */
+  strcpy(ifdata.ifr_name, ifname);
+
+  /* initialize ethtool interface */
+  memset(&ecmd, 0, sizeof(ecmd));
+  ecmd.cmd = ETHTOOL_GSET;  /* ETHTOOL_GLINK */
+  ifdata.ifr_data = (__caddr_t) &ecmd;
+
+  /* use ioctl to get IP address of an interface */
+  sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+  if(sd < 0) {
+    zlog_debug ("Failure to read interface %s speed: %d %s",
+                ifname, errno, safe_strerror(errno));
+    return 0;
+  }
+
+  /* Get the current link state for the interface */
+  rc = ioctl(sd, SIOCETHTOOL, (char *)&ifdata);
+  if(rc < 0) {
+    zlog_debug("IOCTL failure to read interface %s speed: %d %s",
+              ifname, errno, safe_strerror(errno));
+    ecmd.speed_hi = 0;
+    ecmd.speed = 0;
+  }
+
+  close(sd);
+
+  return (ecmd.speed_hi << 16 ) | ecmd.speed;
+}
+
 /* Called from interface_lookup_netlink().  This function is only used
    during bootstrap. */
 static int
@@ -375,13 +418,14 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
     }
 
   /* Add interface. */
-  ifp = if_get_by_name_vrf (name, vrf_id);
+  ifp = if_get_by_name (name, vrf_id);
   set_ifindex(ifp, ifi->ifi_index, zns);
   ifp->flags = ifi->ifi_flags & 0x0000fffff;
   if (vrf_device)
     SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
   ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
   ifp->metric = 0;
+  ifp->speed = get_iflink_speed (name);
   ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
 
   /* Hardware type and address. */
@@ -722,13 +766,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
           if (ifp == NULL)
             {
               /* unknown interface */
-              ifp = if_get_by_name_vrf (name, vrf_id);
+              ifp = if_get_by_name (name, vrf_id);
             }
           else
             {
               /* pre-configured interface, learnt now */
               if (ifp->vrf_id != vrf_id)
-                if_update_vrf (ifp, name, strlen(name), vrf_id);
+                if_update (ifp, name, strlen(name), vrf_id);
             }
 
           /* Update interface information. */
index 8326f0e396cd8d8f9dc2f629f3e32209d7689b68..c62d9926a251f989a2bc2f85a71847f275190d1f 100644 (file)
@@ -80,7 +80,7 @@ ifstat_update_sysctl (void)
       ifm = (struct if_msghdr *) buf;
       if (ifm->ifm_type == RTM_IFINFO)
        {
-         ifp = if_lookup_by_index (ifm->ifm_index);
+         ifp = if_lookup_by_index (ifm->ifm_index, VRF_DEFAULT);
          if (ifp)
            ifp->stats = ifm->ifm_data;
        }
index 5a9de5b70b249ea5ce9b330f5b2a0cee2fe74007..1d015e858859e11213483b2f7584d7af8fff0829 100644 (file)
@@ -715,7 +715,7 @@ if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id)
   zebra_interface_vrf_update_del (ifp, vrf_id);
 
   /* update VRF */
-  if_update_vrf (ifp, ifp->name, strlen (ifp->name), vrf_id);
+  if_update (ifp, ifp->name, strlen (ifp->name), vrf_id);
 
   /* Send out notification on interface VRF change. */
   /* This is to issue an ADD, if needed. */
@@ -1056,8 +1056,8 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
       return;
     }
 
-  vty_out (vty, "  index %d metric %d mtu %d ",
-          ifp->ifindex, ifp->metric, ifp->mtu);
+  vty_out (vty, "  index %d metric %d mtu %d speed %u ",
+          ifp->ifindex, ifp->metric, ifp->mtu, ifp->speed);
   if (ifp->mtu6 != ifp->mtu)
     vty_out (vty, "mtu6 %d ", ifp->mtu6);
   vty_out (vty, "%s  flags: %s%s", VTY_NEWLINE,
@@ -1320,7 +1320,7 @@ DEFUN (show_interface_name_vrf,
   VRF_GET_ID (vrf_id, argv[idx_name]->arg);
 
   /* Specified interface print. */
-  ifp = if_lookup_by_name_vrf (argv[idx_ifname]->arg, vrf_id);
+  ifp = if_lookup_by_name (argv[idx_ifname]->arg, vrf_id);
   if (ifp == NULL)
     {
       vty_out (vty, "%% Can't find interface %s%s", argv[idx_ifname]->arg,
@@ -1352,7 +1352,7 @@ DEFUN (show_interface_name_vrf_all,
   RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
     {
       /* Specified interface print. */
-      ifp = if_lookup_by_name_vrf (argv[idx_ifname]->arg, vrf->vrf_id);
+      ifp = if_lookup_by_name (argv[idx_ifname]->arg, vrf->vrf_id);
       if (ifp)
         {
           if_dump_vty (vty, ifp);
@@ -1697,7 +1697,7 @@ link_param_cmd_unset (struct interface *ifp, uint32_t type)
     zebra_interface_parameters_update (ifp);
 }
 
-DEFUN (link_params,
+DEFUN_NOSH (link_params,
        link_params_cmd,
        "link-params",
        LINK_PARAMS_STR)
@@ -1708,7 +1708,7 @@ DEFUN (link_params,
   return CMD_SUCCESS;
 }
 
-DEFUN (exit_link_params,
+DEFUN_NOSH (exit_link_params,
        exit_link_params_cmd,
        "exit-link-params",
        "Exit from Link Params configuration mode\n")
index c9c32ce311d553d8c3ba058a0a27b9004df2c89d..4c58b6b35d26e28bef530138af7f9edbfc36030b 100644 (file)
@@ -238,7 +238,7 @@ int irdp_read_raw(struct thread *r)
  
   if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
 
-  ifp = if_lookup_by_index(ifindex);
+  ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
   if(! ifp ) return ret;
 
   zi= ifp->info;
index 1bb85a31abdb9345362f6a2f1cb81b458b8adc27..7212ed6f26b60895e12ba124a4020917c6d90a3a 100644 (file)
@@ -324,7 +324,7 @@ ifan_read (struct if_announcemsghdr *ifan)
 {
   struct interface *ifp;
   
-  ifp = if_lookup_by_index (ifan->ifan_index);
+  ifp = if_lookup_by_index (ifan->ifan_index, VRF_DEFAULT);
   
   if (ifp)
     assert ( (ifp->ifindex == ifan->ifan_index) 
@@ -341,7 +341,8 @@ ifan_read (struct if_announcemsghdr *ifan)
       /* Create Interface */
       ifp = if_get_by_name_len(ifan->ifan_name,
                               strnlen(ifan->ifan_name,
-                                      sizeof(ifan->ifan_name)));
+                                      sizeof(ifan->ifan_name)),
+                               VRF_DEFAULT, 0);
       ifp->ifindex = ifan->ifan_index;
 
       if_get_metric (ifp);
@@ -460,7 +461,7 @@ ifm_read (struct if_msghdr *ifm)
    * messages, such as up/down status changes on NetBSD, do not include a
    * sockaddr_dl).
    */
-  if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL )
+  if ( (ifp = if_lookup_by_index (ifm->ifm_index, VRF_DEFAULT)) != NULL )
     {
       /* we have an ifp, verify that the name matches as some systems,
        * eg Solaris, have a 1:many association of ifindex:ifname
@@ -487,7 +488,7 @@ ifm_read (struct if_msghdr *ifm)
    * be filled in.
    */
   if ( (ifp == NULL) && ifnlen)
-    ifp = if_lookup_by_name (ifname);
+    ifp = if_lookup_by_name (ifname, VRF_DEFAULT);
 
   /*
    * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL),
@@ -517,7 +518,7 @@ ifm_read (struct if_msghdr *ifm)
       if (ifp == NULL)
         {
          /* Interface that zebra was not previously aware of, so create. */ 
-         ifp = if_create (ifname, ifnlen);
+         ifp = if_create (ifname, ifnlen, VRF_DEFAULT);
          if (IS_ZEBRA_DEBUG_KERNEL)
            zlog_debug ("%s: creating ifp for ifindex %d", 
                        __func__, ifm->ifm_index);
@@ -723,7 +724,7 @@ ifam_read (struct ifa_msghdr *ifam)
   /* Allocate and read address information. */
   ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen);
   
-  if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL)
+  if ((ifp = if_lookup_by_index(ifam->ifam_index, VRF_DEFAULT)) == NULL)
     {
       zlog_warn ("%s: no interface for ifname %s, index %d", 
                  __func__, ifname, ifam->ifam_index);
@@ -1099,7 +1100,7 @@ rtm_write (int message,
       msg.rtm.rtm_inits |= RTV_HOPCOUNT;
     }
 
-  ifp = if_lookup_by_index (index);
+  ifp = if_lookup_by_index (index, VRF_DEFAULT);
 
   if (gate && (message == RTM_ADD || message == RTM_CHANGE))
     msg.rtm.rtm_flags |= RTF_GATEWAY;
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
new file mode 100644 (file)
index 0000000..9f83785
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Label Manager for FRR
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ *                       Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "zebra.h"
+#include "zserv.h"
+#include "lib/log.h"
+#include "lib/memory.h"
+#include "lib/mpls.h"
+#include "lib/network.h"
+#include "lib/stream.h"
+#include "lib/zclient.h"
+
+#include "label_manager.h"
+
+#define CONNECTION_DELAY 5
+
+struct label_manager lbl_mgr;
+
+DEFINE_MGROUP(LBL_MGR, "Label Manager");
+DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
+
+/* In case this zebra daemon is not acting as label manager,
+ * it will be a proxy to relay messages to external label manager
+ * This zclient thus is to connect to it
+ */
+static struct zclient *zclient;
+bool lm_is_external;
+
+static void delete_label_chunk(void *val)
+{
+       XFREE(MTYPE_LM_CHUNK, val);
+}
+
+/**
+ * Receive a request to get or release a label chunk and forward it to external
+ * label manager.
+ *
+ * It's called from zserv in case it's not an actual label manager, but just a
+ * proxy.
+ *
+ * @param cmd Type of request (connect, get or release)
+ * @param src Input buffer from zserv
+ * @return 0 on success, -1 otherwise
+ */
+int zread_relay_label_manager_request(int cmd, struct zserv *zserv)
+{
+       struct stream *src, *dst;
+       int ret;
+
+       if (zclient->sock < 0) {
+               zlog_err("%s: Error relaying label chunk request: no zclient socket",
+                                __func__);
+               return -1;
+       }
+       /* Send request to external label manager */
+       src = zserv->ibuf;
+       dst = zclient->obuf;
+
+       stream_copy(dst, src);
+
+       ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
+       if (ret <= 0) {
+               zlog_err("%s: Error relaying label chunk request: %s", __func__,
+                        strerror(errno));
+               return -1;
+       }
+       zlog_debug("%s: Label chunk request relayed. %d bytes sent", __func__,
+                  ret);
+
+       /* Release label chunk has no response */
+       if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
+               return 0;
+
+       /* read response */
+       src = zclient->ibuf;
+       dst = zserv->obuf;
+
+       stream_reset(src);
+
+       u_int16_t size;
+       u_char marker;
+       u_char version;
+       vrf_id_t vrf_id;
+       u_int16_t resp_cmd;
+       ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
+                                 &vrf_id, &resp_cmd);
+       if (ret < 0) {
+               zlog_err("%s: Error reading label chunk response: %s", __func__,
+                        strerror(errno));
+               return -1;
+       }
+       zlog_debug("%s: Label chunk response received, %d bytes", __func__,
+                  size);
+
+       /* send response back */
+       stream_copy(dst, src);
+       stream_copy(zserv->obuf, zclient->ibuf);
+       ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
+       if (ret <= 0) {
+               zlog_err("%s: Error sending label chunk response back: %s",
+                        __func__, strerror(errno));
+               return -1;
+       }
+       zlog_debug("%s: Label chunk response (%d bytes) sent back", __func__,
+                  ret);
+
+       return 0;
+}
+
+static int zclient_connect(struct thread *t)
+{
+       zclient->t_connect = NULL;
+
+       if (zclient->sock >= 0)
+               return 0;
+
+       if (zclient_socket_connect(zclient) < 0) {
+               zlog_err("Error connecting synchronous zclient!");
+               THREAD_TIMER_ON(zebrad.master, zclient->t_connect,
+                                               zclient_connect,
+                                               zclient, CONNECTION_DELAY);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Function to initialize zclient in case this is not an actual
+ * label manager, but just a proxy to an external one.
+ *
+ * @param lm_zserv_path Path to zserv socket of external label manager
+ */
+static void lm_zclient_init(char *lm_zserv_path)
+{
+       if (lm_zserv_path)
+               zclient_serv_path_set(lm_zserv_path);
+
+       /* Set default values. */
+       zclient = zclient_new(zebrad.master);
+       zclient->sock = -1;
+       zclient->t_connect = NULL;
+       zclient_connect (NULL);
+}
+
+/**
+ * Init label manager (or proxy to an external one)
+ */
+void label_manager_init(char *lm_zserv_path)
+{
+       /* this is an actual label manager */
+       if (!lm_zserv_path) {
+               zlog_debug("Initializing own label manager");
+               lm_is_external = false;
+               lbl_mgr.lc_list = list_new();
+               lbl_mgr.lc_list->del = delete_label_chunk;
+       } else {                /* it's acting just as a proxy */
+               zlog_debug("Initializing external label manager at %s",
+                          lm_zserv_path);
+               lm_is_external = true;
+               lm_zclient_init(lm_zserv_path);
+       }
+}
+
+/**
+ * Core function, assigns label cunks
+ *
+ * It first searches through the list to check if there's one available
+ * (previously released). Otherwise it creates and assigns a new one
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param keep If set, avoid garbage collection
+ * @para size Size of the label chunk
+ * @return Pointer to the assigned label chunk
+ */
+struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance,
+                                              u_char keep, uint32_t size)
+{
+       struct label_manager_chunk *lmc;
+       struct listnode *node;
+
+       node = lbl_mgr.lc_list->head;
+       /* first check if there's one available */
+       for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+               if (lmc->proto == NO_PROTO && lmc->end - lmc->start + 1 == size) {
+                       lmc->proto = proto;
+                       lmc->instance = instance;
+                       lmc->keep = keep;
+                       return lmc;
+               }
+       }
+       /* otherwise create a new one */
+       lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
+       if (!lmc)
+               return NULL;
+
+       if (list_isempty(lbl_mgr.lc_list))
+               lmc->start = MPLS_MIN_UNRESERVED_LABEL;
+       else
+               lmc->start = ((struct label_manager_chunk *)
+                             listgetdata(listtail(lbl_mgr.lc_list)))->end + 1;
+       if (lmc->start > MPLS_MAX_UNRESERVED_LABEL - size + 1) {
+               zlog_err("Reached max labels. Start: %u, size: %u", lmc->start,
+                        size);
+               return NULL;
+       }
+       lmc->end = lmc->start + size - 1;
+       lmc->proto = proto;
+       lmc->instance = instance;
+       lmc->keep = keep;
+       listnode_add(lbl_mgr.lc_list, lmc);
+
+       return lmc;
+}
+
+/**
+ * Core function, release no longer used label cunks
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param start First label of the chunk
+ * @param end Last label of the chunk
+ * @return 0 on success, -1 otherwise
+ */
+int
+release_label_chunk(u_char proto, u_short instance, uint32_t start,
+                   uint32_t end)
+{
+       struct listnode *node;
+       struct label_manager_chunk *lmc;
+       int ret = -1;
+
+       /* check that size matches */
+       zlog_debug("Releasing label chunk: %u - %u", start, end);
+       /* find chunk and disown */
+       for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+               if (lmc->start != start)
+                       continue;
+               if (lmc->end != end)
+                       continue;
+               if (lmc->proto != proto || lmc->instance != instance) {
+                       zlog_err("%s: Daemon mismatch!!", __func__);
+                       continue;
+               }
+               lmc->proto = NO_PROTO;
+               lmc->instance = 0;
+               lmc->keep = 0;
+               ret = 0;
+               break;
+       }
+       if (ret != 0)
+               zlog_err("%s: Label chunk not released!!", __func__);
+
+       return ret;
+}
+
+/**
+ * Release label chunks from a client.
+ *
+ * Called on client disconnection or reconnection. It only releases chunks
+ * with empty keep value.
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @return Number of chunks released
+ */
+int release_daemon_chunks(u_char proto, u_short instance)
+{
+       struct listnode *node;
+       struct label_manager_chunk *lmc;
+       int count = 0;
+       int ret;
+
+       for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
+               if (lmc->proto == proto && lmc->instance == instance
+                   && lmc->keep == 0) {
+                       ret =
+                           release_label_chunk(lmc->proto, lmc->instance,
+                                               lmc->start, lmc->end);
+                       if (ret == 0)
+                               count++;
+               }
+       }
+
+       zlog_debug("%s: Released %d label chunks", __func__, count);
+
+       return count;
+}
+
+void label_manager_close()
+{
+       list_delete(lbl_mgr.lc_list);
+}
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
new file mode 100644 (file)
index 0000000..0c6a5eb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Label Manager header
+ *
+ * Copyright (C) 2017 by Bingen Eguzkitza,
+ *                       Volta Networks Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LABEL_MANAGER_H
+#define _LABEL_MANAGER_H
+
+#include <stdint.h>
+
+#include "lib/linklist.h"
+#include "lib/thread.h"
+
+#define NO_PROTO 0
+
+/*
+ * Label chunk struct
+ * Client daemon which the chunk belongs to can be identified by either
+ * proto (daemon protocol) + instance.
+ * If the client then passes a non-empty value to keep field when it requests
+ * for chunks, the chunks won't be garbage collected and the client will be
+ * responsible of its release.
+ * Otherwise, if the keep field is not set (value 0) for the chunk, it will be
+ * automatically released when the client disconnects or when it reconnects
+ * (in case it died unexpectedly, we can know it's the same because it will have
+ * the same proto and instance values)
+ */
+struct label_manager_chunk {
+       u_char proto;
+       u_short instance;
+       u_char keep;
+       uint32_t start;         /* First label of the chunk */
+       uint32_t end;           /* Last label of the chunk */
+};
+
+/*
+ * Main label manager struct
+ * Holds a linked list of label chunks.
+ */
+struct label_manager {
+       struct list *lc_list;
+};
+
+bool lm_is_external;
+
+int zread_relay_label_manager_request(int cmd, struct zserv *zserv);
+void label_manager_init(char *lm_zserv_path);
+struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance,
+                                              u_char keep, uint32_t size);
+int release_label_chunk(u_char proto, u_short instance, uint32_t start,
+                       uint32_t end);
+int release_daemon_chunks(u_char proto, u_short instance);
+void label_manager_close(void);
+
+#endif                         /* _LABEL_MANAGER_H */
index 98177a423e5bfacdf363c03b9482d2aefd283b8d..459e6148d8459b2a2b645462d68e7e467044928b 100644 (file)
@@ -16,7 +16,7 @@
  * 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.  
+ * 02111-1307, USA.
  */
 
 #include <zebra.h>
 #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"
 #include "zebra/zebra_mpls.h"
+#include "zebra/label_manager.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -78,14 +78,14 @@ u_int32_t nl_rcvbufsize = 4194304;
 #endif /* HAVE_NETLINK */
 
 /* Command line options. */
-struct option longopts[] = 
+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'},
   { "retain",       no_argument,       NULL, 'r'},
 #ifdef HAVE_NETLINK
   { "nl-bufsize",   required_argument, NULL, 's'},
@@ -93,7 +93,7 @@ struct option longopts[] =
   { 0 }
 };
 
-zebra_capabilities_t _caps_p [] = 
+zebra_capabilities_t _caps_p [] =
 {
   ZCAP_NET_ADMIN,
   ZCAP_SYS_ADMIN,
@@ -118,7 +118,7 @@ struct zebra_privs_t zserv_privs =
 unsigned int multipath_num = MULTIPATH_NUM;
 
 /* SIGHUP handler. */
-static void 
+static void
 sighup (void)
 {
   zlog_info ("SIGHUP received");
@@ -182,8 +182,8 @@ sigusr1 (void)
 
 struct quagga_signal_t zebra_signals[] =
 {
-  { 
-    .signal = SIGHUP, 
+  {
+    .signal = SIGHUP,
     .handler = &sighup,
   },
   {
@@ -219,20 +219,21 @@ 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: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"\
        "  -k, --keep_kernel  Don't delete old routes which installed by zebra.\n"
        "  -r, --retain       When program terminates, retain added route by zebra.\n"
 #ifdef HAVE_NETLINK
@@ -247,7 +248,7 @@ main (int argc, char **argv)
       if (opt == EOF)
        break;
 
-      switch (opt) 
+      switch (opt)
        {
        case 0:
          break;
@@ -260,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)
@@ -274,6 +272,9 @@ main (int argc, char **argv)
        case 'z':
          zserv_path = optarg;
          break;
+       case 'l':
+         lblmgr_path = optarg;
+         break;
        case 'r':
          retain_mode = 1;
          break;
@@ -320,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
@@ -359,6 +350,9 @@ main (int argc, char **argv)
   /* This must be done only after locking pidfile (bug #403). */
   zebra_zserv_socket_init (zserv_path);
 
+  /* Init label manager */
+  label_manager_init (lblmgr_path);
+
   frr_run (zebrad.master);
 
   /* Not reached... */
index a83c307413c7d90503335017a40d37787ae79a8b..49cb92bd7d93d6b4bc19e569c579dd515c89029e 100644 (file)
@@ -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;
-}
index c0cde50baf46ad9319381138662abf421176d6de..5381d76b9874688cf88007093979a669d0b160c5 100644 (file)
@@ -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 */
index 6ac13144962dac11ab0ec4ec78e3198858fd6c20..a544593dd65afad9edf4bcd59477d37df560a6a2 100644 (file)
@@ -465,13 +465,13 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
       strcpy (gbuf, inet_ntoa (m->sg.grp));
       for (count = 0; count < oif_count; count++)
        {
-         ifp = if_lookup_by_index_vrf (oif[count], vrf);
+         ifp = if_lookup_by_index (oif[count], vrf);
          char temp[256];
 
          sprintf (temp, "%s ", ifp->name);
          strcat (oif_list, temp);
        }
-      ifp = if_lookup_by_index_vrf (iif, vrf);
+      ifp = if_lookup_by_index (iif, vrf);
       zlog_debug ("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld",
                  nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, ifp->name, oif_list, m->lastused);
     }
index 1007d0ac18dbde6ceb7315571454b4b5756d199c..4d491f3200d582fff8a96d5f2cb5e9b27059e518 100644 (file)
 #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>
 
index afa557096c2cc0b5086f69de77fbe373300d3ae9..405b2e9f7976c58a2263374e99124e7321775a2e 100644 (file)
 #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 (file)
index fdb0699..0000000
+++ /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 */
index 715e250a665ca41c2048aa1f3e6d20c5768c4286..7b4e1b90dc6ba7d28048f19c2a8d32797373cb51 100644 (file)
 #include "qpb/qpb_allocator.h"
 #include "qpb/linear_allocator.h"
 
+#ifdef HAVE_PROTOBUF
 #include "qpb/qpb.h"
 #include "fpm/fpm.pb-c.h"
+#endif
 
 /*
  * Externs.
index fba57c68f5bc02b7a9d2ea68971207b13cfc47d7..11869d8a2b1bc5632ec136e63d60788d1af4823e 100644 (file)
@@ -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));
 
index 56a6ca7afa0bcf8904473bec1c02622d6e2f01d8..5a3ed7545d294f5f4f29747428f3458d540f58ca 100644 (file)
@@ -291,7 +291,7 @@ nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe)
       case NEXTHOP_TYPE_IPV6_IFINDEX:
         if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
           {
-            ifp = if_lookup_by_index (nexthop->ifindex);
+            ifp = if_lookup_by_index (nexthop->ifindex, VRF_DEFAULT);
             if (ifp && if_is_operative(ifp))
               SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
             else
@@ -869,7 +869,7 @@ nhlfe_json (zebra_nhlfe_t *nhlfe)
                              inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
 
       if (nexthop->ifindex)
-        json_object_string_add(json_nhlfe, "interface", ifindex2ifname (nexthop->ifindex));
+        json_object_string_add(json_nhlfe, "interface", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT));
       break;
     default:
       break;
@@ -900,14 +900,14 @@ nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty)
     case NEXTHOP_TYPE_IPV4_IFINDEX:
       vty_out (vty, "  via %s", inet_ntoa (nexthop->gate.ipv4));
       if (nexthop->ifindex)
-        vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex));
+        vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT));
       break;
     case NEXTHOP_TYPE_IPV6:
     case NEXTHOP_TYPE_IPV6_IFINDEX:
       vty_out (vty, "  via %s",
                inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
       if (nexthop->ifindex)
-        vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex));
+        vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT));
       break;
     default:
       break;
@@ -1183,7 +1183,7 @@ snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
       case NEXTHOP_TYPE_IPV6_IFINDEX:
         inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
         if (snhlfe->ifindex)
-          strcat (buf, ifindex2ifname (snhlfe->ifindex));
+          strcat (buf, ifindex2ifname (snhlfe->ifindex, VRF_DEFAULT));
         break;
       default:
         break;
index b68b03e0c40394466ed7d7047b0d2cfd2c48e4d1..eaa80ac5588183ffd5410a55e7a28625c2b2d0e9 100644 (file)
@@ -38,7 +38,7 @@ struct {
 } kr_state;
 
 static int
-kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
+kernel_send_rtmsg_v4 (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
 {
   struct iovec iov[5];
   struct rt_msghdr hdr;
@@ -48,10 +48,10 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   int ret;
 
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("kernel_send_rtmsg: 0x%x, label=%u", action, in_label);
+    zlog_debug ("%s: 0x%x, label=%u", __func__, action, in_label);
 
   /* initialize header */
-  bzero(&hdr, sizeof (hdr));
+  memset (&hdr, 0, sizeof (hdr));
   hdr.rtm_version = RTM_VERSION;
 
   hdr.rtm_type = action;
@@ -66,7 +66,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   iov[iovcnt++].iov_len = sizeof (hdr);
 
   /* in label */
-  bzero(&sa_label_in, sizeof (sa_label_in));
+  memset (&sa_label_in, 0, sizeof (sa_label_in));
   sa_label_in.smpls_len = sizeof (sa_label_in);
   sa_label_in.smpls_family = AF_MPLS;
   sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
@@ -79,7 +79,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   iov[iovcnt++].iov_len = sizeof (sa_label_in);
 
   /* nexthop */
-  bzero(&nexthop, sizeof (nexthop));
+  memset (&nexthop, 0, sizeof (nexthop));
   nexthop.sin_len = sizeof (nexthop);
   nexthop.sin_family = AF_INET;
   nexthop.sin_addr = nhlfe->nexthop->gate.ipv4;
@@ -94,7 +94,7 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
   /* If action is RTM_DELETE we have to get rid of MPLS infos */
   if (action != RTM_DELETE)
     {
-      bzero(&sa_label_out, sizeof (sa_label_out));
+      memset (&sa_label_out, 0, sizeof (sa_label_out));
       sa_label_out.smpls_len = sizeof (sa_label_out);
       sa_label_out.smpls_family = AF_MPLS;
       sa_label_out.smpls_label =
@@ -120,7 +120,116 @@ kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
     zlog_err ("Can't lower privileges");
 
   if (ret == -1)
-    zlog_err ("kernel_send_rtmsg: %s", safe_strerror (errno));
+    zlog_err ("%s: %s", __func__, safe_strerror (errno));
+
+  return ret;
+}
+
+#if !defined(ROUNDUP)
+#define        ROUNDUP(a)      \
+    (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
+#endif
+
+static int
+kernel_send_rtmsg_v6 (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
+{
+  struct iovec iov[5];
+  struct rt_msghdr hdr;
+  struct sockaddr_mpls sa_label_in, sa_label_out;
+  struct pad {
+      struct sockaddr_in6      addr;
+      char                     pad[sizeof(long)]; /* thank you IPv6 */
+  } nexthop;
+  int iovcnt = 0;
+  int ret;
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("%s: 0x%x, label=%u", __func__, action, in_label);
+
+  /* initialize header */
+  memset (&hdr, 0, sizeof (hdr));
+  hdr.rtm_version = RTM_VERSION;
+
+  hdr.rtm_type = action;
+  hdr.rtm_flags = RTF_UP;
+  hdr.rtm_fmask = RTF_MPLS;
+  hdr.rtm_seq = kr_state.rtseq++;      /* overflow doesn't matter */
+  hdr.rtm_msglen = sizeof (hdr);
+  hdr.rtm_hdrlen = sizeof (struct rt_msghdr);
+  hdr.rtm_priority = 0;
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &hdr;
+  iov[iovcnt++].iov_len = sizeof (hdr);
+
+  /* in label */
+  memset (&sa_label_in, 0, sizeof (sa_label_in));
+  sa_label_in.smpls_len = sizeof (sa_label_in);
+  sa_label_in.smpls_family = AF_MPLS;
+  sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
+  /* adjust header */
+  hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
+  hdr.rtm_addrs |= RTA_DST;
+  hdr.rtm_msglen += sizeof (sa_label_in);
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &sa_label_in;
+  iov[iovcnt++].iov_len = sizeof (sa_label_in);
+
+  /* nexthop */
+  memset (&nexthop, 0, sizeof (nexthop));
+  nexthop.addr.sin6_len = sizeof (struct sockaddr_in6);
+  nexthop.addr.sin6_family = AF_INET6;
+  nexthop.addr.sin6_addr = nhlfe->nexthop->gate.ipv6;
+  if (IN6_IS_ADDR_LINKLOCAL (&nexthop.addr.sin6_addr))
+    {
+      uint16_t                  tmp16;
+      struct sockaddr_in6      *sin6 = &nexthop.addr;
+
+      nexthop.addr.sin6_scope_id = nhlfe->nexthop->ifindex;
+
+      memcpy (&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof (tmp16));
+      tmp16 = htons (sin6->sin6_scope_id);
+      memcpy (&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof (tmp16));
+      sin6->sin6_scope_id = 0;
+    }
+
+  /* adjust header */
+  hdr.rtm_flags |= RTF_GATEWAY;
+  hdr.rtm_addrs |= RTA_GATEWAY;
+  hdr.rtm_msglen += ROUNDUP (sizeof (struct sockaddr_in6));
+  /* adjust iovec */
+  iov[iovcnt].iov_base = &nexthop;
+  iov[iovcnt++].iov_len = ROUNDUP (sizeof (struct sockaddr_in6));
+
+  /* If action is RTM_DELETE we have to get rid of MPLS infos */
+  if (action != RTM_DELETE)
+    {
+      memset (&sa_label_out, 0, sizeof (sa_label_out));
+      sa_label_out.smpls_len = sizeof (sa_label_out);
+      sa_label_out.smpls_family = AF_MPLS;
+      sa_label_out.smpls_label =
+       htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET);
+      /* adjust header */
+      hdr.rtm_addrs |= RTA_SRC;
+      hdr.rtm_flags |= RTF_MPLS;
+      hdr.rtm_msglen += sizeof (sa_label_out);
+      /* adjust iovec */
+      iov[iovcnt].iov_base = &sa_label_out;
+      iov[iovcnt++].iov_len = sizeof (sa_label_out);
+
+      if (nhlfe->nexthop->nh_label->label[0] == MPLS_LABEL_IMPLNULL)
+       hdr.rtm_mpls = MPLS_OP_POP;
+      else
+       hdr.rtm_mpls = MPLS_OP_SWAP;
+    }
+
+  if (zserv_privs.change(ZPRIVS_RAISE))
+    zlog_err ("Can't raise privileges");
+  ret = writev (kr_state.fd, iov, iovcnt);
+  if (zserv_privs.change(ZPRIVS_LOWER))
+    zlog_err ("Can't lower privileges");
+
+  if (ret == -1)
+    zlog_err ("%s: %s", __func__, safe_strerror (errno));
 
   return ret;
 }
@@ -141,10 +250,6 @@ kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
       if (nexthop_num >= multipath_num)
         break;
 
-      /* XXX */
-      if (NHLFE_FAMILY(nhlfe) == AF_INET6)
-       continue;
-
       if (((action == RTM_ADD || action == RTM_CHANGE) &&
            (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) &&
             CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) ||
@@ -154,7 +259,17 @@ kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
         {
           nexthop_num++;
 
-         kernel_send_rtmsg (action, lsp->ile.in_label, nhlfe);
+         switch (NHLFE_FAMILY(nhlfe))
+           {
+           case AF_INET:
+             kernel_send_rtmsg_v4 (action, lsp->ile.in_label, nhlfe);
+             break;
+           case AF_INET6:
+             kernel_send_rtmsg_v6 (action, lsp->ile.in_label, nhlfe);
+             break;
+           default:
+             break;
+           }
           if (action == RTM_ADD || action == RTM_CHANGE)
             {
               SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
index f9734fdf7d12ad5f5800c81b079c91917d0169fb..b3e70e46fa9eaa558a6d6e4d4c59d85e85a0835b 100644 (file)
 #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;
 
@@ -272,7 +273,7 @@ rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
   if (src)
     nexthop->src.ipv4 = *src;
   nexthop->ifindex = ifindex;
-  ifp = if_lookup_by_index (nexthop->ifindex);
+  ifp = if_lookup_by_index (nexthop->ifindex, VRF_DEFAULT);
   /*Pending: need to think if null ifp here is ok during bootup?
     There was a crash because ifp here was coming to be NULL */
   if (ifp)
@@ -388,7 +389,7 @@ nexthop_active (afi_t afi, struct rib *rib, struct nexthop *nexthop, int set,
    */
   if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
     {
-      ifp = if_lookup_by_index (nexthop->ifindex);
+      ifp = if_lookup_by_index (nexthop->ifindex, VRF_DEFAULT);
       if (ifp && connected_is_unnumbered(ifp))
        {
          if (if_is_operative(ifp))
@@ -938,7 +939,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
   switch (nexthop->type)
     {
     case NEXTHOP_TYPE_IFINDEX:
-      ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id);
+      ifp = if_lookup_by_index (nexthop->ifindex, rib->vrf_id);
       if (ifp && if_is_operative(ifp))
        SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       else
@@ -965,7 +966,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
        family = AFI_IP6;
       if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
        {
-         ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id);
+         ifp = if_lookup_by_index (nexthop->ifindex, rib->vrf_id);
          if (ifp && if_is_operative(ifp))
            SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
          else
@@ -1021,7 +1022,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
          srcdest_rnode2str(rn, buf, sizeof(buf));
          zlog_debug("%u:%s: Filtering out with NH out %s due to route map",
                     rib->vrf_id, buf,
-                    ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                    ifindex2ifname (nexthop->ifindex, rib->vrf_id));
        }
       UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     }
@@ -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);
index 5fe4a7ab9d9216be5217acc39d1b7b38061490ce..847da529523d671314f34c70f55ee51792c3969f 100644 (file)
@@ -189,7 +189,7 @@ route_match_interface (void *rule, struct prefix *prefix,
       nh_data = object;
       if (!nh_data || !nh_data->nexthop)
        return RMAP_NOMATCH;
-      ifindex = ifname2ifindex_vrf (ifname, nh_data->vrf_id);
+      ifindex = ifname2ifindex (ifname, nh_data->vrf_id);
       if (ifindex == 0)
        return RMAP_NOMATCH;
       if (nh_data->nexthop->ifindex == ifindex)
@@ -375,11 +375,11 @@ DEFUN (set_src,
   RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
     {
       if (family == AF_INET)
-        pif = if_lookup_exact_address_vrf ((void *)&src.ipv4, AF_INET,
-                                           vrf->vrf_id);
+        pif = if_lookup_exact_address ((void *)&src.ipv4, AF_INET,
+                                       vrf->vrf_id);
       else if (family == AF_INET6)
-        pif = if_lookup_exact_address_vrf ((void *)&src.ipv6, AF_INET6,
-                                           vrf->vrf_id);
+        pif = if_lookup_exact_address ((void *)&src.ipv6, AF_INET6,
+                                       vrf->vrf_id);
 
       if (pif != NULL)
         break;
index 19364b5b91847c13a1fd5f1bf4b000871699dd3f..8adb8873dc9be28506f366534f096970e2294fe0 100644 (file)
@@ -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,
+)
index 6fc41c3a1486595b573517095a0f0f13835da1cd..bc18ee5863650caee2eaa4f0a74522b3d55804d7 100644 (file)
@@ -171,7 +171,7 @@ zebra_vrf_enable (struct vrf *vrf)
              si->vrf_id = vrf->vrf_id;
              if (si->ifindex)
                {
-                 ifp = if_lookup_by_name_vrf (si->ifname, si->vrf_id);
+                 ifp = if_lookup_by_name (si->ifname, si->vrf_id);
                  if (ifp)
                    si->ifindex = ifp->ifindex;
                  else
index 7946089aea3604fa1ca0e08f557db63acbb4d8d3..35aa69cc97c18eb27011bac6ef844bdfeb10127b 100644 (file)
@@ -184,7 +184,7 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
   ret = inet_aton (gate_str, &gate);
   if (!ret)
     {
-      struct interface *ifp = if_lookup_by_name_vrf (gate_str, zvrf_id (zvrf));
+      struct interface *ifp = if_lookup_by_name (gate_str, zvrf_id (zvrf));
       if (!ifp)
         {
          vty_out (vty, "%% Unknown interface: %s%s", gate_str, VTY_NEWLINE);
@@ -725,7 +725,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
              vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4));
              if (nexthop->ifindex)
                vty_out (vty, ", via %s",
-                         ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                         ifindex2ifname (nexthop->ifindex, rib->vrf_id));
              break;
            case NEXTHOP_TYPE_IPV6:
            case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -733,11 +733,11 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
                       inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
              if (nexthop->ifindex)
                vty_out (vty, ", via %s",
-                         ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                         ifindex2ifname (nexthop->ifindex, rib->vrf_id));
              break;
            case NEXTHOP_TYPE_IFINDEX:
              vty_out (vty, " directly connected, %s",
-                      ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                      ifindex2ifname (nexthop->ifindex, rib->vrf_id));
              break;
            case NEXTHOP_TYPE_BLACKHOLE:
              vty_out (vty, " directly connected, Null0");
@@ -874,7 +874,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
               if (nexthop->ifindex)
                 {
                   json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex);
-                  json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                  json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname (nexthop->ifindex, rib->vrf_id));
                 }
               break;
             case NEXTHOP_TYPE_IPV6:
@@ -885,14 +885,14 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
               if (nexthop->ifindex)
                 {
                   json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex);
-                  json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                  json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname (nexthop->ifindex, rib->vrf_id));
                 }
               break;
 
             case NEXTHOP_TYPE_IFINDEX:
               json_object_boolean_true_add(json_nexthop, "directlyConnected");
               json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex);
-              json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+              json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname (nexthop->ifindex, rib->vrf_id));
               break;
             case NEXTHOP_TYPE_BLACKHOLE:
               json_object_boolean_true_add(json_nexthop, "blackhole");
@@ -975,7 +975,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
          vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
          if (nexthop->ifindex)
            vty_out (vty, ", %s",
-                     ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                     ifindex2ifname (nexthop->ifindex, rib->vrf_id));
          break;
         case NEXTHOP_TYPE_IPV6:
        case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -983,12 +983,12 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib,
                   inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
          if (nexthop->ifindex)
            vty_out (vty, ", %s",
-                     ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                     ifindex2ifname (nexthop->ifindex, rib->vrf_id));
          break;
 
        case NEXTHOP_TYPE_IFINDEX:
          vty_out (vty, " is directly connected, %s",
-                  ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id));
+                  ifindex2ifname (nexthop->ifindex, rib->vrf_id));
          break;
        case NEXTHOP_TYPE_BLACKHOLE:
          vty_out (vty, " is directly connected, Null0");
@@ -2292,7 +2292,7 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd)
              case STATIC_IPV6_GATEWAY_IFINDEX:
                vty_out (vty, " %s %s",
                         inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ),
-                        ifindex2ifname_vrf (si->ifindex, si->vrf_id));
+                        ifindex2ifname (si->ifindex, si->vrf_id));
                break;
               }
 
@@ -2459,7 +2459,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
         }
       type = STATIC_IPV6_GATEWAY_IFINDEX;
       gate = &gate_addr;
-      ifp = if_lookup_by_name_vrf (ifname, zvrf_id (zvrf));
+      ifp = if_lookup_by_name (ifname, zvrf_id (zvrf));
       if (!ifp)
         {
           vty_out (vty, "%% Malformed Interface name %s%s", ifname, VTY_NEWLINE);
@@ -2477,7 +2477,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
       else
         {
           type = STATIC_IFINDEX;
-          ifp = if_lookup_by_name_vrf (gate_str, zvrf_id (zvrf));
+          ifp = if_lookup_by_name (gate_str, zvrf_id (zvrf));
           if (!ifp)
             {
               vty_out (vty, "%% Malformed Interface name %s%s", gate_str, VTY_NEWLINE);
@@ -3143,7 +3143,7 @@ DEFUN (show_ipv6_route_protocol,
     VRF_GET_ID (vrf_id, argv[idx]->arg);
 
   char *proto = argv[argc - 1]->text;
-  type = proto_redistnum (AFI_IP, proto);
+  type = proto_redistnum (AFI_IP6, proto);
 
   if (type < 0)
     {
@@ -3431,7 +3431,7 @@ DEFUN (show_ipv6_route_vrf_all_tag,
   RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
     {
       if ((zvrf = vrf->info) == NULL ||
-          (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL)
+          (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL)
         continue;
 
       /* Show all IPv6 routes with matching tag value. */
@@ -3541,7 +3541,7 @@ DEFUN (show_ipv6_route_vrf_all_protocol,
   int vrf_header = 1;
 
   char *proto = argv[argc - 1]->text;
-  type = proto_redistnum (AFI_IP, proto);
+  type = proto_redistnum (AFI_IP6, proto);
 
   if (type < 0)
     {
@@ -3705,7 +3705,7 @@ DEFUN (show_ipv6_mroute_vrf_all,
   RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
     {
       if ((zvrf = vrf->info) == NULL ||
-          (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL)
+          (table = zvrf->table[AFI_IP6][SAFI_MULTICAST]) == NULL)
         continue;
 
       /* Show all IPv6 route. */
@@ -3784,7 +3784,7 @@ static_config_ipv6 (struct vty *vty)
              case STATIC_IPV6_GATEWAY_IFINDEX:
                vty_out (vty, " %s %s",
                         inet_ntop (AF_INET6, &si->addr.ipv6, buf, BUFSIZ),
-                        ifindex2ifname_vrf (si->ifindex, si->vrf_id));
+                        ifindex2ifname (si->ifindex, si->vrf_id));
                break;
              }
 
@@ -3825,7 +3825,7 @@ static_config_ipv6 (struct vty *vty)
 DEFUN (allow_external_route_update,
        allow_external_route_update_cmd,
        "allow-external-route-update",
-       "Allow FRR routes to be overwritten by external processes")
+       "Allow FRR routes to be overwritten by external processes\n")
 {
   allow_delete = 1;
 
@@ -3835,7 +3835,8 @@ DEFUN (allow_external_route_update,
 DEFUN (no_allow_external_route_update,
        no_allow_external_route_update_cmd,
        "no allow-external-route-update",
-       "Allow FRR routes to be overwritten by external processes")
+       NO_STR
+       "Allow FRR routes to be overwritten by external processes\n")
 {
   allow_delete = 0;
 
index 064489acd99377ea896dfe42efb8455b449e66e8..3477dc36d2ccb355295d1a099fa559e9e9502281 100644 (file)
@@ -53,8 +53,8 @@
 #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"
 
 /* Event list of zebra. */
 enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -113,6 +113,9 @@ zebra_server_send_message(struct zserv *client)
   if (client->t_suicide)
     return -1;
 
+  if (client->is_synchronous)
+    return 0;
+
   stream_set_getp(client->obuf, 0);
   client->last_write_cmd = stream_getw_from(client->obuf, 6);
   switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf),
@@ -163,6 +166,7 @@ zserv_encode_interface (struct stream *s, struct interface *ifp)
   stream_putc (s, ifp->ptm_enable);
   stream_putc (s, ifp->ptm_status);
   stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->speed);
   stream_putl (s, ifp->mtu);
   stream_putl (s, ifp->mtu6);
   stream_putl (s, ifp->bandwidth);
@@ -1770,6 +1774,167 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
                         distance, out_label);
     }
 }
+/* Send response to a label manager connect request to client */
+static int
+zsend_label_manager_connect_response (struct zserv *client, vrf_id_t vrf_id, u_short result)
+{
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  zserv_create_header (s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
+
+  /* result */
+  stream_putc (s, result);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+static void
+zread_label_manager_connect (struct zserv *client, vrf_id_t vrf_id)
+{
+  struct stream *s;
+  /* type of protocol (lib/zebra.h) */
+  u_char proto;
+  u_short instance;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Get data. */
+  proto = stream_getc (s);
+  instance = stream_getw (s);
+
+  /* accept only dynamic routing protocols */
+  if ((proto >= ZEBRA_ROUTE_MAX)
+      ||  (proto <= ZEBRA_ROUTE_STATIC))
+    {
+      zlog_err ("client %d has wrong protocol %s",
+                client->sock, zebra_route_string(proto));
+      zsend_label_manager_connect_response (client, vrf_id, 1);
+      return;
+    }
+  zlog_notice ("client %d with instance %u connected as %s",
+               client->sock, instance, zebra_route_string(proto));
+  client->proto = proto;
+  client->instance = instance;
+
+  /*
+    Release previous labels of same protocol and instance.
+    This is done in case it restarted from an unexpected shutdown.
+  */
+  release_daemon_chunks (proto, instance);
+
+  zlog_debug (" Label Manager client connected: sock %d, proto %s, instance %u",
+              client->sock, zebra_route_string(proto), instance);
+  /* send response back */
+  zsend_label_manager_connect_response (client, vrf_id, 0);
+}
+/* Send response to a get label chunk request to client */
+static int
+zsend_assign_label_chunk_response (struct zserv *client, vrf_id_t vrf_id,
+                                   struct label_manager_chunk *lmc)
+{
+  struct stream *s;
+
+  s = client->obuf;
+  stream_reset (s);
+
+  zserv_create_header (s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
+
+  if (lmc)
+    {
+      /* keep */
+      stream_putc (s, lmc->keep);
+      /* start and end labels */
+      stream_putl (s, lmc->start);
+      stream_putl (s, lmc->end);
+
+    }
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (client->sock, s->data, stream_get_endp (s));
+}
+
+static void
+zread_get_label_chunk (struct zserv *client, vrf_id_t vrf_id)
+{
+  struct stream *s;
+  u_char keep;
+  uint32_t size;
+  struct label_manager_chunk *lmc;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Get data. */
+  keep = stream_getc (s);
+  size = stream_getl (s);
+
+  lmc = assign_label_chunk (client->proto, client->instance, keep, size);
+  if (!lmc)
+    zlog_err ("%s: Unable to assign Label Chunk of size %u", __func__, size);
+  else
+    zlog_debug ("Assigned Label Chunk %u - %u to %u",
+                lmc->start, lmc->end, keep);
+  /* send response back */
+  zsend_assign_label_chunk_response (client, vrf_id, lmc);
+}
+
+static void
+zread_release_label_chunk (struct zserv *client)
+{
+  struct stream *s;
+  uint32_t start, end;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Get data. */
+  start = stream_getl (s);
+  end = stream_getl (s);
+
+  release_label_chunk (client->proto, client->instance, start, end);
+}
+static void
+zread_label_manager_request (int cmd, struct zserv *client, vrf_id_t vrf_id)
+{
+  /* to avoid sending other messages like ZERBA_INTERFACE_UP */
+  if (cmd == ZEBRA_LABEL_MANAGER_CONNECT)
+    client->is_synchronous = 1;
+
+  /* external label manager */
+  if (lm_is_external)
+    {
+      if (zread_relay_label_manager_request (cmd, client) != 0)
+        zsend_label_manager_connect_response (client, vrf_id, 1);
+    }
+  /* this is a label manager */
+  else
+    {
+      if (cmd == ZEBRA_LABEL_MANAGER_CONNECT)
+        zread_label_manager_connect (client, vrf_id);
+      else
+        {
+          /* Sanity: don't allow 'unidentified' requests */
+          if (!client->proto)
+            {
+              zlog_err ("Got label request from an unidentified client");
+              return;
+            }
+          if (cmd == ZEBRA_GET_LABEL_CHUNK)
+            zread_get_label_chunk (client, vrf_id);
+          else if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
+            zread_release_label_chunk (client);
+        }
+    }
+}
 
 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
 static void
@@ -1807,6 +1972,9 @@ zebra_client_close (struct zserv *client)
   /* Cleanup any registered nexthops - across all VRFs. */
   zebra_client_close_cleanup_rnh (client);
 
+  /* Release Label Manager chunks */
+  release_daemon_chunks (client->proto, client->instance);
+
   /* Close file descriptor. */
   if (client->sock)
     {
@@ -1868,6 +2036,9 @@ zebra_client_create (int sock)
   client->ifinfo = vrf_bitmap_init ();
   client->ridinfo = vrf_bitmap_init ();
 
+  /* by default, it's not a synchronous client */
+  client->is_synchronous = 0;
+
   /* Add this client to linked list. */
   listnode_add (zebrad.client_list, client);
   
@@ -2087,6 +2258,11 @@ zebra_client_read (struct thread *thread)
     case ZEBRA_IPMR_ROUTE_STATS:
       zebra_ipmr_route_stats (client, sock, length, zvrf);
       break;
+    case ZEBRA_LABEL_MANAGER_CONNECT:
+    case ZEBRA_GET_LABEL_CHUNK:
+    case ZEBRA_RELEASE_LABEL_CHUNK:
+      zread_label_manager_request (command, client, vrf_id);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;
@@ -2674,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)
@@ -2703,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);
index 21cf1004bf62b33c03399ea2c3273f0b253ccf15..cd1948373a8a63ce79d5245cdced0b9522dc69c0 100644 (file)
@@ -78,6 +78,7 @@ struct zserv
   /* client's protocol */
   u_char proto;
   u_short instance;
+  u_char is_synchronous;
 
   /* Statistics */
   u_int32_t redist_v4_add_cnt;
@@ -148,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 *);