diff options
257 files changed, 8474 insertions, 2966 deletions
diff --git a/COMMUNITY.md b/COMMUNITY.md index 52777da96..704c47a95 100644 --- a/COMMUNITY.md +++ b/COMMUNITY.md @@ -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. @@ -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/ diff --git a/Makefile.am b/Makefile.am index aeacd4c3c..c0efa1925 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/REPORTING-BUGS b/REPORTING-BUGS index ea36ff5ee..01f25a205 100644 --- a/REPORTING-BUGS +++ b/REPORTING-BUGS @@ -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. diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 50afc7ed6..b6ed9a4d6 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -67,6 +67,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a +module_LTLIBRARIES = sbin_PROGRAMS = bgpd bin_PROGRAMS = bgp_btoa @@ -75,7 +76,7 @@ libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ - bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \ + bgp_dump.c bgp_ecommunity.c bgp_lcommunity.c \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ @@ -89,7 +90,7 @@ noinst_HEADERS = \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_lcommunity.h \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ - bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ + bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h @@ -101,6 +102,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 diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 7dc7f053d..2bbdca595 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -45,14 +45,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_advertise.h" -#ifdef HAVE_SNMP -#include "bgpd/bgp_snmp.h" -#endif /* HAVE_SNMP */ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" +DEFINE_HOOK(peer_backward_transition, (struct peer *peer), (peer)) +DEFINE_HOOK(peer_established, (struct peer *peer), (peer)) + /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h */ @@ -1061,9 +1061,7 @@ bgp_stop (struct peer *peer) zlog_debug ("%s remove from all update group", peer->host); update_group_remove_peer_afs(peer); -#ifdef HAVE_SNMP - bgpTrapBackwardTransition (peer); -#endif /* HAVE_SNMP */ + hook_call(peer_backward_transition, peer); /* Reset peer synctime */ peer->synctime = 0; @@ -1508,9 +1506,7 @@ bgp_establish (struct peer *peer) zlog_debug ("%s graceful restart timer stopped", peer->host); } -#ifdef HAVE_SNMP - bgpTrapEstablished (peer); -#endif /* HAVE_SNMP */ + hook_call(peer_established, peer); /* Reset uptime, send keepalive, send current table. */ peer->uptime = bgp_clock (); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index e47d07702..4d0b48f52 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -109,4 +109,8 @@ extern void bgp_start_routeadv (struct bgp *); */ extern void bgp_adjust_routeadv (struct peer *); +#include "hook.h" +DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)) +DECLARE_HOOK(peer_established, (struct peer *peer), (peer)) + #endif /* _QUAGGA_BGP_FSM_H */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 1358ebc5e..46ae882b2 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -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", diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 0cf96101c..930034589 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -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", diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 5e6218e8a..f45d68384 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -20,7 +20,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -31,6 +30,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "smux.h" #include "filter.h" +#include "hook.h" +#include "libfrr.h" +#include "version.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -38,7 +40,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_fsm.h" -#include "bgpd/bgp_snmp.h" /* BGP4-MIB described in RFC1657. */ #define BGP4MIB 1,3,6,1,2,1,15 @@ -838,7 +839,7 @@ static struct trap_object bgpTrapList[] = {3, {3, 1, BGPPEERSTATE}} }; -void +static int bgpTrapEstablished (struct peer *peer) { int ret; @@ -847,7 +848,7 @@ bgpTrapEstablished (struct peer *peer) ret = inet_aton (peer->host, &addr); if (ret == 0) - return; + return 0; oid_copy_addr (index, &addr, IN_ADDR_SIZE); @@ -857,9 +858,10 @@ bgpTrapEstablished (struct peer *peer) index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPESTABLISHED); + return 0; } -void +static int bgpTrapBackwardTransition (struct peer *peer) { int ret; @@ -868,7 +870,7 @@ bgpTrapBackwardTransition (struct peer *peer) ret = inet_aton (peer->host, &addr); if (ret == 0) - return; + return 0; oid_copy_addr (index, &addr, IN_ADDR_SIZE); @@ -878,12 +880,29 @@ bgpTrapBackwardTransition (struct peer *peer) index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPBACKWARDTRANSITION); + return 0; } -void -bgp_snmp_init (void) +static int +bgp_snmp_init (struct thread_master *tm) { - smux_init (bm->master); + smux_init (tm); REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); + return 0; +} + +static int +bgp_snmp_module_init (void) +{ + hook_register(peer_established, bgpTrapEstablished); + hook_register(peer_backward_transition, bgpTrapBackwardTransition); + hook_register(frr_late_init, bgp_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "bgpd_snmp", + .version = FRR_VERSION, + .description = "bgpd AgentX SNMP module", + .init = bgp_snmp_module_init +) diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h deleted file mode 100644 index 7a0d9dd00..000000000 --- a/bgpd/bgp_snmp.h +++ /dev/null @@ -1,28 +0,0 @@ -/* BGP4 SNMP support - Copyright (C) 1999, 2000 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -GNU Zebra is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#ifndef _QUAGGA_BGP_SNMP_H -#define _QUAGGA_BGP_SNMP_H - -extern void bgp_snmp_init (void); -extern void bgpTrapEstablished (struct peer *); -extern void bgpTrapBackwardTransition (struct peer *); - -#endif /* _QUAGGA_BGP_SNMP_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index dba336051..e94de682d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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") diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2a513dda2..72bd081a7 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -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; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ce0718df5..3f81c1c50 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -72,9 +72,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" -#ifdef HAVE_SNMP -#include "bgpd/bgp_snmp.h" -#endif /* HAVE_SNMP */ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" @@ -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(); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9ccc0e39d..a72974bc1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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 diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 71086c875..aa48b4924 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -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") diff --git a/configure.ac b/configure.ac index 821e0e230..ec5442d06 100755 --- a/configure.ac +++ b/configure.ac @@ -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} diff --git a/debian/README.Debian b/debian/README.Debian index caded5207..4cf35d7e3 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -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 diff --git a/debian/copyright b/debian/copyright index 6a5ed98f9..7b873abd3 100644 --- a/debian/copyright +++ b/debian/copyright @@ -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 index 000000000..57e35f3ce --- /dev/null +++ b/defaults.h @@ -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 */ diff --git a/doc/Building_FRR_on_CentOS6.md b/doc/Building_FRR_on_CentOS6.md index ccb07fb2a..9f40418ff 100644 --- a/doc/Building_FRR_on_CentOS6.md +++ b/doc/Building_FRR_on_CentOS6.md @@ -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 \ diff --git a/doc/Building_FRR_on_CentOS7.md b/doc/Building_FRR_on_CentOS7.md index cd10a91ed..0ab5c0ff5 100644 --- a/doc/Building_FRR_on_CentOS7.md +++ b/doc/Building_FRR_on_CentOS7.md @@ -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 \ diff --git a/doc/Building_FRR_on_Debian8.md b/doc/Building_FRR_on_Debian8.md index 902f8c623..b902033d5 100644 --- a/doc/Building_FRR_on_Debian8.md +++ b/doc/Building_FRR_on_Debian8.md @@ -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/ \ diff --git a/doc/Building_FRR_on_Fedora24.md b/doc/Building_FRR_on_Fedora24.md index 9617afc73..941126da4 100644 --- a/doc/Building_FRR_on_Fedora24.md +++ b/doc/Building_FRR_on_Fedora24.md @@ -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 \ diff --git a/doc/Building_FRR_on_FreeBSD10.md b/doc/Building_FRR_on_FreeBSD10.md index 696b7d5d2..36ef573bb 100644 --- a/doc/Building_FRR_on_FreeBSD10.md +++ b/doc/Building_FRR_on_FreeBSD10.md @@ -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" diff --git a/doc/Building_FRR_on_FreeBSD11.md b/doc/Building_FRR_on_FreeBSD11.md index d0b8a7bf8..d6affd688 100644 --- a/doc/Building_FRR_on_FreeBSD11.md +++ b/doc/Building_FRR_on_FreeBSD11.md @@ -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" diff --git a/doc/Building_FRR_on_FreeBSD9.md b/doc/Building_FRR_on_FreeBSD9.md index d470d0046..41d3148ad 100644 --- a/doc/Building_FRR_on_FreeBSD9.md +++ b/doc/Building_FRR_on_FreeBSD9.md @@ -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" diff --git a/doc/Building_FRR_on_NetBSD6.md b/doc/Building_FRR_on_NetBSD6.md index 03d04ce95..542a7f489 100644 --- a/doc/Building_FRR_on_NetBSD6.md +++ b/doc/Building_FRR_on_NetBSD6.md @@ -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" diff --git a/doc/Building_FRR_on_NetBSD7.md b/doc/Building_FRR_on_NetBSD7.md index d9b4b47ea..821a6109f 100644 --- a/doc/Building_FRR_on_NetBSD7.md +++ b/doc/Building_FRR_on_NetBSD7.md @@ -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" diff --git a/doc/Building_FRR_on_OmniOS.md b/doc/Building_FRR_on_OmniOS.md index f158c80a7..2e9871467 100644 --- a/doc/Building_FRR_on_OmniOS.md +++ b/doc/Building_FRR_on_OmniOS.md @@ -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/ \ diff --git a/doc/Building_FRR_on_OpenBSD6.md b/doc/Building_FRR_on_OpenBSD6.md index 9e13d5ce4..a59452a72 100644 --- a/doc/Building_FRR_on_OpenBSD6.md +++ b/doc/Building_FRR_on_OpenBSD6.md @@ -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) diff --git a/doc/Building_FRR_on_Ubuntu1204.md b/doc/Building_FRR_on_Ubuntu1204.md index 3312a2c9c..154907d9d 100644 --- a/doc/Building_FRR_on_Ubuntu1204.md +++ b/doc/Building_FRR_on_Ubuntu1204.md @@ -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 diff --git a/doc/Building_FRR_on_Ubuntu1404.md b/doc/Building_FRR_on_Ubuntu1404.md index ac0a45acd..33ef896a9 100644 --- a/doc/Building_FRR_on_Ubuntu1404.md +++ b/doc/Building_FRR_on_Ubuntu1404.md @@ -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 diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md index d1e1a377d..18724859f 100644 --- a/doc/Building_FRR_on_Ubuntu1604.md +++ b/doc/Building_FRR_on_Ubuntu1604.md @@ -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 diff --git a/doc/basic.texi b/doc/basic.texi index cea33eaa8..05d72bc80 100644 --- a/doc/basic.texi +++ b/doc/basic.texi @@ -18,6 +18,7 @@ daemons. * Config Commands:: Commands used in config files * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons +* Loadable Module Support:: Using extension modules * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @@ -372,6 +373,51 @@ Print program version. @end table +@node Loadable Module Support +@section Loadable Module Support + +FRR supports loading extension modules at startup. Loading, reloading or +unloading modules at runtime is not supported (yet). To load a module, use +the following command line option at daemon startup: + +@table @samp +@item -M @var{module:options} +@itemx --module @var{module:options} + +Load the specified module, optionally passing options to it. If the module +name contains a slash (/), it is assumed to be a full pathname to a file to +be loaded. If it does not contain a slash, the +@code{@value{INSTALL_PREFIX_MODULES}} directory is searched for a module of +the given name; first with the daemon name prepended (e.g. @code{zebra_mod} +for @code{mod}), then without the daemon name prepended. + +This option is available on all daemons, though some daemons may not have +any modules available to be loaded. +@end table + + +@subsection The SNMP Module + +If SNMP is enabled during compile-time and installed as part of the package, +the @code{snmp} module can be loaded for the @command{zebra}, +@command{bgpd}, @command{ospfd}, @command{ospf6d} and @command{ripd} daemons. + +The module ignores any options passed to it. Refer to @ref{SNMP Support} +for information on its usage. + + +@subsection The FPM Module + +If FPM is enabled during compile-time and installed as part of the package, +the @code{fpm} module can be loaded for the @command{zebra} daemon. This +provides the Forwarding Plane Manager ("FPM") API. + +The module expects its argument to be either @code{netlink} or +@code{protobuf}, specifying the encapsulation to use. @code{netlink} is the +default, and @code{protobuf} may not be available if the module was built +without protobuf support. Refer to @ref{zebra FIB push interface} for more +information. + @node Virtual Terminal Interfaces @section Virtual Terminal Interfaces diff --git a/doc/bgpd.8.in b/doc/bgpd.8.in index 9026f2cde..0df1b1dce 100644 --- a/doc/bgpd.8.in +++ b/doc/bgpd.8.in @@ -27,6 +27,9 @@ bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with @PACKAGE_FULLNAME@ ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B bgpd @@ -76,6 +79,11 @@ When the program terminates, retain routes added by \fBbgpd\fR. \fB\-S\fR, \fB\-\-skip_runas\fR Skip setting the process effective user and group. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBbgpd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/defines.texi.in b/doc/defines.texi.in index 43d744293..0fadba964 100644 --- a/doc/defines.texi.in +++ b/doc/defines.texi.in @@ -13,6 +13,7 @@ @set INSTALL_PREFIX_ETC @CFG_SYSCONF@ @set INSTALL_PREFIX_SBIN @CFG_SBIN@ @set INSTALL_PREFIX_STATE @CFG_STATE@ +@set INSTALL_PREFIX_MODULES @CFG_MODULE@ @set INSTALL_USER @enable_user@ @set INSTALL_GROUP @enable_group@ @set INSTALL_VTY_GROUP @enable_vty_group@ diff --git a/doc/dev-modules.md b/doc/dev-modules.md new file mode 100644 index 000000000..87bc96318 --- /dev/null +++ b/doc/dev-modules.md @@ -0,0 +1,119 @@ +# Module and Hook support (developer docs) + +## What it does + +It uses `dlopen()` to load DSOs at startup. + + +## Limitations + +* can't load, unload, or reload during runtime. This just needs some work + and can probably be done in the future. +* doesn't fix any of the "things need to be changed in the code in the library" + issues. Most prominently, you can't add a CLI node because CLI nodes are + listed in the library... +* if your module crashes, the daemon crashes. Should be obvious. +* **does not provide a stable API or ABI**. Your module must match a version + of FRR and you may have to update it frequently to match changes. +* **does not create a license boundary**. Your module will need to link + libzebra and include header files from the daemons, meaning it will be + GPL-encumbered. + + +## Installation + +Look for `moduledir` in `configure.ac`, default is normally +`/usr/lib64/frr/modules` but depends on `--libdir` / `--prefix`. + +The daemon's name is prepended when looking for a module, e.g. "snmp" tries +to find "zebra_snmp" first when used in zebra. This is just to make it nicer +for the user, with the snmp module having the same name everywhere. + +Modules can be packaged separately from FRR. The SNMP and FPM modules are +good candidates for this because they have dependencies (net-snmp / protobuf) +that are not FRR dependencies. However, any distro packages should have an +"exact-match" dependency onto the FRR package. Using a module from a +different FRR version will probably blow up nicely. + +For snapcraft (and during development), modules can be loaded with full path +(e.g. -M `$SNAP/lib/frr/modules/zebra_snmp.so`). Note that libtool puts output +files in the .libs directory, so during development you have to use +`./zebra -M .libs/zebra_snmp.so`. + + +## Creating a module + +... best to look at the existing SNMP or FPM modules. + +Basic boilerplate: + +``` +#include "hook.h" +#include "module.h" + +static int +module_init (void) +{ + hook_register(frr_late_init, module_late_init); + return 0; +} + +FRR_MODULE_SETUP( + .name = "my module", + .version = "0.0", + .description = "my module", + .init = module_init, +) +``` + +The `frr_late_init` hook will be called after the daemon has finished its +other startup and is about to enter the main event loop; this is the best +place for most initialisation. + + +## Compiler & Linker magic + +There's a `THIS_MODULE` (like in the Linux kernel), which uses `visibility` +attributes to restrict it to the current module. If you get a linker error +with `_frrmod_this_module`, there is some linker SNAFU. This shouldn't be +possible, though one way to get it would be to not include libzebra (which +provides a fallback definition for the symbol). + +libzebra and the daemons each have their own `THIS_MODULE`, as do all loadable +modules. In any other libraries (e.g. `libfrrsnmp`), `THIS_MODULE` will use +the definition in libzebra; same applies if the main executable doesn't use +`FRR_DAEMON_INFO` (e.g. all testcases). + +The deciding factor here is "what dynamic linker unit are you using the symbol +from." If you're in a library function and want to know who called you, you +can't use `THIS_MODULE` (because that'll just tell you you're in the library). +Put a macro around your function that adds `THIS_MODULE` in the *caller's +code calling your function*. + +The idea is to use this in the future for module unloading. Hooks already +remember which module they were installed by, as groundwork for a function +that removes all of a module's installed hooks. + +There's also the `frr_module` symbol in modules, pretty much a standard entry +point for loadable modules. + + +## Hooks + +Hooks are just points in the code where you can register your callback to +be called. The parameter list is specific to the hook point. Since there is +no stable API, the hook code has some extra type safety checks making sure +you get a compiler warning when the hook parameter list doesn't match your +callback. Don't ignore these warnings. + + +## Relation to MTYPE macros + +The MTYPE macros, while primarily designed to decouple MTYPEs from the library +and beautify the code, also work very nicely with loadable modules -- both +constructors and destructors are executed when loading/unloading modules. + +This means there is absolutely no change required to MTYPEs, you can just use +them in a module and they will even clean up themselves when we implement +module unloading and an unload happens. In fact, it's impossible to create +a bug where unloading fails to de-register a MTYPE. diff --git a/doc/frr.texi b/doc/frr.texi index a64dc9e72..b08bb6fd0 100644 --- a/doc/frr.texi +++ b/doc/frr.texi @@ -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 diff --git a/doc/git_branches.svg b/doc/git_branches.svg index 3943eeacc..0c2c96e39 100644 --- a/doc/git_branches.svg +++ b/doc/git_branches.svg @@ -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> diff --git a/doc/isisd.8.in b/doc/isisd.8.in index 9ffcbc618..542c28993 100644 --- a/doc/isisd.8.in +++ b/doc/isisd.8.in @@ -23,6 +23,9 @@ isisd \- an IS-IS routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B isisd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBisisd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ldpd.8.in b/doc/ldpd.8.in index 1683de46c..2d68a31a5 100644 --- a/doc/ldpd.8.in +++ b/doc/ldpd.8.in @@ -23,6 +23,9 @@ ldpd \- an LDP engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ldpd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBldpd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/main.texi b/doc/main.texi index dfe02e1b5..706baa25f 100644 --- a/doc/main.texi +++ b/doc/main.texi @@ -385,7 +385,8 @@ ip protocol rip route-map RM1 Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Frr -routing suite. +routing suite. This is a loadable module that needs to be enabled +at startup as described in @ref{Loadable Module Support}. In Frr, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and @@ -440,9 +441,9 @@ independently. @end itemize As mentioned before, zebra encodes routes sent to the FPM in netlink -format by default. The format can be controlled via the -@code{--fpm_format} command-line option to zebra, which currently -takes the values @code{netlink} and @code{protobuf}. +format by default. The format can be controlled via the FPM module's +load-time option to zebra, which currently takes the values @code{netlink} +and @code{protobuf}. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, diff --git a/doc/nhrpd.8.in b/doc/nhrpd.8.in index c5e4f7e32..09b662ae7 100644 --- a/doc/nhrpd.8.in +++ b/doc/nhrpd.8.in @@ -23,6 +23,9 @@ nhrpd \- a Next Hop Routing Protocol routing engine for use with @PACKAGE_FULLNA ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B nhrpd @@ -63,6 +66,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBnhrpd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ospf6d.8.in b/doc/ospf6d.8.in index 7f94782be..02d9d8083 100644 --- a/doc/ospf6d.8.in +++ b/doc/ospf6d.8.in @@ -23,6 +23,9 @@ ospf6d \- an OSPFv3 routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ospf6d @@ -64,6 +67,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBospf6d\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ospfd.8.in b/doc/ospfd.8.in index 1b86551ca..6bad77771 100644 --- a/doc/ospfd.8.in +++ b/doc/ospfd.8.in @@ -23,6 +23,9 @@ ospfd \- an OSPFv2 routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ospfd @@ -66,6 +69,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-a\fR, \fB\-\-apiserver \fR Enable OSPF apiserver. Default is disabled. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBospfd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/overview.texi b/doc/overview.texi index 370ada3f8..7ecf3d95c 100644 --- a/doc/overview.texi +++ b/doc/overview.texi @@ -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}. diff --git a/doc/pimd.8.in b/doc/pimd.8.in index 60b844b1e..3fb060e56 100644 --- a/doc/pimd.8.in +++ b/doc/pimd.8.in @@ -26,6 +26,9 @@ pimd \- a PIM routing for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B pimd @@ -70,6 +73,11 @@ interfaces. \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fI@enable_user@\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBpimd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .TP diff --git a/doc/ripd.8.in b/doc/ripd.8.in index 6db5ac364..a84668e6d 100644 --- a/doc/ripd.8.in +++ b/doc/ripd.8.in @@ -23,6 +23,9 @@ ripd \- a RIP routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ripd @@ -67,6 +70,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR module may be available for +\fBripd\fR, if the package was built with SNMP support. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/ripngd.8.in b/doc/ripngd.8.in index 4c5f2bb11..98039219a 100644 --- a/doc/ripngd.8.in +++ b/doc/ripngd.8.in @@ -23,6 +23,9 @@ ripngd \- a RIPNG routing engine for use with @PACKAGE_FULLNAME@. ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B ripngd @@ -67,6 +70,11 @@ Specify the user to run as. Default is \fI@enable_user@\fR. \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +There are currently no such modules for +\fBripngd\fR in the base package. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/doc/snmp.texi b/doc/snmp.texi index c2c889de7..d9656941d 100644 --- a/doc/snmp.texi +++ b/doc/snmp.texi @@ -8,6 +8,10 @@ but is able to connect to a SNMP agent using the SMUX protocol (@cite{RFC1227}) or the AgentX protocol (@cite{RFC2741}) and make the routing protocol MIBs available through it. +Note that SNMP Support needs to be enabled at compile-time and loaded as +module on daemon startup. Refer to @ref{Loadable Module Support} on +the latter. + @menu * Getting and installing an SNMP agent:: * AgentX configuration:: diff --git a/doc/watchfrr.8.in b/doc/watchfrr.8.in index 813f87abd..82098e1b0 100644 --- a/doc/watchfrr.8.in +++ b/doc/watchfrr.8.in @@ -108,13 +108,13 @@ Set the logging (LOG_DEBUG), but higher number can be supplied if extra debugging messages are required. .TP -.BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number +.BI \-\-min\-restart\-interval " number Set the minimum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "60"). .TP -.BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number +.BI \-\-max\-restart\-interval " number Set the maximum .I number of seconds to wait between invocations of the daemon restart commands (the diff --git a/doc/zebra.8.in b/doc/zebra.8.in index 4599a8563..f5b8bd4d8 100644 --- a/doc/zebra.8.in +++ b/doc/zebra.8.in @@ -23,6 +23,9 @@ zebra \- a routing manager for use with associated @PACKAGE_FULLNAME@ components ] [ .B \-g .I group +] [ +.B \-M +.I module:options ] .SH DESCRIPTION .B zebra @@ -86,6 +89,14 @@ maximum before starting zebra. Note that this affects Linux only. .TP +\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR +Load a module at startup. May be specified more than once. +The \fBsnmp\fR and \fBfpm\fR modules may be +available for \fBzebra\fR, if the package was built with SNMP and FPM support +respectively. The \fBfpm\fR module takes an additional colon-separated +argument specifying the encapsulation, either \fBnetlink\fR or \fBprotobuf\fR. +It should thus be loaded with \fB-M fpm:netlink\fR or \fB-M fpm:protobuf\fR. +.TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 6ec7771ec..dd07a9c6f 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -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) { diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index db46078f2..554fa563a 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -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; } } diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 830ccb37c..b04d0db3c 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -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); diff --git a/isisd/isisd.c b/isisd/isisd.c index 2863d2f67..f226c4a1f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -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 diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am index 42e54138a..19f819ae3 100644 --- a/ldpd/Makefile.am +++ b/ldpd/Makefile.am @@ -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@ diff --git a/ldpd/address.c b/ldpd/address.c index ad23ca690..584240de8 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -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); diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 2e7b43296..8659202ee 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -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); } diff --git a/ldpd/control.c b/ldpd/control.c index 0bfe0abc9..5c530e1b7 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -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: diff --git a/ldpd/hello.c b/ldpd/hello.c index e7935899b..dd67f68f7 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -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 diff --git a/ldpd/init.c b/ldpd/init.c index bc3a69edc..8b2abe85e 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -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 diff --git a/ldpd/interface.c b/ldpd/interface.c index 8fea91b87..b7f473d39 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -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 diff --git a/ldpd/keepalive.c b/ldpd/keepalive.c index f9a7d850f..ba5f22331 100644 --- a/ldpd/keepalive.c +++ b/ldpd/keepalive.c @@ -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 diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 3f4e21e68..92d865210 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -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,27 +125,13 @@ 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)); @@ -153,6 +139,14 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname) } 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) { struct l2vpn *l2vpn = lif->l2vpn; @@ -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,41 +188,49 @@ 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) { struct fec fec; @@ -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); } @@ -504,37 +475,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) { struct l2vpn *l2vpn; diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index e8ce7fbdf..f53bc8333 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -26,13 +26,13 @@ #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); } diff --git a/ldpd/lde.c b/ldpd/lde.c index 08339c720..d8a2924b3 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -33,6 +33,10 @@ #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) @@ -93,6 +106,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; +} diff --git a/ldpd/lde.h b/ldpd/lde.h index b5bcb42c8..57791cd1b 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -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); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 4444a1e1a..db2682a17 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -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)); } } diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h index b0dc29143..8510a394e 100644 --- a/ldpd/ldp_vty.h +++ b/ldpd/ldp_vty.h @@ -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_ */ diff --git a/ldpd/ldp_vty.xml b/ldpd/ldp_vty.xml index 966b634c2..cd5c92c7b 100644 --- a/ldpd/ldp_vty.xml +++ b/ldpd/ldp_vty.xml @@ -333,11 +333,17 @@ <!-- 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"/> @@ -347,8 +353,17 @@ <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"> diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index 4d1af6214..e4fc7b005 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -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); } diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index 56a64c84f..a149b7fe3 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -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(¶ms, 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, ¶ms)); } @@ -967,9 +1628,18 @@ ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[]) memset(¶ms, 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, ¶ms)); } @@ -1006,6 +1676,58 @@ ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[]) } 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[]) { struct imsgbuf ibuf; @@ -1015,8 +1737,18 @@ ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[]) return (CMD_WARNING); memset(¶ms, 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, ¶ms)); } diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index c41a0dbd9..702b5c5ea 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -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) { diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 98ea5ca53..9729499e2 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -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); } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 0a7e1177b..d2fc5aa3a 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -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); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 3bb84e92a..1bec3d2a9 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -88,6 +88,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); @@ -820,6 +826,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; struct adj *adj; diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 22b75eb00..a3f41a8b9 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -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 *); diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 077d47285..9a92a00d3 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -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) { diff --git a/ldpd/notification.c b/ldpd/notification.c index 393994ed5..f10faa4a5 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -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); diff --git a/ldpd/packet.c b/ldpd/packet.c index a7be0f6b4..46893b992 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -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; diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c index 88a778ccc..a1a79dabf 100644 --- a/ldpd/pfkey.c +++ b/ldpd/pfkey.c @@ -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, diff --git a/lib/Makefile.am b/lib/Makefile.am index 55b1eb804..c4989c73c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -20,7 +20,7 @@ libfrr_la_SOURCES = \ command.c \ sockunion.c prefix.c thread.c if.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c log.c plist.c \ - zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ + zclient.c sockopt.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \ ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \ imsg-buffer.c imsg.c skiplist.c \ @@ -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 diff --git a/lib/agentx.c b/lib/agentx.c index 4175e7ba9..11d5c9385 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -21,7 +21,7 @@ #include <zebra.h> -#if defined HAVE_SNMP && defined SNMP_AGENTX +#ifdef SNMP_AGENTX #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> @@ -315,4 +315,4 @@ smux_trap (struct variable *vp, size_t vp_len, return 1; } -#endif /* HAVE_SNMP */ +#endif /* SNMP_AGENTX */ @@ -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) diff --git a/lib/command.c b/lib/command.c index cae848a5c..f0d7a64eb 100644 --- a/lib/command.c +++ b/lib/command.c @@ -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) { diff --git a/lib/distribute.c b/lib/distribute.c index 2e76e352c..01c338f17 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -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 index 000000000..183790aeb --- /dev/null +++ b/lib/frratomic.h @@ -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 */ diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index e3a7c979f..97de94321 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -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 index 000000000..04d803cd8 --- /dev/null +++ b/lib/hook.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "memory.h" +#include "hook.h" + +DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry") + +void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg, + struct frrmod_runtime *module, const char *funcname) +{ + struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)); + he->hookfn = funcptr; + he->hookarg = arg; + he->has_arg = has_arg; + he->module = module; + he->fnname = funcname; + + he->next = hook->entries; + hook->entries = he; +} + +void _hook_unregister(struct hook *hook, void *funcptr, + void *arg, bool has_arg) +{ + struct hookent *he, **prev; + + for (prev = &hook->entries; (he = *prev) != NULL; prev = &he->next) + if (he->hookfn == funcptr && he->hookarg == arg + && he->has_arg == has_arg) + { + *prev = he->next; + XFREE(MTYPE_HOOK_ENTRY, he); + break; + } +} + diff --git a/lib/hook.h b/lib/hook.h new file mode 100644 index 000000000..0cb7ab5c7 --- /dev/null +++ b/lib/hook.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _FRR_HOOK_H +#define _FRR_HOOK_H + +#include <stdbool.h> + +#include "module.h" +#include "memory.h" + +/* type-safe subscribable hook points + * + * where "type-safe" applies to the function pointers used for subscriptions + * + * overall usage: + * - to create a hook: + * + * mydaemon.h: + * #include "hook.h" + * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * + * mydaemon.c: + * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * ... + * hook_call (some_update_event, info) + * + * Note: the second and third macro args must be the hook function's + * parameter list, with the same names for each parameter. The second + * macro arg is with types (used for defining things), the third arg is + * just the names (used for passing along parameters). + * + * Do not use parameter names starting with "hook", these can collide with + * names used by the hook code itself. + * + * The return value is always "int" for now; hook_call will sum up the + * return values from each registered user. Default is 0. + * + * There are no pre-defined semantics for the value, in most cases it is + * ignored. For success/failure indication, 0 should be success, and + * handlers should make sure to only return 0 or 1 (not -1 or other values). + * + * + * - to use a hook / create a handler: + * + * #include "mydaemon.h" + * int event_handler (struct eventinfo *info) { ... } + * hook_register (some_update_event, event_handler); + * + * or, if you need an argument to be passed along (addonptr will be added + * as first argument when calling the handler): + * + * #include "mydaemon.h" + * int event_handler (void *addonptr, struct eventinfo *info) { ... } + * hook_register_arg (some_update_event, event_handler, addonptr); + * + * (addonptr isn't typesafe, but that should be manageable.) + */ + +/* TODO: + * - hook_unregister_all_module() + * - introspection / CLI / debug + * - testcases ;) + * + * For loadable modules, the idea is that hooks could be automatically + * unregistered when a module is unloaded. + * + * It's also possible to add a constructor (MTYPE style) to DEFINE_HOOK, + * which would make it possible for the CLI to show all hooks and all + * registered handlers. + */ + +struct hookent { + struct hookent *next; + void *hookfn; /* actually a function pointer */ + void *hookarg; + bool has_arg; + struct frrmod_runtime *module; + const char *fnname; +}; + +struct hook { + const char *name; + struct hookent *entries; +}; + +/* subscribe/add callback function to a hook + * + * always use hook_register(), which uses the static inline helper from + * DECLARE_HOOK in order to get type safety + */ +extern void _hook_register(struct hook *hook, void *funcptr, void *arg, + bool has_arg, struct frrmod_runtime *module, + const char *funcname); +#define hook_register(hookname, func) \ + _hook_register(&_hook_ ## hookname, \ + _hook_typecheck_ ## hookname (func), \ + NULL, false, THIS_MODULE, #func) +#define hook_register_arg(hookname, func, arg) \ + _hook_register(&_hook_ ## hookname, \ + _hook_typecheck_arg_ ## hookname (func), \ + arg, true, THIS_MODULE, #func) + +extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, + bool has_arg); +#define hook_unregister(hookname, func) \ + _hook_unregister(&_hook_ ## hookname, \ + _hook_typecheck_ ## hookname (func), NULL, false) +#define hook_unregister_arg(hookname, func, arg) \ + _hook_unregister(&_hook_ ## hookname, \ + _hook_typecheck_arg_ ## hookname (func), arg, true) + +/* invoke hooks + * this is private (static) to the file that has the DEFINE_HOOK statement + */ +#define hook_call(hookname, ...) \ + hook_call_ ## hookname (__VA_ARGS__) + +/* helpers to add the void * arg */ +#define HOOK_ADDDEF(...) (void *hookarg , ## __VA_ARGS__) +#define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__) + +/* use in header file - declares the hook and its arguments + * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2)) + * as above, "passlist" must use the same order and same names as "arglist" + * + * theoretically passlist is not neccessary, but let's keep things simple and + * use exact same args on DECLARE and DEFINE. + */ +#define DECLARE_HOOK(hookname, arglist, passlist) \ + extern struct hook _hook_ ## hookname; \ + __attribute__((unused)) \ + static void *_hook_typecheck_ ## hookname ( \ + int (*funcptr) arglist) { \ + return (void *)funcptr; } \ + __attribute__((unused)) \ + static void *_hook_typecheck_arg_ ## hookname ( \ + int (*funcptr) HOOK_ADDDEF arglist) { \ + return (void *)funcptr; } + +/* use in source file - contains hook-related definitions. + */ +#define DEFINE_HOOK(hookname, arglist, passlist) \ + struct hook _hook_ ## hookname = { \ + .name = #hookname, \ + .entries = NULL, \ + }; \ + static int hook_call_ ## hookname arglist { \ + int hooksum = 0; \ + struct hookent *he = _hook_ ## hookname .entries; \ + void *hookarg; \ + union { \ + void *voidptr; \ + int (*fptr) arglist; \ + int (*farg) HOOK_ADDDEF arglist; \ + } hookp; \ + for (; he; he = he->next) { \ + hookarg = he->hookarg; \ + hookp.voidptr = he->hookfn; \ + if (!he->has_arg) \ + hooksum += hookp.fptr passlist; \ + else \ + hooksum += hookp.farg HOOK_ADDARG passlist; \ + } \ + return hooksum; \ + } + +#endif /* _FRR_HOOK_H */ @@ -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 */ @@ -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); diff --git a/lib/keychain.c b/lib/keychain.c index cd8039b95..95a2c8e59 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -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" diff --git a/lib/libfrr.c b/lib/libfrr.c index b7ce0679c..64f8be2ca 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -28,6 +28,9 @@ #include "memory_vty.h" #include "zclient.h" #include "log_int.h" +#include "module.h" + +DEFINE_HOOK(frr_late_init, (struct thread_master *tm), (tm)) const char frr_sysconfdir[] = SYSCONFDIR; const char frr_vtydir[] = DAEMON_VTY_DIR; @@ -64,14 +67,16 @@ static const struct option lo_always[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, { NULL } }; static const struct optspec os_always = { - "hvdi:", + "hvdM:", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" + " -M, --module Load specified module\n" " --vty_socket Override vty socket path\n", lo_always }; @@ -184,12 +189,18 @@ void frr_help_exit(int status) exit(status); } +struct option_chain { + struct option_chain *next; + const char *arg; +}; +static struct option_chain *modules = NULL, **modnext = &modules; static int errors = 0; static int frr_opt(int opt) { static int vty_port_set = 0; static int vty_addr_set = 0; + struct option_chain *oc; char *err; switch (opt) { @@ -203,6 +214,13 @@ static int frr_opt(int opt) case 'd': di->daemon_mode = 1; break; + case 'M': + oc = XMALLOC(MTYPE_TMP, sizeof(*oc)); + oc->arg = optarg; + oc->next = NULL; + *modnext = oc; + modnext = &oc->next; + break; case 'i': if (di->flags & FRR_NO_CFG_PID_DRY) return 1; @@ -295,9 +313,12 @@ int frr_getopt(int argc, char * const argv[], int *longindex) return opt; } +static struct thread_master *master; struct thread_master *frr_init(void) { - struct thread_master *master; + struct option_chain *oc; + struct frrmod_runtime *module; + char moderr[256]; srandom(time(NULL)); @@ -307,6 +328,17 @@ struct thread_master *frr_init(void) zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl); #endif + frrmod_init(di->module); + while (modules) { + modules = (oc = modules)->next; + module = frrmod_load(oc->arg, moderr, sizeof(moderr)); + if (!module) { + fprintf(stderr, "%s\n", moderr); + exit(1); + } + XFREE(MTYPE_TMP, oc); + } + zprivs_init(di->privs); master = thread_master_create(); @@ -324,6 +356,8 @@ struct thread_master *frr_init(void) void frr_config_fork(void) { + hook_call(frr_late_init, master); + if (di->instance) { snprintf(config_default, sizeof(config_default), "%s/%s-%d.conf", frr_sysconfdir, di->name, di->instance); diff --git a/lib/libfrr.h b/lib/libfrr.h index d37f406f5..a40fc3489 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -26,6 +26,8 @@ #include "thread.h" #include "log.h" #include "getopt.h" +#include "module.h" +#include "hook.h" #define FRR_NO_PRIVSEP (1 << 0) #define FRR_NO_TCPVTY (1 << 1) @@ -40,6 +42,7 @@ struct frr_daemon_info { const char *name; const char *logname; unsigned short instance; + struct frrmod_runtime *module; char *vty_addr; int vty_port; @@ -67,15 +70,22 @@ struct frr_daemon_info { * i.e. "ZEBRA" or "BGP" * * note that this macro is also a latch-on point for other changes (e.g. - * upcoming plugin support) that need to place some per-daemon things. Each + * upcoming module support) that need to place some per-daemon things. Each * daemon should have one of these. */ #define FRR_DAEMON_INFO(execname, constname, ...) \ static struct frr_daemon_info execname ##_di = { \ .name = # execname, \ .logname = # constname, \ + .module = THIS_MODULE, \ __VA_ARGS__ \ - }; + }; \ + FRR_COREMOD_SETUP( \ + .name = # execname, \ + .description = # execname " daemon", \ + .version = FRR_VERSION, \ + ) \ + /* end */ extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv); @@ -86,6 +96,7 @@ extern void frr_help_exit(int status); extern struct thread_master *frr_init(void); +DECLARE_HOOK(frr_late_init, (struct thread_master *tm), (tm)) extern void frr_config_fork(void); extern void frr_vty_serv(void); @@ -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; diff --git a/lib/memory.c b/lib/memory.c index ad55366f6..c6207adb9 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -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); } diff --git a/lib/memory.h b/lib/memory.h index 477a6162d..9e8803a8b 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -18,23 +18,22 @@ #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 */ diff --git a/lib/memory_vty.c b/lib/memory_vty.c index 149b32913..6d63bc2d5 100644 --- a/lib/memory_vty.c +++ b/lib/memory_vty.c @@ -1,23 +1,22 @@ /* - * Memory management routine - * Copyright (C) 1998 Kunihiro Ishiguro + * Memory and dynamic module VTY routine * - * This file is part of GNU Zebra. + * Copyright (C) 1998 Kunihiro Ishiguro + * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc. * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA */ #include <zebra.h> @@ -25,9 +24,12 @@ #if (defined(GNU_LINUX) && defined(HAVE_MALLINFO)) #include <malloc.h> #endif /* HAVE_MALLINFO */ +#include <dlfcn.h> +#include <link.h> #include "log.h" #include "memory.h" +#include "module.h" #include "memory_vty.h" /* Looking up memory status from vty interface. */ @@ -110,10 +112,55 @@ DEFUN (show_memory, return CMD_SUCCESS; } +DEFUN (show_modules, + show_modules_cmd, + "show modules", + "Show running system information\n" + "Loaded modules\n") +{ + struct frrmod_runtime *plug = frrmod_list; + + vty_out (vty, "%-12s %-25s %s%s%s", + "Module Name", "Version", "Description", + VTY_NEWLINE, VTY_NEWLINE); + while (plug) + { + const struct frrmod_info *i = plug->info; + + vty_out (vty, "%-12s %-25s %s%s", i->name, i->version, i->description, + VTY_NEWLINE); + if (plug->dl_handle) + { +#ifdef HAVE_DLINFO_ORIGIN + char origin[MAXPATHLEN] = ""; + dlinfo (plug->dl_handle, RTLD_DI_ORIGIN, &origin); +# ifdef HAVE_DLINFO_LINKMAP + const char *name; + struct link_map *lm = NULL; + dlinfo (plug->dl_handle, RTLD_DI_LINKMAP, &lm); + if (lm) + { + name = strrchr(lm->l_name, '/'); + name = name ? name + 1 : lm->l_name; + vty_out (vty, "\tfrom: %s/%s%s", origin, name, VTY_NEWLINE); + } +# else + vty_out (vty, "\tfrom: %s %s", origin, plug->load_name, VTY_NEWLINE); +# endif +#else + vty_out (vty, "\tfrom: %s%s", plug->load_name, VTY_NEWLINE); +#endif + } + plug = plug->next; + } + return CMD_SUCCESS; +} + void memory_init (void) { install_element (VIEW_NODE, &show_memory_cmd); + install_element (VIEW_NODE, &show_modules_cmd); } /* Stats querying from users */ diff --git a/lib/module.c b/lib/module.c new file mode 100644 index 000000000..4ebe3c0da --- /dev/null +++ b/lib/module.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <dlfcn.h> + +#include "module.h" +#include "memory.h" +#include "version.h" + +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") + +static struct frrmod_info frrmod_default_info = { + .name = "libfrr", + .version = FRR_VERSION, + .description = "libfrr core module", +}; +union _frrmod_runtime_u frrmod_default = { + .r.info = &frrmod_default_info, + .r.finished_loading = 1, +}; + +// if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) +// union _frrmod_runtime_u _frrmod_this_module +// __attribute__((weak, alias("frrmod_default"))); +// elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) +#pragma weak _frrmod_this_module = frrmod_default +// else +// error need weak symbol support +// endif + +struct frrmod_runtime *frrmod_list = &frrmod_default.r; +static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next; +static const char *execname = NULL; + +void frrmod_init(struct frrmod_runtime *modinfo) +{ + modinfo->finished_loading = 1; + *frrmod_last = modinfo; + frrmod_last = &modinfo->next; + + execname = modinfo->info->name; +} + +struct frrmod_runtime *frrmod_load(const char *spec, + char *err, size_t err_len) +{ + void *handle = NULL; + char name[PATH_MAX], fullpath[PATH_MAX], *args; + struct frrmod_runtime *rtinfo, **rtinfop; + const struct frrmod_info *info; + + snprintf(name, sizeof(name), "%s", spec); + args = strchr(name, ':'); + if (args) + *args++ = '\0'; + + if (!strchr(name, '/')) { + if (!handle && execname) { + snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", + MODULE_PATH, execname, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s/%s.so", + MODULE_PATH, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s", name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + if (err) + snprintf(err, err_len, + "loading module \"%s\" failed: %s", + name, dlerror()); + return NULL; + } + + rtinfop = dlsym(handle, "frr_module"); + if (!rtinfop) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "\"%s\" is not a Quagga module: %s", + name, dlerror()); + return NULL; + } + rtinfo = *rtinfop; + rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name); + rtinfo->dl_handle = handle; + if (args) + rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args); + info = rtinfo->info; + + if (rtinfo->finished_loading) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" already loaded", + name); + goto out_fail; + } + + if (info->init && info->init()) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" initialisation failed", + name); + goto out_fail; + } + + rtinfo->finished_loading = 1; + + *frrmod_last = rtinfo; + frrmod_last = &rtinfo->next; + return rtinfo; + +out_fail: + if (rtinfo->load_args) + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + return NULL; +} + +#if 0 +void frrmod_unload(struct frrmod_runtime *module) +{ +} +#endif diff --git a/lib/module.h b/lib/module.h new file mode 100644 index 000000000..cb66e6097 --- /dev/null +++ b/lib/module.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _FRR_MODULE_H +#define _FRR_MODULE_H + +#include <stdint.h> +#include <stdbool.h> + +#if !defined(__GNUC__) +# error module code needs GCC visibility extensions +#elif __GNUC__ < 4 +# error module code needs GCC visibility extensions +#else +# define DSO_PUBLIC __attribute__ ((visibility ("default"))) +# define DSO_SELF __attribute__ ((visibility ("protected"))) +# define DSO_LOCAL __attribute__ ((visibility ("hidden"))) +#endif + +struct frrmod_runtime; + +struct frrmod_info { + /* single-line few-word title */ + const char *name; + /* human-readable version number, should not contain spaces */ + const char *version; + /* one-paragraph description */ + const char *description; + + int (*init)(void); +}; + +/* primary entry point structure to be present in loadable module under + * "_frrmod_this_module" dlsym() name + * + * note space for future extensions is reserved below, so other modules + * (e.g. memory management, hooks) can add fields + * + * const members/info are in frrmod_info. + */ +struct frrmod_runtime { + struct frrmod_runtime *next; + + const struct frrmod_info *info; + void *dl_handle; + bool finished_loading; + + char *load_name; + char *load_args; +}; + +/* space-reserving foo */ +struct _frrmod_runtime_size { + struct frrmod_runtime r; + /* this will barf if frrmod_runtime exceeds 1024 bytes ... */ + uint8_t space[1024 - sizeof(struct frrmod_runtime)]; +}; +union _frrmod_runtime_u { + struct frrmod_runtime r; + struct _frrmod_runtime_size s; +}; + +extern union _frrmod_runtime_u _frrmod_this_module; +#define THIS_MODULE (&_frrmod_this_module.r) + +#define FRR_COREMOD_SETUP(...) \ + static const struct frrmod_info _frrmod_info = { __VA_ARGS__ }; \ + DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \ + .r.info = &_frrmod_info, \ + }; +#define FRR_MODULE_SETUP(...) \ + FRR_COREMOD_SETUP(__VA_ARGS__) \ + DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; + +extern struct frrmod_runtime *frrmod_list; + +extern void frrmod_init(struct frrmod_runtime *modinfo); +extern struct frrmod_runtime *frrmod_load(const char *spec, + char *err, size_t err_len); +#if 0 +/* not implemented yet */ +extern void frrmod_unload(struct frrmod_runtime *module); +#endif + +#endif /* _FRR_MODULE_H */ diff --git a/lib/mpls.h b/lib/mpls.h index b5c1a653b..13a46e101 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -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 @@ -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" diff --git a/lib/privs.c b/lib/privs.c index 376d6f336..decd4bb7d 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -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", diff --git a/lib/routemap.c b/lib/routemap.c index 1647ac366..cd34ffaae 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -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 diff --git a/lib/sigevent.c b/lib/sigevent.c index a120028d8..b2059a17b 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -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) @@ -326,6 +339,11 @@ trap_default_signals(void) 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) zlog_warn("Unable to set signal handler for signal %d: %s", diff --git a/lib/smux.c b/lib/smux.c index 3abfadcd2..370b8f138 100644 --- a/lib/smux.c +++ b/lib/smux.c @@ -21,7 +21,7 @@ #include <zebra.h> -#if defined HAVE_SNMP && defined SNMP_SMUX +#ifdef SNMP_SMUX #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -1445,4 +1445,4 @@ smux_start(void) /* Schedule first connection. */ smux_event (SMUX_SCHEDULE, 0); } -#endif /* HAVE_SNMP */ +#endif /* SNMP_SMUX */ diff --git a/lib/snmp.c b/lib/snmp.c index f6f9845e2..1cbd41c72 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -21,7 +21,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -130,4 +129,3 @@ smux_header_table (struct variable *v, oid *name, size_t *length, int exact, return MATCH_SUCCEEDED; } -#endif /* HAVE_SNMP */ diff --git a/lib/thread.c b/lib/thread.c index 6138e7971..e707fc584 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1037,28 +1037,6 @@ thread_process_fds_helper (struct thread_master *m, struct thread *thread, threa #if defined(HAVE_POLL) -#if defined(HAVE_SNMP) -/* add snmp fds to poll set */ -static void -add_snmp_pollfds(struct thread_master *m, fd_set *snmpfds, int fdsetsize) -{ - int i; - m->handler.pfdcountsnmp = m->handler.pfdcount; - /* cycle trough fds and add neccessary fds to poll set */ - for (i=0;i<fdsetsize;++i) - { - if (FD_ISSET(i, snmpfds)) - { - assert (m->handler.pfdcountsnmp <= m->handler.pfdsize); - - m->handler.pfds[m->handler.pfdcountsnmp].fd = i; - m->handler.pfds[m->handler.pfdcountsnmp].events = POLLIN; - m->handler.pfdcountsnmp++; - } - } -} -#endif - /* check poll events */ static void check_pollfds(struct thread_master *m, fd_set *readfd, int num) diff --git a/lib/version.h.in b/lib/version.h.in index adc827818..d9eabb9f8 100644 --- a/lib/version.h.in +++ b/lib/version.h.in @@ -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@" @@ -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" @@ -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 diff --git a/lib/zclient.c b/lib/zclient.c index 859751deb..71b95ae7d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -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 diff --git a/lib/zclient.h b/lib/zclient.h index 89fc865c7..d3d0a202c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -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 diff --git a/m4/.gitignore b/m4/.gitignore index 3f3bd0a73..798188b0b 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -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 index 000000000..d383ad5c6 --- /dev/null +++ b/m4/ax_pthread.m4 @@ -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 index 000000000..3d4d56d58 --- /dev/null +++ b/nhrpd/.gitignore @@ -0,0 +1 @@ +nhrpd diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index a418ecabd..76419a7ff 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -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; diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 4ac612d3a..bbaa630cd 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -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: diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index 5d2866a67..36dbdfd77 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -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); diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 73b6aaccf..4c1d97a48 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -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); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 8d066eeae..69c55e305 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -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)) diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index 06fc7a30a..75dd8ffe4 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -7,6 +7,7 @@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libospf6.a +module_LTLIBRARIES = sbin_PROGRAMS = ospf6d libospf6_a_SOURCES = \ @@ -14,7 +15,7 @@ libospf6_a_SOURCES = \ ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ - ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c ospf6_snmp.c \ + ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c \ ospf6d.c ospf6_bfd.c noinst_HEADERS = \ @@ -22,7 +23,7 @@ noinst_HEADERS = \ ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ - ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h ospf6_snmp.h \ + ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h \ ospf6d.h ospf6_bfd.h ospf6d_SOURCES = \ @@ -30,5 +31,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 diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5f2d662b7..8caae5022 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -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) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 8998799cf..8cf7f4afa 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -41,12 +41,14 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_spf.h" -#include "ospf6_snmp.h" #include "ospf6d.h" #include "ospf6_bfd.h" DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names") DEFINE_QOBJ_TYPE(ospf6_interface) +DEFINE_HOOK(ospf6_interface_change, + (struct ospf6_interface *oi, int state, int old_state), + (oi, state, old_state)) unsigned char conf_debug_ospf6_interface = 0; @@ -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; diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 179477a63..846cde419 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -23,6 +23,7 @@ #define OSPF6_INTERFACE_H #include "qobj.h" +#include "hook.h" #include "if.h" /* Debug option */ @@ -182,4 +183,8 @@ extern void install_element_ospf6_clear_interface (void); extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); +DECLARE_HOOK(ospf6_interface_change, + (struct ospf6_interface *oi, int state, int old_state), + (oi, state, old_state)) + #endif /* OSPF6_INTERFACE_H */ diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index d93406fb6..646196385 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -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); } diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index ec79a1552..118210dfc 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -38,7 +38,6 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_flood.h" -#include "ospf6_snmp.h" #include "ospf6d.h" #include "ospf6_bfd.h" #include "ospf6_abr.h" @@ -47,6 +46,10 @@ #include "ospf6_spf.h" #include "ospf6_zebra.h" +DEFINE_HOOK(ospf6_neighbor_change, + (struct ospf6_neighbor *on, int state, int next_state), + (on, state, next_state)) + unsigned char conf_debug_ospf6_neighbor = 0; const char *ospf6_neighbor_state_str[] = @@ -202,13 +205,7 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int e next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((next_state == OSPF6_NEIGHBOR_FULL) || - (next_state == OSPF6_NEIGHBOR_TWOWAY) || - (next_state < prev_state)) - ospf6TrapNbrStateChange (on); -#endif + hook_call(ospf6_neighbor_change, on, next_state, prev_state); ospf6_bfd_trigger_event(on, prev_state, next_state); } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index f9e197e99..c275ff830 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -22,6 +22,8 @@ #ifndef OSPF6_NEIGHBOR_H #define OSPF6_NEIGHBOR_H +#include "hook.h" + /* Debug option */ extern unsigned char conf_debug_ospf6_neighbor; #define OSPF6_DEBUG_NEIGHBOR_STATE 0x01 @@ -179,4 +181,8 @@ extern void ospf6_neighbor_init (void); extern int config_write_ospf6_debug_neighbor (struct vty *vty); extern void install_element_ospf6_debug_neighbor (void); +DECLARE_HOOK(ospf6_neighbor_change, + (struct ospf6_neighbor *on, int state, int next_state), + (on, state, next_state)) + #endif /* OSPF6_NEIGHBOR_H */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 29956c61a..b8e5ca619 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -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); diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 86cfd17c8..96f1e3dd2 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -21,8 +21,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP - #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -32,6 +30,8 @@ #include "vector.h" #include "vrf.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -45,7 +45,6 @@ #include "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6d.h" -#include "ospf6_snmp.h" /* OSPFv3-MIB */ #define OSPFv3MIB 1,3,6,1,2,1,191 @@ -1139,11 +1138,18 @@ static struct trap_object ospf6IfTrapList[] = {4, {1, 7, 1, OSPFv3IFAREAID}} }; -void -ospf6TrapNbrStateChange (struct ospf6_neighbor *on) +static int +ospf6TrapNbrStateChange (struct ospf6_neighbor *on, + int next_state, int prev_state) { oid index[3]; + /* Terminal state or regression */ + if ((next_state != OSPF6_NEIGHBOR_FULL) && + (next_state != OSPF6_NEIGHBOR_TWOWAY) && + (next_state >= prev_state)) + return 0; + index[0] = on->ospf6_if->interface->ifindex; index[1] = on->ospf6_if->instance_id; index[2] = ntohl (on->router_id); @@ -1155,13 +1161,23 @@ ospf6TrapNbrStateChange (struct ospf6_neighbor *on) ospf6NbrTrapList, sizeof ospf6NbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); + return 0; } -void -ospf6TrapIfStateChange (struct ospf6_interface *oi) +static int +ospf6TrapIfStateChange (struct ospf6_interface *oi, + int next_state, int prev_state) { oid index[2]; + /* Terminal state or regression */ + if ((next_state != OSPF6_INTERFACE_POINTTOPOINT) && + (next_state != OSPF6_INTERFACE_DROTHER) && + (next_state != OSPF6_INTERFACE_BDR) && + (next_state != OSPF6_INTERFACE_DR) && + (next_state >= prev_state)) + return 0; + index[0] = oi->interface->ifindex; index[1] = oi->instance_id; @@ -1172,15 +1188,30 @@ ospf6TrapIfStateChange (struct ospf6_interface *oi) ospf6IfTrapList, sizeof ospf6IfTrapList / sizeof (struct trap_object), IFSTATECHANGE); + return 0; } /* Register OSPFv3-MIB. */ -void +static int ospf6_snmp_init (struct thread_master *master) { smux_init (master); REGISTER_MIB ("OSPFv3MIB", ospfv3_variables, variable, ospfv3_oid); + return 0; } -#endif /* HAVE_SNMP */ +static int +ospf6_snmp_module_init (void) +{ + hook_register(ospf6_interface_change, ospf6TrapIfStateChange); + hook_register(ospf6_neighbor_change, ospf6TrapNbrStateChange); + hook_register(frr_late_init, ospf6_snmp_init); + return 0; +} +FRR_MODULE_SETUP( + .name = "ospf6d_snmp", + .version = FRR_VERSION, + .description = "ospf6d AgentX SNMP module", + .init = ospf6_snmp_module_init, +) diff --git a/ospf6d/ospf6_snmp.h b/ospf6d/ospf6_snmp.h deleted file mode 100644 index fa1b0c37a..000000000 --- a/ospf6d/ospf6_snmp.h +++ /dev/null @@ -1,31 +0,0 @@ -/* OSPFv3 SNMP support - * Copyright (C) 2004 Yasuhiro Ohara - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef OSPF6_SNMP_H -#define OSPF6_SNMP_H - -extern void ospf6TrapNbrStateChange (struct ospf6_neighbor *); -extern void ospf6TrapIfStateChange (struct ospf6_interface *); -extern void ospf6_snmp_init (struct thread_master *); - -#endif /*OSPF6_SNMP_H*/ - - diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 92111c73f..f2a1c8c2e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -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); } diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 2aaed5fcb..036cc6d4c 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -45,10 +45,6 @@ #include "ospf6d.h" #include "ospf6_bfd.h" -#ifdef HAVE_SNMP -#include "ospf6_snmp.h" -#endif /*HAVE_SNMP*/ - char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION; struct route_node * @@ -1215,10 +1211,6 @@ ospf6_init (void) ospf6_asbr_init (); ospf6_abr_init (); -#ifdef HAVE_SNMP - ospf6_snmp_init (master); -#endif /*HAVE_SNMP*/ - ospf6_bfd_init(); install_node (&debug_node, config_write_ospf6_debug); diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 71e0df0dc..c6a5ec91d 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -6,13 +6,14 @@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 noinst_LIBRARIES = libfrrospf.a +module_LTLIBRARIES = sbin_PROGRAMS = ospfd libfrrospf_a_SOURCES = \ ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ - ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ + ospf_lsdb.c ospf_asbr.c ospf_routemap.c \ ospf_opaque.c ospf_te.c ospf_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c \ ospf_bfd.c ospf_memory.c ospf_dump_api.c @@ -26,13 +27,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) diff --git a/ospfd/ospf_dump_api.c b/ospfd/ospf_dump_api.c index 20e7740d3..5ef262ce5 100644 --- a/ospfd/ospf_dump_api.c +++ b/ospfd/ospf_dump_api.c @@ -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 diff --git a/ospfd/ospf_dump_api.h b/ospfd/ospf_dump_api.h index c3ff1e3f5..1cd8257f0 100644 --- a/ospfd/ospf_dump_api.h +++ b/ospfd/ospf_dump_api.h @@ -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 diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 936ec6966..b4a282a52 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -47,11 +47,10 @@ #include "ospfd/ospf_abr.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_dump.h" -#ifdef HAVE_SNMP -#include "ospfd/ospf_snmp.h" -#endif /* HAVE_SNMP */ DEFINE_QOBJ_TYPE(ospf_interface) +DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data *vd), (vd)) +DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data *vd), (vd)) int ospf_if_get_output_cost (struct ospf_interface *oi) @@ -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); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index bd51bbf42..39202f777 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -24,6 +24,7 @@ #define _ZEBRA_OSPF_INTERFACE_H #include "qobj.h" +#include "hook.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" @@ -309,4 +310,7 @@ extern u_char ospf_default_iftype (struct interface *ifp); state of the interface. */ extern void ospf_if_set_multicast (struct ospf_interface *); +DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data *vd), (vd)) +DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data *vd), (vd)) + #endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 9630616ac..717c99c21 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -43,7 +43,10 @@ #include "ospfd/ospf_packet.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" -#include "ospfd/ospf_snmp.h" + +DEFINE_HOOK(ospf_ism_change, + (struct ospf_interface *oi, int state, int oldstate), + (oi, state, oldstate)) /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor * @@ -545,19 +548,7 @@ ism_change_state (struct ospf_interface *oi, int state) oi->state = state; oi->state_change++; -#ifdef HAVE_SNMP - /* Terminal state or regression */ - if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || - (state == ISM_PointToPoint) || (state < old_state)) - { - /* ospfVirtIfStateChange */ - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - ospfTrapVirtIfStateChange (oi); - /* ospfIfStateChange */ - else - ospfTrapIfStateChange (oi); - } -#endif + hook_call(ospf_ism_change, oi, state, old_state); /* Set multicast memberships appropriately for new state. */ ospf_if_set_multicast(oi); diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index f0357a482..fa8e6d70f 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -24,6 +24,8 @@ #ifndef _ZEBRA_OSPF_ISM_H #define _ZEBRA_OSPF_ISM_H +#include "hook.h" + /* OSPF Interface State Machine Status. */ #define ISM_DependUpon 0 #define ISM_Down 1 @@ -35,10 +37,6 @@ #define ISM_DR 7 #define OSPF_ISM_STATE_MAX 8 -/* Because DR/DROther values are exhanged wrt RFC */ -#define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ - ((x) == ISM_DR) ? ISM_DROther : (x)) - /* OSPF Interface State Machine Event. */ #define ISM_NoEvent 0 #define ISM_InterfaceUp 1 @@ -111,4 +109,8 @@ extern int ospf_ism_event (struct thread *); extern void ism_change_status (struct ospf_interface *, int); extern int ospf_hello_timer (struct thread *thread); +DECLARE_HOOK(ospf_ism_change, + (struct ospf_interface *oi, int state, int oldstate), + (oi, state, oldstate)) + #endif /* _ZEBRA_OSPF_ISM_H */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index f462c207e..38718b35d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -225,9 +225,6 @@ main (int argc, char **argv) ospf_bfd_init(); ospf_route_map_init (); -#ifdef HAVE_SNMP - ospf_snmp_init (); -#endif /* HAVE_SNMP */ ospf_opaque_init (); /* Need to initialize the default ospf structure, so the interface mode diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 01617055c..97f3f6a38 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -48,9 +48,12 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" -#include "ospfd/ospf_snmp.h" #include "ospfd/ospf_bfd.h" +DEFINE_HOOK(ospf_nsm_change, + (struct ospf_neighbor *on, int state, int oldstate), + (on, state, oldstate)) + static void nsm_clear_adj (struct ospf_neighbor *); /* OSPF NSM Timer functions. */ @@ -838,35 +841,12 @@ ospf_nsm_event (struct thread *thread) /* If state is changed. */ if (next_state != nbr->state) { + int old_state = nbr->state; + nsm_notice_state_change (nbr, next_state, event); -#ifdef HAVE_SNMP - int send_trap_virt = 0; - int send_trap = 0; - /* Terminal state or regression */ - if ((next_state == NSM_Full) - || (next_state == NSM_TwoWay) - || (next_state < nbr->state)) - { - /* ospfVirtNbrStateChange */ - if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) - send_trap_virt = 1; - /* ospfNbrStateChange trap */ - else - /* To/From FULL, only managed by DR */ - if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) - || (nbr->oi->state == ISM_DR)) - send_trap = 1; - } -#endif nsm_change_state (nbr, next_state); -#ifdef HAVE_SNMP - if (send_trap_virt) { - ospfTrapVirtNbrStateChange(nbr); - } else if (send_trap) { - ospfTrapNbrStateChange(nbr); - } -#endif + hook_call(ospf_nsm_change, nbr, next_state, old_state); } /* Make sure timer is set. */ diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index 9b7e14a4a..4531f6ec7 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -24,6 +24,8 @@ #ifndef _ZEBRA_OSPF_NSM_H #define _ZEBRA_OSPF_NSM_H +#include "hook.h" + /* OSPF Neighbor State Machine State. */ #define NSM_DependUpon 0 #define NSM_Deleted 1 @@ -86,5 +88,9 @@ extern int ospf_db_summary_isempty (struct ospf_neighbor *); extern int ospf_db_summary_count (struct ospf_neighbor *); extern void ospf_db_summary_clear (struct ospf_neighbor *); +DECLARE_HOOK(ospf_nsm_change, + (struct ospf_neighbor *on, int state, int oldstate), + (on, state, oldstate)) + #endif /* _ZEBRA_OSPF_NSM_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index a0cc367cd..b7721adb3 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -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) diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 717dc25f9..db51abca2 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -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; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 4afbda878..32449d559 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -24,7 +24,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -35,6 +34,8 @@ #include "command.h" #include "memory.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -47,7 +48,7 @@ #include "ospfd/ospf_flood.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_dump.h" -#include "ospfd/ospf_snmp.h" +#include "ospfd/ospf_zebra.h" /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 @@ -205,6 +206,10 @@ #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR +/* Because DR/DROther values are exhanged wrt RFC */ +#define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ + ((x) == ISM_DR) ? ISM_DROther : (x)) + /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES @@ -1429,7 +1434,7 @@ ospf_snmp_if_free (struct ospf_snmp_if *osif) XFREE (MTYPE_TMP, osif); } -void +static int ospf_snmp_if_delete (struct interface *ifp) { struct listnode *node, *nnode; @@ -1441,12 +1446,13 @@ ospf_snmp_if_delete (struct interface *ifp) { list_delete_node (ospf_snmp_iflist, node); ospf_snmp_if_free (osif); - return; + break; } } + return 0; } -void +static int ospf_snmp_if_update (struct interface *ifp) { struct listnode *node; @@ -1511,6 +1517,7 @@ ospf_snmp_if_update (struct interface *ifp) osif->ifp = ifp; listnode_add_after (ospf_snmp_iflist, pn, osif); + return 0; } static int @@ -1914,7 +1921,7 @@ ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, static struct route_table *ospf_snmp_vl_table; -void +static int ospf_snmp_vl_add (struct ospf_vl_data *vl_data) { struct prefix_ls lp; @@ -1931,9 +1938,10 @@ ospf_snmp_vl_add (struct ospf_vl_data *vl_data) route_unlock_node (rn); rn->info = vl_data; + return 0; } -void +static int ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) { struct prefix_ls lp; @@ -1947,10 +1955,11 @@ ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); if (! rn) - return; + return 0; rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); + return 0; } static struct ospf_vl_data * @@ -2651,7 +2660,7 @@ static struct trap_object ospfVirtIfTrapList[] = {3, {9, 1, OSPFVIRTIFSTATE}} }; -void +static void ospfTrapNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2673,7 +2682,7 @@ ospfTrapNbrStateChange (struct ospf_neighbor *on) NBRSTATECHANGE); } -void +static void ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2692,7 +2701,29 @@ ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) VIRTNBRSTATECHANGE); } -void +static int +ospf_snmp_nsm_change (struct ospf_neighbor *nbr, + int next_state, int old_state) +{ + /* Terminal state or regression */ + if ((next_state == NSM_Full) + || (next_state == NSM_TwoWay) + || (next_state < old_state)) + { + /* ospfVirtNbrStateChange */ + if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) + ospfTrapVirtNbrStateChange(nbr); + /* ospfNbrStateChange trap */ + else + /* To/From FULL, only managed by DR */ + if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) + || (nbr->oi->state == ISM_DR)) + ospfTrapNbrStateChange(nbr); + } + return 0; +} + +static void ospfTrapIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2713,7 +2744,7 @@ ospfTrapIfStateChange (struct ospf_interface *oi) IFSTATECHANGE); } -void +static void ospfTrapVirtIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; @@ -2731,13 +2762,53 @@ ospfTrapVirtIfStateChange (struct ospf_interface *oi) sizeof ospfVirtIfTrapList / sizeof (struct trap_object), VIRTIFSTATECHANGE); } + +static int +ospf_snmp_ism_change (struct ospf_interface *oi, + int state, int old_state) +{ + /* Terminal state or regression */ + if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || + (state == ISM_PointToPoint) || (state < old_state)) + { + /* ospfVirtIfStateChange */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + ospfTrapVirtIfStateChange (oi); + /* ospfIfStateChange */ + else + ospfTrapIfStateChange (oi); + } + return 0; +} + /* Register OSPF2-MIB. */ -void -ospf_snmp_init () +static int +ospf_snmp_init (struct thread_master *tm) { ospf_snmp_iflist = list_new (); ospf_snmp_vl_table = route_table_init (); - smux_init (om->master); + smux_init (tm); REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); + return 0; +} + +static int +ospf_snmp_module_init (void) +{ + hook_register(ospf_if_update, ospf_snmp_if_update); + hook_register(ospf_if_delete, ospf_snmp_if_delete); + hook_register(ospf_vl_add, ospf_snmp_vl_add); + hook_register(ospf_vl_delete, ospf_snmp_vl_delete); + hook_register(ospf_ism_change, ospf_snmp_ism_change); + hook_register(ospf_nsm_change, ospf_snmp_nsm_change); + + hook_register(frr_late_init, ospf_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "ospfd_snmp", + .version = FRR_VERSION, + .description = "ospfd AgentX SNMP module", + .init = ospf_snmp_module_init, +) diff --git a/ospfd/ospf_snmp.h b/ospfd/ospf_snmp.h deleted file mode 100644 index 413d1d7f7..000000000 --- a/ospfd/ospf_snmp.h +++ /dev/null @@ -1,38 +0,0 @@ -/* OSPFv2 SNMP support - * Copyright (C) 2000 IP Infusion Inc. - * - * Written by Kunihiro Ishiguro <kunihiro@zebra.org> - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef _ZEBRA_OSPF_SNMP_H -#define _ZEBRA_OSPF_SNMP_H - -extern void ospf_snmp_if_update (struct interface *); -extern void ospf_snmp_if_delete (struct interface *); - -extern void ospf_snmp_vl_add (struct ospf_vl_data *); -extern void ospf_snmp_vl_delete (struct ospf_vl_data *); - -extern void ospfTrapIfStateChange (struct ospf_interface *); -extern void ospfTrapVirtIfStateChange (struct ospf_interface *); -extern void ospfTrapNbrStateChange (struct ospf_neighbor *); -extern void ospfTrapVirtNbrStateChange (struct ospf_neighbor *); - -#endif /* _ZEBRA_OSPF_SNMP_H */ diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 077d0e68a..31f0d9d28 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -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); } } } diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 4c5862e84..449f9e7b9 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -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); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index ce4bc9dfa..49474df82 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -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); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index b0ff5d0e3..abb6db034 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -50,11 +50,11 @@ #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_zebra.h" -#ifdef HAVE_SNMP -#include "ospfd/ospf_snmp.h" -#endif /* HAVE_SNMP */ #include "ospfd/ospf_te.h" +DEFINE_HOOK(ospf_if_update, (struct interface *ifp), (ifp)) +DEFINE_HOOK(ospf_if_delete, (struct interface *ifp), (ifp)) + /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -112,9 +112,7 @@ ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length, ospf_if_update (NULL, ifp); -#ifdef HAVE_SNMP - ospf_snmp_if_update (ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_update, ifp); return 0; } @@ -143,9 +141,7 @@ ospf_interface_delete (int command, struct zclient *zclient, ("Zebra: interface delete %s[%u] index %d flags %llx metric %d mtu %d", ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); -#ifdef HAVE_SNMP - ospf_snmp_if_delete (ifp); -#endif /* HAVE_SNMP */ + hook_call(ospf_if_delete, ifp); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if (rn->info) @@ -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); diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 8e93ed269..22c71a49e 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -24,6 +24,7 @@ #define _ZEBRA_OSPF_ZEBRA_H #include "vty.h" +#include "hook.h" #define EXTERNAL_METRIC_TYPE_1 0 #define EXTERNAL_METRIC_TYPE_2 1 @@ -79,5 +80,8 @@ extern int ospf_distance_unset (struct vty *, struct ospf *, const char *, const char *, const char *); extern void ospf_zebra_init(struct thread_master *, u_short); +DECLARE_HOOK(ospf_if_update, (struct interface *ifp), (ifp)) +DECLARE_HOOK(ospf_if_delete, (struct interface *ifp), (ifp)) + #endif /* _ZEBRA_OSPF_ZEBRA_H */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 7cd390367..30b1e9622 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -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; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index a3bd0ca12..9198d5c62 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -574,7 +574,6 @@ extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); extern void ospf_route_map_init (void); -extern void ospf_snmp_init (void); extern void ospf_master_init (struct thread_master *master); diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 59abd1aa3..77eb5c756 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -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) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 465c368f4..3c5a16ec6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -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); } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 94ee07a0e..086479643 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -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); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 8d332c70b..e98c17fed 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -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 */ diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index ee7579302..e6b4ba92a 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -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; diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index c7084034a..fe9fb9a7f 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -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); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index e6582e2b1..ee88e7d8e 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -876,10 +876,8 @@ pim_igmp_read (struct thread *t) if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) - { - cont = 0; break; - } + goto done; } } diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index ba80db069..228d30c5c 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -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; diff --git a/pimd/pim_join.c b/pimd/pim_join.c index c19468da6..884aa35bc 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -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) diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 8d4510324..251e67a35 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -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 diff --git a/pimd/pim_jp_agg.h b/pimd/pim_jp_agg.h index 4c84c120e..ad014d952 100644 --- a/pimd/pim_jp_agg.h +++ b/pimd/pim_jp_agg.h @@ -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); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index a0e42aab5..d814af6b2 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -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(); diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 5af2a8203..2acca6f49 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -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") diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 0d5f131a4..02446de46 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -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 */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 940147581..2fb243b9b 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -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) { diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 4018fd639..e19893f5d 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -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; } diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 9774ef3ed..de663aa3b 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -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 index 000000000..fe96d01a0 --- /dev/null +++ b/pimd/pim_nht.c @@ -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 index 000000000..5348ec370 --- /dev/null +++ b/pimd/pim_nht.h @@ -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 diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 471d8aa39..b2f858b7d 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -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); } diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 46d8e3ec2..65a3e8714 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -43,10 +43,25 @@ #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) || diff --git a/pimd/pim_register.h b/pimd/pim_register.h index 42a908b22..210a904ae 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -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 diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index dc19002a4..78bbd1440 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -42,14 +42,8 @@ #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; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index b32228ed4..84ab9be48 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -21,6 +21,21 @@ #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 diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index ff8a6054c..400048738 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -34,11 +34,12 @@ #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) diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index f4a987793..85fb1ed89 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -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 index 000000000..41bf1e566 --- /dev/null +++ b/pimd/pim_ssm.c @@ -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 index 000000000..ca82d334f --- /dev/null +++ b/pimd/pim_ssm.h @@ -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 diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 035408333..76b327ab0 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -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]; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 19f7d3336..172d0d21c 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -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); } } } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index b191fe940..6f7556f32 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -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 */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 5b6a79b95..f4bfcc5ce 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -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; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 1db6616c5..4e18c478d 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -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; +} diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 751a7be25..2ed463efa 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -21,13 +21,16 @@ #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 */ diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 7ec31c7d5..f77990ab5 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -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; diff --git a/pimd/pimd.c b/pimd/pimd.c index c8a0efc40..bdbd251e2 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -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 (); } diff --git a/pimd/pimd.h b/pimd/pimd.h index 090601630..69aee28f8 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -22,6 +22,11 @@ #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 */ diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md index db3c7d45c..6bec5d65c 100644 --- a/redhat/README.rpm_build.md +++ b/redhat/README.rpm_build.md @@ -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 diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index bb23931b1..c32e3e3af 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -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 diff --git a/ripd/Makefile.am b/ripd/Makefile.am index 7967ff153..9c034f0c3 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -7,11 +7,12 @@ INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = librip.a +module_LTLIBRARIES = sbin_PROGRAMS = ripd librip_a_SOURCES = \ rip_memory.c \ - ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ + ripd.c rip_zebra.c rip_interface.c rip_debug.c \ rip_routemap.c rip_peer.c rip_offset.c noinst_HEADERS = \ @@ -23,6 +24,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 diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 4c750faf4..a4ee2ba57 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -42,6 +42,9 @@ #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" +DEFINE_HOOK(rip_ifaddr_add, (struct connected *ifc), (ifc)) +DEFINE_HOOK(rip_ifaddr_del, (struct connected *ifc), (ifc)) + /* static prototypes */ static void rip_enable_apply (struct interface *); static void rip_passive_interface_apply (struct interface *); @@ -673,9 +676,7 @@ rip_interface_address_add (int command, struct zclient *zclient, /* Check if this prefix needs to be redistributed */ rip_apply_address_add(ifc); -#ifdef HAVE_SNMP - rip_ifaddr_add (ifc->ifp, ifc); -#endif /* HAVE_SNMP */ + hook_call(rip_ifaddr_add, ifc); } return 0; @@ -723,9 +724,7 @@ rip_interface_address_delete (int command, struct zclient *zclient, zlog_debug ("connected address %s/%d is deleted", inet_ntoa (p->u.prefix4), p->prefixlen); -#ifdef HAVE_SNMP - rip_ifaddr_delete (ifc->ifp, ifc); -#endif /* HAVE_SNMP */ + hook_call(rip_ifaddr_del, ifc); /* Chech wether this prefix needs to be removed */ rip_apply_address_del(ifc); diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 6fd647596..baba9592e 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -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; diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index c28b9379c..06cd3cef6 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -21,16 +21,18 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include "if.h" +#include "vrf.h" #include "log.h" #include "prefix.h" #include "command.h" #include "table.h" #include "smux.h" +#include "libfrr.h" +#include "version.h" #include "ripd/ripd.h" @@ -174,24 +176,27 @@ rip2Globals (struct variable *v, oid name[], size_t *length, return NULL; } -void -rip_ifaddr_add (struct interface *ifp, struct connected *ifc) +static int +rip_snmp_ifaddr_add (struct connected *ifc) { + struct interface *ifp = ifc->ifp; struct prefix *p; struct route_node *rn; p = ifc->address; if (p->family != AF_INET) - return; + return 0; rn = route_node_get (rip_ifaddr_table, p); rn->info = ifp; + return 0; } -void -rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) +static int +rip_snmp_ifaddr_del (struct connected *ifc) { + struct interface *ifp = ifc->ifp; struct prefix *p; struct route_node *rn; struct interface *i; @@ -199,11 +204,11 @@ rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) p = ifc->address; if (p->family != AF_INET) - return; + return 0; rn = route_node_lookup (rip_ifaddr_table, p); if (! rn) - return; + return 0; i = rn->info; if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) { @@ -211,6 +216,7 @@ rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) route_unlock_node (rn); route_unlock_node (rn); } + return 0; } static struct interface * @@ -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, +) diff --git a/ripd/ripd.c b/ripd/ripd.c index e0f96f9aa..b668b0a0b 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -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); diff --git a/ripd/ripd.h b/ripd/ripd.h index 68b3d1fc6..eeb008e3d 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -23,6 +23,7 @@ #define _ZEBRA_RIP_H #include "qobj.h" +#include "hook.h" #include "rip_memory.h" /* RIP version number. */ @@ -391,7 +392,6 @@ extern void rip_if_init (void); extern void rip_if_down_all (void); extern void rip_route_map_init (void); extern void rip_route_map_reset (void); -extern void rip_snmp_init (void); extern void rip_zclient_init(struct thread_master *); extern void rip_zclient_reset (void); extern void rip_offset_init (void); @@ -432,8 +432,6 @@ extern void rip_offset_clean (void); extern void rip_info_free (struct rip_info *); extern u_char rip_distance_apply (struct rip_info *); extern void rip_redistribute_clean (void); -extern void rip_ifaddr_add (struct interface *, struct connected *); -extern void rip_ifaddr_delete (struct interface *, struct connected *); extern struct rip_info *rip_ecmp_add (struct rip_info *); extern struct rip_info *rip_ecmp_replace (struct rip_info *); @@ -448,4 +446,8 @@ extern struct thread_master *master; /* RIP statistics for SNMP. */ extern long rip_global_route_changes; extern long rip_global_queries; + +DECLARE_HOOK(rip_ifaddr_add, (struct connected *ifc), (ifc)) +DECLARE_HOOK(rip_ifaddr_del, (struct connected *ifc), (ifc)) + #endif /* _ZEBRA_RIP_H */ diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index 7cab5861b..ad8dbc92f 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -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; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 108da21c1..a883bec3c 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -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; diff --git a/snapcraft/Makefile.am b/snapcraft/Makefile.am index 15813be72..75f768e94 100644 --- a/snapcraft/Makefile.am +++ b/snapcraft/Makefile.am @@ -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 diff --git a/snapcraft/README.snap_build.md b/snapcraft/README.snap_build.md index 341b210f7..c4db51bd6 100644 --- a/snapcraft/README.snap_build.md +++ b/snapcraft/README.snap_build.md @@ -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 diff --git a/snapcraft/README.usage.md b/snapcraft/README.usage.md index 2d2b32b6b..aaff59438 100644 --- a/snapcraft/README.usage.md +++ b/snapcraft/README.usage.md @@ -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 Binary files differdeleted file mode 100644 index e8f68e6dd..000000000 --- a/snapcraft/setup/gui/icon.png +++ /dev/null diff --git a/snapcraft/snap/gui/icon.png b/snapcraft/snap/gui/icon.png Binary files differnew file mode 100644 index 000000000..3ab3f8fc1 --- /dev/null +++ b/snapcraft/snap/gui/icon.png diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index a703766f0..a20a1d039 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -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 diff --git a/solaris/README.txt b/solaris/README.txt index 01f725b8f..589570d88 100644 --- a/solaris/README.txt +++ b/solaris/README.txt @@ -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. diff --git a/solaris/depend.daemons.in b/solaris/depend.daemons.in index 64fb03ac1..a8ce943e3 100644 --- a/solaris/depend.daemons.in +++ b/solaris/depend.daemons.in @@ -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) diff --git a/solaris/depend.dev.in b/solaris/depend.dev.in index 5d8bf16ed..1b65724a0 100644 --- a/solaris/depend.dev.in +++ b/solaris/depend.dev.in @@ -1,2 +1,2 @@ -P FRRlibs FreeRangeRouting common runtime libraries +P FRRlibs FRRouting common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ diff --git a/solaris/depend.libs.in b/solaris/depend.libs.in index 6ead0b286..04f04efd0 100644 --- a/solaris/depend.libs.in +++ b/solaris/depend.libs.in @@ -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 diff --git a/solaris/depend.smf.in b/solaris/depend.smf.in index 66b11eba2..b3b1bd778 100644 --- a/solaris/depend.smf.in +++ b/solaris/depend.smf.in @@ -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) diff --git a/solaris/frr.init.in b/solaris/frr.init.in index 580fd9b35..bd9ab85e6 100755 --- a/solaris/frr.init.in +++ b/solaris/frr.init.in @@ -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 diff --git a/solaris/frr.xml.in b/solaris/frr.xml.in index 5ac7e5272..08a9a11c0 100644 --- a/solaris/frr.xml.in +++ b/solaris/frr.xml.in @@ -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. @@ -107,9 +107,9 @@ <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. @@ -142,14 +142,14 @@ <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> @@ -240,7 +240,7 @@ <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. @@ -273,14 +273,14 @@ <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> @@ -408,8 +408,8 @@ <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> @@ -539,8 +539,8 @@ <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> @@ -665,8 +665,8 @@ <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> @@ -818,8 +818,8 @@ <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> diff --git a/solaris/pkginfo.tmpl.in b/solaris/pkginfo.tmpl.in index 02abb0f96..89a281ceb 100644 --- a/solaris/pkginfo.tmpl.in +++ b/solaris/pkginfo.tmpl.in @@ -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" diff --git a/tests/helpers/python/frrtest.py b/tests/helpers/python/frrtest.py index 20c854f66..a7ef1c56b 100644 --- a/tests/helpers/python/frrtest.py +++ b/tests/helpers/python/frrtest.py @@ -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 index 000000000..682e95faa --- /dev/null +++ b/tests/lib/cli/.gitignore @@ -0,0 +1 @@ +/test_cli.refout diff --git a/tests/lib/cli/test_cli.refout b/tests/lib/cli/test_cli.refout.in index 8b438baee..18822c150 100644 --- a/tests/lib/cli/test_cli.refout +++ b/tests/lib/cli/test_cli.refout.in @@ -304,6 +304,9 @@ test# show run Current configuration:
!
+frr version @PACKAGE_VERSION@
+frr defaults @DFLT_NAME@
+!
hostname test
!
!
@@ -316,6 +319,9 @@ foohost(config)# do show run Current configuration:
!
+frr version @PACKAGE_VERSION@
+frr defaults @DFLT_NAME@
+!
hostname foohost
!
!
diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c new file mode 100644 index 000000000..4a4aaa001 --- /dev/null +++ b/tests/test_lblmgr.c @@ -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; +} diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 4c2630009..c91392da1 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -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: diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index c28b9cb71..44fbafc33 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -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 diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 4dddb809a..169220c77 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -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; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index afb742d90..0473b244a 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -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); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 11b678fe4..ad45abcdf 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -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 diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index ca52d65bc..06e856934 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -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 diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 1910e7b80..3e0de3b46 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -19,33 +19,22 @@ mpls_method = @MPLS_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) \ $(rt_method) $(rtread_method) $(kernel_method) $(mpls_method) -if HAVE_NETLINK -othersrc = zebra_fpm_netlink.c -endif - -if HAVE_PROTOBUF -protobuf_srcs = zebra_fpm_protobuf.c -endif - -if DEV_BUILD -dev_srcs = zebra_fpm_dt.c -endif - AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra - noinst_PROGRAMS = testzebra +module_LTLIBRARIES = zebra_SOURCES = \ zebra_memory.c \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ - redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ - irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ - $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ + redistribute.c debug.c rtadv.c zebra_vty.c \ + irdp_main.c irdp_interface.c irdp_packet.c router-id.c \ + zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \ - $(protobuf_srcs) zebra_mroute.c \ - $(dev_srcs) + 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 \ diff --git a/zebra/debug.c b/zebra/debug.c index 2e9fef292..f21778276 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -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); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index a4498a84f..5333f0331 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -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", diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 339e00b22..dbc410991 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -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; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 65fc8789f..28538fabd 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -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. */ diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index 8326f0e39..c62d9926a 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -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; } diff --git a/zebra/interface.c b/zebra/interface.c index 5a9de5b70..1d015e858 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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") diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index c9c32ce31..4c58b6b35 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -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; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 1bb85a31a..7212ed6f2 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -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 index 000000000..9f8378572 --- /dev/null +++ b/zebra/label_manager.c @@ -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 index 000000000..0c6a5ebc7 --- /dev/null +++ b/zebra/label_manager.h @@ -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 */ diff --git a/zebra/main.c b/zebra/main.c index 98177a423..459e6148d 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -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> @@ -43,11 +43,11 @@ #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... */ diff --git a/zebra/misc_null.c b/zebra/misc_null.c index a83c30741..49cb92bd7 100644 --- a/zebra/misc_null.c +++ b/zebra/misc_null.c @@ -25,7 +25,6 @@ #include "zebra/rtadv.h" #include "zebra/irdp.h" #include "zebra/interface.h" -#include "zebra/zebra_fpm.h" void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } @@ -35,9 +34,3 @@ void ifstat_update_proc (void) { return; } #ifdef HAVE_NET_RT_IFLIST void ifstat_update_sysctl (void) { return; } #endif - -void -zfpm_trigger_update (struct route_node *rn, const char *reason) -{ - return; -} diff --git a/zebra/rib.h b/zebra/rib.h index c0cde50ba..5381d76b9 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -24,6 +24,7 @@ #define _ZEBRA_RIB_H #include "zebra.h" +#include "hook.h" #include "linklist.h" #include "prefix.h" #include "table.h" @@ -490,4 +491,6 @@ rib_tables_iter_cleanup (rib_tables_iter_t *iter) iter->state = RIB_TABLES_ITER_S_DONE; } +DECLARE_HOOK(rib_update, (struct route_node *rn, const char *reason), (rn, reason)) + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6ac131449..a544593dd 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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); } diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 1007d0ac1..4d491f320 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -31,6 +31,10 @@ #include "zebra/rib.h" #include "zebra/zserv.h" +/* Thank you, Solaris, for polluting application symbol namespace. */ +#undef hook_register +#undef hook_unregister + #include <sys/stream.h> #include <sys/tihdr.h> diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index afa557096..405b2e9f7 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -25,10 +25,12 @@ #include <zebra.h> #include "log.h" +#include "libfrr.h" #include "stream.h" #include "thread.h" #include "network.h" #include "command.h" +#include "version.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -36,7 +38,6 @@ #include "zebra/zebra_vrf.h" #include "fpm/fpm.h" -#include "zebra_fpm.h" #include "zebra_fpm_private.h" /* @@ -254,6 +255,8 @@ typedef struct zfpm_glob_t_ static zfpm_glob_t zfpm_glob_space; static zfpm_glob_t *zfpm_g = &zfpm_glob_space; +static int zfpm_trigger_update (struct route_node *rn, const char *reason); + static int zfpm_read_cb (struct thread *thread); static int zfpm_write_cb (struct thread *thread); @@ -1296,7 +1299,6 @@ zfpm_start_connect_timer (const char *reason) zfpm_set_state (ZFPM_STATE_ACTIVE, reason); } -#if defined (HAVE_FPM) /* * zfpm_is_enabled * @@ -1307,7 +1309,6 @@ zfpm_is_enabled (void) { return zfpm_g->enabled; } -#endif /* * zfpm_conn_is_up @@ -1331,7 +1332,7 @@ zfpm_conn_is_up (void) * The zebra code invokes this function to indicate that we should * send an update to the FPM about the given route_node. */ -void +static int zfpm_trigger_update (struct route_node *rn, const char *reason) { rib_dest_t *dest; @@ -1342,7 +1343,7 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) * all destinations once the connection comes up. */ if (!zfpm_conn_is_up ()) - return; + return 0; dest = rib_dest_from_rnode (rn); @@ -1353,12 +1354,12 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) if (!zfpm_is_table_for_fpm (rib_dest_table (dest))) { zfpm_g->stats.non_fpm_table_triggers++; - return; + return 0; } if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { zfpm_g->stats.redundant_triggers++; - return; + return 0; } if (reason) @@ -1375,9 +1376,10 @@ zfpm_trigger_update (struct route_node *rn, const char *reason) * Make sure that writes are enabled. */ if (zfpm_g->t_write) - return; + return 0; zfpm_write_on (); + return 0; } /* @@ -1411,7 +1413,6 @@ zfpm_stats_timer_cb (struct thread *t) return 0; } -#if defined (HAVE_FPM) /* * zfpm_stop_stats_timer */ @@ -1424,7 +1425,6 @@ zfpm_stop_stats_timer (void) zfpm_debug ("Stopping existing stats timer"); THREAD_TIMER_OFF (zfpm_g->t_stats); } -#endif /* * zfpm_start_stats_timer @@ -1447,7 +1447,6 @@ zfpm_start_stats_timer (void) zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \ } while (0) -#if defined (HAVE_FPM) /* * zfpm_show_stats */ @@ -1600,7 +1599,6 @@ DEFUN ( no_fpm_remote_ip, return CMD_SUCCESS; } -#endif /* * zfpm_init_message_format @@ -1670,7 +1668,7 @@ zfpm_init_message_format (const char *format) * Returns ZERO on success. */ -int fpm_remote_srv_write (struct vty *vty ) +static int fpm_remote_srv_write (struct vty *vty) { struct in_addr in; @@ -1684,6 +1682,15 @@ int fpm_remote_srv_write (struct vty *vty ) } +/* Zebra node */ +static struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "", + 1 +}; + + /** * zfpm_init * @@ -1695,17 +1702,12 @@ int fpm_remote_srv_write (struct vty *vty ) * * Returns TRUE on success. */ -int -zfpm_init (struct thread_master *master, int enable, uint16_t port, - const char *format) +static int +zfpm_init (struct thread_master *master) { - static int initialized = 0; - - if (initialized) { - return 1; - } - - initialized = 1; + int enable = 1; + uint16_t port = 0; + const char *format = THIS_MODULE->load_args; memset (zfpm_g, 0, sizeof (*zfpm_g)); zfpm_g->master = master; @@ -1717,12 +1719,11 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_stats_init (&zfpm_g->last_ivl_stats); zfpm_stats_init (&zfpm_g->cumulative_stats); -#if defined (HAVE_FPM) + install_node (&zebra_node, fpm_remote_srv_write); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); install_element (CONFIG_NODE, &fpm_remote_ip_cmd); install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd); -#endif zfpm_init_message_format(format); @@ -1734,10 +1735,6 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_g->enabled = enable; - if (!enable) { - return 1; - } - if (!zfpm_g->fpm_server) zfpm_g->fpm_server = FPM_DEFAULT_IP; @@ -1751,6 +1748,20 @@ zfpm_init (struct thread_master *master, int enable, uint16_t port, zfpm_start_stats_timer (); zfpm_start_connect_timer ("initialized"); + return 0; +} - return 1; +static int +zebra_fpm_module_init (void) +{ + hook_register(rib_update, zfpm_trigger_update); + hook_register(frr_late_init, zfpm_init); + return 0; } + +FRR_MODULE_SETUP( + .name = "zebra_fpm", + .version = FRR_VERSION, + .description = "zebra FPM (Forwarding Plane Manager) module", + .init = zebra_fpm_module_init, +) diff --git a/zebra/zebra_fpm.h b/zebra/zebra_fpm.h deleted file mode 100644 index fdb069965..000000000 --- a/zebra/zebra_fpm.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Header file exported by the zebra FPM module to zebra. - * - * Copyright (C) 2012 by Open Source Routing. - * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _ZEBRA_FPM_H -#define _ZEBRA_FPM_H - -/* - * Externs. - */ -extern int zfpm_init (struct thread_master *master, int enable, uint16_t port, - const char *message_format); -extern void zfpm_trigger_update (struct route_node *rn, const char *reason); -extern int fpm_remote_srv_write (struct vty *vty); - -#endif /* _ZEBRA_FPM_H */ diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index 715e250a6..7b4e1b90d 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -50,8 +50,10 @@ #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. diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index fba57c68f..11869d8a2 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -53,7 +53,7 @@ create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, } fpm__delete_route__init(msg); - msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); @@ -159,7 +159,7 @@ create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, fpm__add_route__init(msg); - msg->vrf_id = rib_dest_vrf(dest)->vrf_id; + msg->vrf_id = zvrf_id(rib_dest_vrf(dest)); qpb_address_family_set (&msg->address_family, rib_dest_af(dest)); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 56a6ca7af..5a3ed7545 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -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; diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index b68b03e0c..eaa80ac55 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -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); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f9734fdf7..b3e70e46f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -48,11 +48,12 @@ #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" #include "zebra/debug.h" -#include "zebra/zebra_fpm.h" #include "zebra/zebra_rnh.h" #include "zebra/interface.h" #include "zebra/connected.h" +DEFINE_HOOK(rib_update, (struct route_node *rn, const char *reason), (rn, reason)) + /* Should we allow non Quagga processes to delete our routes */ extern int allow_delete; @@ -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); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 5fe4a7ab9..847da5295 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -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; diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 19364b5b9..8adb8873d 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -25,7 +25,6 @@ #include <zebra.h> -#ifdef HAVE_SNMP #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> @@ -36,6 +35,9 @@ #include "smux.h" #include "table.h" #include "vrf.h" +#include "hook.h" +#include "libfrr.h" +#include "version.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -571,10 +573,24 @@ ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, return NULL; } -void -zebra_snmp_init () +static int +zebra_snmp_init (struct thread_master *tm) { - smux_init (zebrad.master); + smux_init (tm); REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); + return 0; +} + +static int +zebra_snmp_module_init (void) +{ + hook_register(frr_late_init, zebra_snmp_init); + return 0; } -#endif /* HAVE_SNMP */ + +FRR_MODULE_SETUP( + .name = "zebra_snmp", + .version = FRR_VERSION, + .description = "zebra AgentX SNMP module", + .init = zebra_snmp_module_init, +) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 6fc41c3a1..bc18ee586 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -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 diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7946089ae..35aa69cc9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -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; diff --git a/zebra/zserv.c b/zebra/zserv.c index 064489acd..3477dc36d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -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); diff --git a/zebra/zserv.h b/zebra/zserv.h index 21cf1004b..cd1948373 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -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 *); |