From 7c900c2d5d5973a455f9438f2c6a90f0a0983dc5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 19 May 2016 13:31:51 -0400 Subject: [PATCH 01/30] cumulus: Increase netlink socket buffer size Ticket: CM-10950 Signed-off-by: Donald Sharp Reviewed-by: Vivek Venkatraman --- cumulus/etc/quagga/debian.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/etc/quagga/debian.conf b/cumulus/etc/quagga/debian.conf index ed2fdd985a..0b7819e1ed 100644 --- a/cumulus/etc/quagga/debian.conf +++ b/cumulus/etc/quagga/debian.conf @@ -4,7 +4,7 @@ # Check /etc/pam.d/quagga if you intend to use "vtysh"! # vtysh_enable=yes -zebra_options=" -s 16777216 --daemon -A 127.0.0.1" +zebra_options=" -s 90000000 --daemon -A 127.0.0.1" bgpd_options=" --daemon -A 127.0.0.1" ospfd_options=" --daemon -A 127.0.0.1" ospf6d_options=" --daemon -A ::1" From afe50908f91349ff94d4dd3a76058be63b1070a3 Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 18 May 2016 14:08:55 -0700 Subject: [PATCH 02/30] Quagga: Make sure order of route-maps in list and hash table matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quick create/delete actions on a route-map can result in the same route-map entity having multiple entries created for it — because BGP hasn't run the update processing to complete prior delete action. The route-map is present in both a hash table as well as a linked list and the order in each is different. This can lead to problems when the BGP route-map update processing runs and finds the same route-map entity present for deletion multiple times. For example, while processing instance-2 of rmap-A, the code may end up freeing the hash bucket corresponding to instance-1 of rmap-A. The fix works by ensuring the list is ordered the same way as the hash buckets. Signed-off-by: Vivek Venkatraman Reviewed-by: Daniel Walton Reviewed-by: Donald Sharp Reviewed-by: Shrijeet Mukherjee Ticket: CM-10023 Reviewed By: CCR-4747 Testing Done: manual, bgp-smoke --- lib/routemap.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index 733e61c99b..c3afcb896d 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -163,13 +163,23 @@ route_map_add (const char *name) /* Add map to the hash */ hash_get(route_map_master_hash, map, hash_alloc_intern); - map->next = NULL; - map->prev = list->tail; - if (list->tail) - list->tail->next = map; - else - list->head = map; - list->tail = map; + /* Add new entry to the head of the list to match how it is added in the + * hash table. This is to ensure that if the same route-map has been + * created more than once and then marked for deletion (which can happen + * if prior deletions haven't completed as BGP hasn't yet done the + * route-map processing), the order of the entities is the same in both + * the list and the hash table. Otherwise, since there is nothing to + * distinguish between the two entries, the wrong entry could get freed. + * TODO: This needs to be re-examined to handle it better - e.g., revive + * a deleted entry if the route-map is created again. + */ + map->prev = NULL; + map->next = list->head; + if (list->head) + list->head->prev = map; + list->head = map; + if (!list->tail) + list->tail = map; /* Execute hook. */ if (route_map_master.add_hook) From f6da66a913bcae1d3f75c55f24e72e97288af619 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 19 May 2016 09:56:35 -0400 Subject: [PATCH 03/30] lib: Fix some poll semantics Two Fixes: 1) When a fd has both read and write as a .events. (POLLHUP | POLLIN | POLLOUT) and a thread_cancel_read_write call is executed from a protocol, the code was blindly removing the fd from consideration at all. 2) POLLNVAL was being evaluated before POLLIN|POLLOUT were being evaluated. While I didn't see a case of POLLNVAL being included with other .revent flags I decided to move the POLLNVAL and POLLHUP handling to the same section of code. Additionally the function thread_cancel_read_write was poorly named and let me to poorly implement the poll version of it. I've renamed the function thread_cancel_read_or_write in an attempt to make this problem moot in the future. Ticket: CM-11027 Signed-off-by: Donald Sharp --- lib/thread.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index ab4764dfb1..a2a42e43c8 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1046,7 +1046,7 @@ funcname_thread_add_event (struct thread_master *m, } static void -thread_cancel_read_write (struct thread *thread) +thread_cancel_read_or_write (struct thread *thread, short int state) { #if defined(HAVE_POLL) nfds_t i; @@ -1054,12 +1054,17 @@ thread_cancel_read_write (struct thread *thread) for (i=0;imaster->handler.pfdcount;++i) if (thread->master->handler.pfds[i].fd == thread->u.fd) { + thread->master->handler.pfds[i].events &= ~(state); + /* remove thread fds from pfd list */ - memmove(thread->master->handler.pfds+i, - thread->master->handler.pfds+i+1, - (thread->master->handler.pfdsize-i-1) * sizeof(struct pollfd)); - i--; - thread->master->handler.pfdcount--; + if (thread->master->handler.pfds[i].events == 0) + { + memmove(thread->master->handler.pfds+i, + thread->master->handler.pfds+i+1, + (thread->master->handler.pfdsize-i-1) * sizeof(struct pollfd)); + thread->master->handler.pfdcount--; + return; + } } #endif @@ -1077,11 +1082,19 @@ thread_cancel (struct thread *thread) switch (thread->type) { case THREAD_READ: - thread_cancel_read_write (thread); +#if defined (HAVE_POLL) + thread_cancel_read_or_write (thread, POLLIN | POLLHUP); +#else + thread_cancel_read_or_write (thread, 0); +#endif thread_array = thread->master->read; break; case THREAD_WRITE: - thread_cancel_read_write (thread); +#if defined (HAVE_POLL) + thread_cancel_read_or_write (thread, POLLOUT | POLLHUP); +#else + thread_cancel_read_or_write (thread, 0); +#endif thread_array = thread->master->write; break; case THREAD_TIMER: @@ -1254,16 +1267,6 @@ check_pollfds(struct thread_master *m, fd_set *readfd, int num) continue; ready++; - /* remove fd from list on POLLNVAL */ - if (m->handler.pfds[i].revents & POLLNVAL) - { - memmove(m->handler.pfds+i, - m->handler.pfds+i+1, - (m->handler.pfdsize-i-1) * sizeof(struct pollfd)); - m->handler.pfdcount--; - i--; - continue; - } /* POLLIN / POLLOUT process event */ if (m->handler.pfds[i].revents & POLLIN) @@ -1271,8 +1274,9 @@ check_pollfds(struct thread_master *m, fd_set *readfd, int num) if (m->handler.pfds[i].revents & POLLOUT) thread_process_fds_helper(m, m->write[m->handler.pfds[i].fd], NULL, POLLOUT, i); - /* remove fd from list on POLLHUP after other event is processed */ - if (m->handler.pfds[i].revents & POLLHUP) + /* remove fd from list on POLLNVAL */ + if (m->handler.pfds[i].revents & POLLNVAL || + m->handler.pfds[i].revents & POLLHUP) { memmove(m->handler.pfds+i, m->handler.pfds+i+1, From 116bd4e9ff9a8df4b6c66b3e674f21d8000d8e41 Mon Sep 17 00:00:00 2001 From: radhika Date: Sat, 21 May 2016 01:16:14 -0700 Subject: [PATCH 04/30] BGP:Fix for BFD sessions not getting replayed after quagga restart Signed-off-by: Radhika Mahankali Reviewed-by: Donald Sharp Reviewed-by: Kanna Rajagopal Ticket: CM-11055 Reviewed By: CCR-4773 Testing Done: Unit, PTM smoke, BGP neighbor smoke Issue: bgpd is not replaying the BFD registrations to PTM after quagga restart. Root Cause: This problem happens when BFD configuration is part of the peer group template. Currently, the BFD configuration is being copied to the peer from template as part of the AF (address family) configuration. But, when the saved config is used after the quagga restart the peer group template is applied to the peer before the AF configuration is configured for the template. Due to this the BFD configuration never gets copied from the template to the peer and the BGP peers have no BFD configuration after the restart Sample config which failed: router bgp 100 bgp router-id 10.10.0.1 no bgp default ipv4-unicast bgp bestpath as-path multipath-relax neighbor dpeergrp_2 peer-group neighbor dpeergrp_2 remote-as 100 neighbor dpeergrp_2 bfd neighbor dpeergrp_2 advertisement-interval 1 neighbor dpeergrp_2 timers connect 1 neighbor dpeergrp_4 peer-group neighbor dpeergrp_4 remote-as 400 neighbor dpeergrp_4 bfd neighbor dpeergrp_4 advertisement-interval 1 neighbor dpeergrp_4 timers connect 1 neighbor swp2s0.1 interface peer-group dpeergrp_2 neighbor swp18s3.1 interface peer-group dpeergrp_4 ! address-family ipv4 unicast redistribute connected route-map redist neighbor dpeergrp_2 activate neighbor dpeergrp_2 next-hop-self neighbor dpeergrp_2 default-originate neighbor dpeergrp_2 soft-reconfiguration inbound neighbor dpeergrp_4 activate neighbor dpeergrp_4 next-hop-self neighbor dpeergrp_4 default-originate neighbor dpeergrp_4 soft-reconfiguration inbound maximum-paths 14 exit-address-family Fix: Moved the BFD config copy from the peer group AF config copy function to the main peer group config copy function. --- bgpd/bgpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2f7c584c2d..ed76cfcf60 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2196,6 +2196,8 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer) } peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, conf->update_if); } + + bgp_bfd_peer_group2peer_copy(conf, peer); } static void @@ -2340,8 +2342,6 @@ peer_group2peer_config_copy_af (struct peer_group *group, struct peer *peer, pfilter->usmap.name = NULL; pfilter->usmap.map = NULL; } - - bgp_bfd_peer_group2peer_copy(conf, peer); } /* Peer group's remote AS configuration. */ From 99d8325e9a43d70531b83c68864736c009a60c04 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 23 May 2016 17:22:24 -0400 Subject: [PATCH 05/30] zebra: Fix zebra to exit on recvmsg buffer overrun When zebra receives a recvmsg buffer from the kernel silently exit so that watchquagga will notice and then restart zebra. Ticket: CM-11130 Signed-off-by: Donald Sharp Reviewed-by: Vivek Venkatraman --- zebra/rt_netlink.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 50a269dbc6..e52fcd4342 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -327,6 +327,12 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *, break; zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s", nl->name, safe_strerror(errno)); + /* + * In this case we are screwed. + * There is no good way to + * recover zebra at this point. + */ + exit (-1); continue; } From d236e0b80a40d57198ad661f085ac0e57489a86c Mon Sep 17 00:00:00 2001 From: Don Slice Date: Fri, 10 Jun 2016 06:58:03 -0700 Subject: [PATCH 06/30] bgpd: remove vrf->iflist deleted to avoid a crash Ticket: CM-11327 Signed-off-by: Don Slice Reviewed-by: Donald Sharp Testing Done: Manual testing, bgp-min, vrf-min, bgp-smoke, vrf-smoke all successful When bgp was configured in a vrf and then deleted, the vrf->iflist was being deleted from the vrf. Since the vrf itself was not deleted, it was assumed in later calls that the vrf->iflist was still there and when it was referenced, the crash occurred. --- bgpd/bgpd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ed76cfcf60..f23cc13725 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7251,7 +7251,6 @@ bgp_if_finish (struct bgp *bgp) for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) bgp_connected_delete (bgp, c); } - vrf_iflist_terminate (bgp->vrf_id); } void From f104b1d98c5e298aa0946ad376899210082cc05a Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 4 Sep 2015 14:25:13 +0100 Subject: [PATCH 07/30] distro: fix redhat/quagga.spec.in * quagga.spec.in: Add default for with_pimd macro. Remove ancient condtional on quagga_buildreqs. More recent rpmbuild complains about too many levels of recursion in quagga_buildreqs, so use %{expand:..}. Actually use quagga_buildreqs in BuildRequires! groff is needed for build. texi2html --number argument has disappeared, split into 2. Acked-by: Donald Sharp (cherry picked from commit e07068c838142a127da8821afd660f075f7c35f8) --- redhat/quagga.spec.in | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index a9b0312165..a49f48096a 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -20,6 +20,7 @@ %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } +%{!?with_pimd: %define with_pimd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } @@ -44,23 +45,24 @@ %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. -%define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel -%define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel +%define quagga_buildreqs texi2html texinfo autoconf pam-devel +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. -%if "%dist" != "fc2" || "%dist" != "fc3" -%define quagga_buildreqs %{quagga_buildreqs} texi2html -%endif +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html -# pam_stack is deprecated in FC5 +# pam_stack was deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif -############################################################################ +# man page probably needs groff for groff_ms macros +%define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff + +############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } @@ -103,7 +105,7 @@ Requires(pre): net-snmp BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif -BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex +BuildRequires: %{quagga_buildreqs} # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam @@ -223,7 +225,7 @@ developing OSPF-API and quagga applications. make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc -texi2html -number quagga.texi +texi2html --number-footnotes --number-sections quagga.texi popd %install @@ -446,6 +448,10 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Fri Sep 4 2015 Paul Jakma - %{version} +- buildreq updates +- add a default define for with_pimd + * Thu Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable From a5ca204764a9323dc75f57eaeb1a1387b8c5d606 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 11 Feb 2016 13:54:23 +0000 Subject: [PATCH 08/30] distro/redhat/rpm: remove with_ipv6, package pimd binary, remove pam stack * redhat/quagga.spec.in: remove with_ipv6, it should just be the norm now. The actual pimd binary wasn't being packaged, fix. Remove deprecated pam.stack support. * redhat/quagga.pam.stack: ancient, nuke. * Makefile.am: ditto (cherry picked from commit 283d5d7f2fa12c3d33dc17962154665a9993b2c5) --- redhat/Makefile.am | 2 +- redhat/quagga.pam.stack | 26 -------------------------- redhat/quagga.spec.in | 36 +++++++++++++----------------------- 3 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 redhat/quagga.pam.stack diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 9612e91484..3ec1fb73ac 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,6 +1,6 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ - quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ + quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init zebra.init zebra.service diff --git a/redhat/quagga.pam.stack b/redhat/quagga.pam.stack deleted file mode 100644 index 8ddc2bbe33..0000000000 --- a/redhat/quagga.pam.stack +++ /dev/null @@ -1,26 +0,0 @@ -#%PAM-1.0 -# - -##### if running quagga as root: -# Only allow root (and possibly wheel) to use this because enable access -# is unrestricted. -auth sufficient /lib/security/$ISA/pam_rootok.so - -# Uncomment the following line to implicitly trust users in the "wheel" group. -#auth sufficient /lib/security/$ISA/pam_wheel.so trust use_uid -# Uncomment the following line to require a user to be in the "wheel" group. -#auth required /lib/security/$ISA/pam_wheel.so use_uid -########################################################### - -# If using quagga privileges and with a seperate group for vty access, then -# access can be controlled via the vty access group, and pam can simply -# check for valid user/password, eg: -# -# only allow local users. -#auth required /lib/security/$ISA/pam_securetty.so -#auth required /lib/security/$ISA/pam_stack.so service=system-auth -#auth required /lib/security/$ISA/pam_nologin.so -#account required /lib/security/$ISA/pam_stack.so service=system-auth -#password required /lib/security/$ISA/pam_stack.so service=system-auth -#session required /lib/security/$ISA/pam_stack.so service=system-auth -#session optional /lib/security/$ISA/pam_console.so diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index a49f48096a..746922a03a 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -3,6 +3,9 @@ # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # +# E.g. rpmbuild --define 'release_rev 02' may be useful if building +# rpms again and again on the same day, so the newer rpms can be installed. +# bumping the number each time. ####################### Quagga configure options ######################### # with-feature options @@ -14,7 +17,6 @@ %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } -%{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } @@ -51,14 +53,6 @@ # FC4 and 5 split texi2html out of tetex package. %define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html -# pam_stack was deprecated in FC5 -# default to pam_stack, default should be changed later. -%if "%dist" == "fc4" || "%dist" == "fc3" -%define quagga_pam_source quagga.pam.stack -%else -%define quagga_pam_source quagga.pam -%endif - # man page probably needs groff for groff_ms macros %define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff @@ -69,11 +63,7 @@ %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd -%if %{with_ipv6} %define daemonv6_list ripngd ospf6d -%else -%define daemonv6_list "" -%endif %if %{with_isisd} %define daemon_other isisd @@ -161,9 +151,6 @@ developing OSPF-API and quagga applications. %if !%{with_shared} --disable-shared \ %endif -%if %{with_ipv6} - --enable-ipv6 \ -%endif %if %{with_snmp} --enable-snmp \ %endif @@ -247,7 +234,7 @@ for daemon in %{all_daemons} ; do $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done -install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ +install -m644 %{zeb_rh_src}/quagga.pam \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga @@ -291,14 +278,10 @@ zebra_spec_add_service () zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service zebra 2601/tcp "zebra vty" zebra_spec_add_service ripd 2602/tcp "RIPd vty" -%if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" -%endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" -%if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" -%endif %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif @@ -405,9 +388,10 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga -%if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d +%if %{with_pimd} +%{_sbindir}/pimd %endif %if %{with_isisd} %{_sbindir}/isisd @@ -448,6 +432,12 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Fri Sep 4 2015 Paul Jakma - %{version} +- package the pimd binary +- remove with_ipv6 conditionals, always build v6 +- Fix UTF-8 char in spec changelog +- remove quagga.pam.stack, long deprecated. + * Fri Sep 4 2015 Paul Jakma - %{version} - buildreq updates - add a default define for with_pimd @@ -584,7 +574,7 @@ rm -rf $RPM_BUILD_ROOT * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 -* Wed Aug 1 2001 Trond Eivind Glomsrřd 0.91a-5 +* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) From 3144257787e69c960fa6c4bbb8b6f06199bf41e8 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 29 Oct 2015 22:15:42 -0700 Subject: [PATCH 09/30] distro/redhat: Update to support CentOS/RHEL/Fedora, upstart/init/systemd * redhat/quagga.spec.in: Update to support CentOS, RHEL and Fedora, and support the various init systems across different versions of these distros, e.g. upstart/init/systemd. Clean up various warnings from rpmlint. Remove configure options that are gone. A few edits and commit message by: Paul Jakma / (cherry picked from commit a5efdb60905049e1224a020b78dd9699bdd15b29) Conflicts: redhat/Makefile.am --- redhat/Makefile.am | 3 +- redhat/README.rpm_build.md | 128 +++++++++++ redhat/quagga.spec.in | 437 +++++++++++++++++++++++++------------ 3 files changed, 423 insertions(+), 145 deletions(-) create mode 100644 redhat/README.rpm_build.md diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 3ec1fb73ac..695d7eae84 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -3,4 +3,5 @@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ - watchquagga.init zebra.init zebra.service + watchquagga.init zebra.init zebra.service \ + README.rpm_build.md diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md new file mode 100644 index 0000000000..3e8fa05306 --- /dev/null +++ b/redhat/README.rpm_build.md @@ -0,0 +1,128 @@ +Building your own Quagga RPM +============================ +(Tested on CentOS 6, CentOS 7 and Fedora 22.) + +1. Install the following packages to build the RPMs: + + yum install git autoconf automake libtool make gawk readline-devel \ + texinfo dejagnu net-snmp-devel groff rpm-build net-snmp-devel \ + libcap-devel texi2html + + (use `dnf install` on new Fedora instead of `yum install `) + +2. Checkout Quagga under a **unpriviledged** user account + + git clone git://git.savannah.nongnu.org/quagga.git quagga + +3. Run Bootstrap and make distribution tar.gz + + cd quagga + ./bootstrap.sh + ./configure --with-pkg-extra-version=-MyRPMVersion + make dist + + Note: configure parameters are not important for the RPM building - except the + `with-pkg-extra-version` if you want to give the RPM a specific name to + mark your own unoffical build + +4. Create RPM directory structure and populate with sources + + mkdir rpmbuild + mkdir rpmbuild/SOURCES + mkdir rpmbuild/SPECS + cp redhat/*.spec rpmbuild/SPECS/ + cp quagga*.tar.gz rpmbuild/SOURCES/ + +5. Edit rpm/SPECS/quagga.spec with configuration as needed + Look at the beginning of the file and adjust the following parameters to enable + or disable features as required: + + ################# Quagga configure options #################### + # with-feature options + %{!?with_snmp: %global with_snmp 1 } + %{!?with_vtysh: %global with_vtysh 1 } + %{!?with_ospf_te: %global with_ospf_te 1 } + %{!?with_opaque_lsa: %global with_opaque_lsa 1 } + %{!?with_tcp_zebra: %global with_tcp_zebra 0 } + %{!?with_vtysh: %global with_vtysh 1 } + %{!?with_pam: %global with_pam 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_irdp: %global with_irdp 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_isisd: %global with_isisd 1 } + %{!?with_pimd: %global with_pimd 1 } + %{!?with_shared: %global with_shared 1 } + %{!?with_multipath: %global with_multipath 64 } + %{!?quagga_user: %global quagga_user quagga } + %{!?vty_group: %global vty_group quaggavt } + %{!?with_fpm: %global with_fpm 0 } + %{!?with_watchquagga: %global with_watchquagga 1 } + +6. Build the RPM + + rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/quagga.spec + +DONE. + +If all works correctly, then you should end up with the RPMs under `rpmbuild/RPMS` +and the Source RPM under `rpmbuild/SRPMS` + + +Enabling daemons after installation of the package: +--------------------------------------------------- + +### init.d based systems (ie CentOS 6): + +1. Enable the daemons as needed to run after boot (Zebra is mandatory) + + chkconfig zebra on + chkconfig ospfd on + chkconfig ospf6d on + chkconfig bgpd on + ... etc + +2. If you want to run `watchquagga`, then configure `/etc/sysconfig/quagga` + and uncomment the line with the daemons for `watchquagga` to monitor, + then enable watchquagga + + chkconfig watchquagga on + +3. Check your firewall / IPtables to make sure the routing protocols are +allowed. + +4. Start the daemons (or reboot) + + service zebra start + service bgpd start + service ospfd start + ... etc + +Configuration is stored in `/etc/quagga/*.conf` files. + + +### systemd based systems (ie CentOS 7, Fedora 22) + +1. Enable the daemons as needed to run after boot (Zebra is mandatory) + + systemctl enable zebra + systemctl enable ospfd + systemctl enable ospf6d + systemctl enable bgpd + ... etc + + Note: There is no watchquagga on systemd based systems. Systemd contains + the functionality of monitoring and restarting daemons. + +2. Check your firewall / IPtables to make sure the routing protocols are +allowed. + +3. Start the daemons (or reboot) + + systemctl start zebra + systemctl start bgpd + systemctl start ospfd + ... etc + +Configuration is stored in `/etc/quagga/*.conf` files. + diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 746922a03a..13fdc07983 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -2,6 +2,7 @@ # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' +# (use any value, ie 1 for flag "with_XXXX" definitions) # # E.g. rpmbuild --define 'release_rev 02' may be useful if building # rpms again and again on the same day, so the newer rpms can be installed. @@ -9,107 +10,141 @@ ####################### Quagga configure options ######################### # with-feature options -%{!?with_snmp: %define with_snmp 1 } -%{!?with_vtysh: %define with_vtysh 1 } -%{!?with_ospf_te: %define with_ospf_te 1 } -%{!?with_nssa: %define with_nssa 1 } -%{!?with_opaque_lsa: %define with_opaque_lsa 1 } -%{!?with_tcp_zebra: %define with_tcp_zebra 0 } -%{!?with_vtysh: %define with_vtysh 1 } -%{!?with_pam: %define with_pam 1 } -%{!?with_ospfclient: %define with_ospfclient 1 } -%{!?with_ospfapi: %define with_ospfapi 1 } -%{!?with_irdp: %define with_irdp 1 } -%{!?with_rtadv: %define with_rtadv 1 } -%{!?with_isisd: %define with_isisd 1 } -%{!?with_pimd: %define with_pimd 1 } -%{!?with_shared: %define with_shared 1 } -%{!?with_multipath: %define with_multipath 64 } -%{!?quagga_user: %define quagga_user quagga } -%{!?vty_group: %define vty_group quaggavty } +%{!?with_snmp: %global with_snmp 1 } +%{!?with_vtysh: %global with_vtysh 1 } +%{!?with_tcp_zebra: %global with_tcp_zebra 0 } +%{!?with_vtysh: %global with_vtysh 1 } +%{!?with_pam: %global with_pam 1 } +%{!?with_ospfclient: %global with_ospfclient 1 } +%{!?with_ospfapi: %global with_ospfapi 1 } +%{!?with_irdp: %global with_irdp 1 } +%{!?with_rtadv: %global with_rtadv 1 } +%{!?with_isisd: %global with_isisd 1 } +%{!?with_pimd: %global with_pimd 1 } +%{!?with_shared: %global with_shared 1 } +%{!?with_multipath: %global with_multipath 64 } +%{!?quagga_user: %global quagga_user quagga } +%{!?vty_group: %global vty_group quaggavt } +%{!?with_fpm: %global with_fpm 0 } +%{!?with_watchquagga: %global with_watchquagga 1 } # path defines %define _sysconfdir /etc/quagga -%define zeb_src %{_builddir}/%{name}-%{version} +%define zeb_src %{_builddir}/%{name}-%{quaggaversion} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure -%define _libexecdir %{_exec_prefix}/libexec/quagga -%define _libdir %{_exec_prefix}/%{_lib}/quagga -%define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ -####################### distro specific tweaks ############################# -# default distro. Override with rpmbuild -D "dist XXX" -%{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} -%{!?dist: %define dist %{default_dist}} +#### Version String tweak +# Remove invalid characters form version string and replace with _ +%{expand: %%define rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} +%define quaggaversion @VERSION@ -# as distros change packages we depend on, our Requires have to change, sadly. -%define quagga_buildreqs texi2html texinfo autoconf pam-devel -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} patch libcap-devel +#### Check version of texi2html +# Old versions don't support "--number-footnotes" option. +%{expand: %%global texi2htmlversion %(rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1 )} -# FC4 and 5 split texi2html out of tetex package. -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} texi2html +#### Check for systemd or init.d (upstart) +# Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) +%{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)} +# +# If init system is systemd, then always disable watchquagga +# +%if "%{initsystem}" == "systemd" + # Note: For systems with systemd, watchquagga will NOT be built. Systemd + # takes over the role of restarting crashed processes. Value will + # be overwritten with 0 below for systemd independent on the setting here + %global with_watchquagga 0 +%endif -# man page probably needs groff for groff_ms macros -%define quagga_buildreqs %{expand:%{quagga_buildreqs}} groff - -############################################################################ +# if FPM is enabled, then enable tcp_zebra as well +# +%if %{with_fpm} + %global with_tcp_zebra 1 +%endif # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } +%{!?vty_gid: %define vty_gid 85 } + %define daemon_list zebra ripd ospfd bgpd %define daemonv6_list ripngd ospf6d %if %{with_isisd} -%define daemon_other isisd +%define daemon_isisd isisd %else -%define daemon_other "" +%define daemon_isisd "" %endif -%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga +%if %{with_pimd} +%define daemon_pimd pimd +%else +%define daemon_pimd "" +%endif + +%if %{with_watchquagga} +%define daemon_watchquagga watchquagga +%else +%define daemon_watchquagga "" +%endif + +%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_watchquagga} # allow build dir to be kept -%{!?keep_build: %define keep_build 0 } +%{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon -Name: quagga -Version: @VERSION@ -Release: @CONFDATE@%{release_rev} -License: GPL -Group: System Environment/Daemons -Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz -URL: http://www.quagga.net +Name: quagga +Version: %{rpmversion} +Release: @CONFDATE@%{release_rev}%{?dist} +License: GPLv2+ +Group: System Environment/Daemons +Source0: http://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz +URL: http://www.quagga.net +Requires: ncurses +Requires(pre): /sbin/install-info +Requires(preun): /sbin/install-info +Requires(post): /sbin/install-info +BuildRequires: texi2html texinfo autoconf patch libcap-devel groff %if %{with_snmp} BuildRequires: net-snmp-devel -Requires(pre): net-snmp +Requires: net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel -Requires(pre): ncurses +Requires: ncurses %endif -BuildRequires: %{quagga_buildreqs} +%if %{with_pam} +BuildRequires: pam-devel +Requires: pam +%endif +%if "%{initsystem}" == "systemd" +BuildRequires: systemd +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +%else # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 -Requires(pre): ncurses pam -Requires(pre): /sbin/install-info -Provides: routingdaemon -BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: bird gated mrt zebra +%endif +Provides: routingdaemon = %{version}-%{release} +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Obsoletes: bird gated mrt zebra quagga-sysvinit %description Quagga 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. -Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. +Quagga supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng and PIM. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. @@ -127,13 +162,14 @@ Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep -%setup -q +%setup -q -n quagga-%{quaggaversion} %build @@ -148,6 +184,11 @@ developing OSPF-API and quagga applications. #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ + --sysconfdir=%{_sysconfdir} \ + --libdir=%{_libdir} \ + --libexecdir=%{_libexecdir} \ + --localstatedir=%{_localstatedir} \ + --disable-werror \ %if !%{with_shared} --disable-shared \ %endif @@ -160,15 +201,6 @@ developing OSPF-API and quagga applications. %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif -%if %{with_nssa} - --enable-nssa \ -%endif -%if %{with_opaque_lsa} - --enable-opaque-lsa \ -%endif -%if %{with_ospf_te} - --enable-ospf-te \ -%endif %if %{with_vtysh} --enable-vtysh \ %endif @@ -200,57 +232,79 @@ developing OSPF-API and quagga applications. %if %{with_pam} --with-libpam \ %endif -%if %quagga_user +%if 0%{?quagga_user:1} --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif -%if %vty_group +%if 0%{?vty_group:1} --enable-vty-group=%vty_group \ %endif ---enable-netlink --enable-gcc-rdynamic +%if %{with_fpm} + --enable-fpm \ +%else + --disable-fpm \ +%endif +%if %{with_watchquagga} + --enable-watchquagga \ +%else + --disable-watchquagga \ +%endif + --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc +%if %{texi2htmlversion} < 5 +texi2html --number-sections quagga.texi +%else texi2html --number-footnotes --number-sections quagga.texi +%endif popd %install -rm -rf $RPM_BUILD_ROOT - -install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ - $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} - -make install \ - DESTDIR=$RPM_BUILD_ROOT +mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ + %{buildroot}/var/log/quagga %{buildroot}%{_infodir} +make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 -rm -rf $RPM_BUILD_ROOT/usr/share/info/dir +rm -rf %{buildroot}/usr/share/info/dir -# install etc sources +# install /etc sources +%if "%{initsystem}" == "systemd" +mkdir -p %{buildroot}%{_unitdir} +for daemon in %{all_daemons} ; do + if [ x"${daemon}" != x"" ] ; then + install %{zeb_rh_src}/${daemon}.service \ + %{buildroot}%{_unitdir}/${daemon}.service + fi +done +%else +mkdir -p %{buildroot}/etc/rc.d/init.d for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ - $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} + %{buildroot}/etc/rc.d/init.d/${daemon} fi done +%endif + install -m644 %{zeb_rh_src}/quagga.pam \ - $RPM_BUILD_ROOT/etc/pam.d/quagga + %{buildroot}/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ - $RPM_BUILD_ROOT/etc/logrotate.d/quagga + %{buildroot}/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ - $RPM_BUILD_ROOT/etc/sysconfig/quagga -install -d -m750 $RPM_BUILD_ROOT/var/run/quagga + %{buildroot}/etc/sysconfig/quagga +install -d -m750 %{buildroot}/var/run/quagga %pre # add vty_group -%if %vty_group +%if 0%{?vty_group:1} if getent group %vty_group > /dev/null ; then : ; else \ - /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi + /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi %endif # add quagga user and group -%if %quagga_user +%if 0%{?quagga_user:1} # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ @@ -289,77 +343,145 @@ zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif -for daemon in %daemon_list ; do +%if "%{initsystem}" == "systemd" +for daemon in %all_daemons ; do + %systemd_post ${daemon}.service +done +%else +for daemon in %all_daemons ; do /sbin/chkconfig --add ${daemon} done +%endif /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf -%if %{quagga_user} - chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf +%if 0%{?quagga_user:1} + chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf* %endif chmod 640 %{_sysconfdir}/zebra.conf fi +for daemon in %{all_daemons} ; do + if [ ! -e %{_sysconfdir}/${daemon}.conf ]; then + touch %{_sysconfdir}/${daemon}.conf + %if 0%{?quagga_user:1} + chown %quagga_user:%quagga_user %{_sysconfdir}/${daemon}.conf* + %endif + fi +done +%if %{with_watchquagga} + # No config for watchquagga - this is part of /etc/sysconfig/quagga + rm -f %{_sysconfdir}/watchquagga.* +%endif + if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf +%if 0%{?vty_group:1} + chown quagga:%{vty_group} %{_sysconfdir}/vtysh.conf* +%endif fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do - if [ -f /var/lock/subsys/$daemon ]; then - eval restart_$daemon=yes + if [ -f /var/lock/subsys/${daemon} ]; then + eval restart_${daemon}=yes else - eval restart_$daemon=no + eval restart_${daemon}=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no - running_watchquagga="$restart_watchquagga" - restart_watchquagga=no - # Stop watchquagga first. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 - # Stop all daemons other than zebra and watchquagga. - for daemon in %all_daemons ; do - eval restart=\$restart_${daemon} - [ "$restart" = yes ] && \ - /etc/rc.d/init.d/$daemon stop >/dev/null 2>&1 - done - # Restart zebra. - [ "$running_zebra" = yes ] && \ - /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 - # Start all daemons other than zebra and watchquagga. - for daemon in %all_daemons ; do - eval restart=\$restart_${daemon} - [ "$restart" = yes ] && \ - /etc/rc.d/init.d/$daemon start >/dev/null 2>&1 - done - # Start watchquagga last. - # Avoid postun scriptlet error if watchquagga is not running. - [ "$running_watchquagga" = yes ] && \ - /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : + %if %{with_watchquagga} + running_watchquagga="$restart_watchquagga" + restart_watchquagga=no + %endif + + %if "%{initsystem}" == "systemd" + ## + ## Systemd Version + ## + # No watchquagga for systemd version + # + # Stop all daemons other than zebra. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + %systemd_postun ${daemon}.service + done + # Restart zebra. + [ "$running_zebra" = yes ] && \ + %systemd_postun_with_restart $daemon.service + # Start all daemons other than zebra. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + %systemd_post ${daemon}.service + done + %else + ## + ## init.d Version + ## + %if %{with_watchquagga} + # Stop watchquagga first. + [ "$running_watchquagga" = yes ] && \ + /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 + %endif + # Stop all daemons other than zebra and watchquagga. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 + done + # Restart zebra. + [ "$running_zebra" = yes ] && \ + /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 + # Start all daemons other than zebra and watchquagga. + for daemon in %all_daemons ; do + eval restart=\$restart_${daemon} + [ "$restart" = yes ] && \ + /etc/rc.d/init.d/${daemon} start >/dev/null 2>&1 + done + %if %{with_watchquagga} + # Start watchquagga last. + # Avoid postun scriptlet error if watchquagga is not running. + [ "$running_watchquagga" = yes ] && \ + /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : + %endif + %endif fi -/sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun -if [ "$1" = "0" ]; then - for daemon in %all_daemons ; do - /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 - /sbin/chkconfig --del ${daemon} - done - /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir -fi +%if "%{initsystem}" == "systemd" + ## + ## Systemd Version + ## + if [ "$1" = "0" ]; then + for daemon in %all_daemons ; do + %systemd_preun ${daemon}.service + done + fi +%else + ## + ## init.d Version + ## + if [ "$1" = "0" ]; then + for daemon in %all_daemons ; do + /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 + /sbin/chkconfig --del ${daemon} + done + fi +%endif +/sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %clean -%if !%{keep_build} -rm -rf $RPM_BUILD_ROOT +%if !0%{?keep_build:1} +rm -rf %{buildroot} %endif %files @@ -368,26 +490,27 @@ rm -rf $RPM_BUILD_ROOT %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO -%if %{quagga_user} +%if 0%{?quagga_user:1} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga -%dir %attr(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif -%if %{vty_group} +%if 0%{?vty_group:1} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif -%{_infodir}/*info* +%{_infodir}/quagga.info.gz %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd -%{_sbindir}/watchquagga +%if %{with_watchquagga} + %{_sbindir}/watchquagga +%endif %{_sbindir}/ripngd %{_sbindir}/ospf6d %if %{with_pimd} @@ -396,17 +519,33 @@ rm -rf $RPM_BUILD_ROOT %if %{with_isisd} %{_sbindir}/isisd %endif -%dir %attr(755,root,root) %{_libdir} %if %{with_shared} -%dir %{_libdir} -%{_libdir}/lib*.so -%{_libdir}/lib*.so.* +%attr(755,root,root) %{_libdir}/lib*.so +%attr(755,root,root) %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* -%config /etc/rc.d/init.d/* +%if "%{initsystem}" == "systemd" + %config %{_unitdir}/*.service +%else + %config /etc/rc.d/init.d/zebra + %if %{with_watchquagga} + %config /etc/rc.d/init.d/watchquagga + %endif + %config /etc/rc.d/init.d/ripd + %config /etc/rc.d/init.d/ospfd + %config /etc/rc.d/init.d/bgpd + %config /etc/rc.d/init.d/ripngd + %config /etc/rc.d/init.d/ospf6d + %if %{with_isisd} + %config /etc/rc.d/init.d/isisd + %endif + %if %{with_pimd} + %config /etc/rc.d/init.d/pimd + %endif +%endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* @@ -432,17 +571,27 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog -* Fri Sep 4 2015 Paul Jakma - %{version} -- package the pimd binary +* Thu Feb 11 2016 Paul Jakma - %{version} - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. -* Fri Sep 4 2015 Paul Jakma - %{version} +* Thu Oct 22 2015 Martin Winter +- Cleanup configure: remove --enable-ipv6 (default now), --enable-nssa, + --enable-netlink +- Remove support for old fedora 4/5 +- Fix for package nameing +- Fix Weekdays of previous changelogs (bogus dates) +- Add conditional logic to only build tex footnotes with supported texi2html +- Added pimd to files section and fix double listing of /var/lib*/quagga +- Numerous fixes to unify upstart/systemd startup into same spec file +- Only allow use of watchquagga for non-systemd systems. no need with systemd + +* Fri Sep 4 2015 Paul Jakma - buildreq updates - add a default define for with_pimd -* Thu Sep 12 2005 Paul Jakma +* Mon Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding @@ -495,7 +644,7 @@ rm -rf $RPM_BUILD_ROOT - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) -- delete info file on %preun, not %postun to avoid deletion on upgrade. (RH) +- delete info file on preun, not postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon @@ -507,10 +656,10 @@ rm -rf $RPM_BUILD_ROOT - Renamed to Quagga - Sync to Quagga release 0.96 -* Tue Mar 20 2003 Paul Jakma +* Thu Mar 20 2003 Paul Jakma - zebra privileges support -* Mon Mar 18 2003 Paul Jakma +* Tue Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp @@ -534,7 +683,7 @@ rm -rf $RPM_BUILD_ROOT - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp -- Added conditional to %files for %_bindir depending on vtysh +- Added conditional to files for _bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS @@ -574,7 +723,7 @@ rm -rf $RPM_BUILD_ROOT * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 -* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 +* Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) From c161bb748218a54d24abbb84ffce61eede2c8f97 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 5 Jun 2016 16:39:31 -0400 Subject: [PATCH 10/30] redhat: Cleanup redhat options. Start the cleanup of the redhat .spec file: 1) Remove snmp, it's hopelessly broken. 2) Multiple with_vtysh lines. 3) Fix vty group to be quaggavty Signed-off-by: Donald Sharp --- redhat/quagga.spec.in | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 13fdc07983..13d7606d1c 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -10,10 +10,8 @@ ####################### Quagga configure options ######################### # with-feature options -%{!?with_snmp: %global with_snmp 1 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_tcp_zebra: %global with_tcp_zebra 0 } -%{!?with_vtysh: %global with_vtysh 1 } %{!?with_pam: %global with_pam 1 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } @@ -24,7 +22,7 @@ %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } -%{!?vty_group: %global vty_group quaggavt } +%{!?vty_group: %global vty_group quaggavty } %{!?with_fpm: %global with_fpm 0 } %{!?with_watchquagga: %global with_watchquagga 1 } @@ -114,10 +112,6 @@ Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff -%if %{with_snmp} -BuildRequires: net-snmp-devel -Requires: net-snmp -%endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires: ncurses @@ -192,9 +186,6 @@ developing OSPF-API and quagga applications. %if !%{with_shared} --disable-shared \ %endif -%if %{with_snmp} - --enable-snmp \ -%endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif From 75e801b7d9b6e810936213c39eefb35dd2b3713d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 5 Jun 2016 18:02:24 -0400 Subject: [PATCH 11/30] doc: Add quagga.1 to the distribution The quagga.1 file was not part of the distribution and was not being included in the dist tar ball which caused rpm builds to fail. Signed-off-by: Donald Sharp Conflicts: doc/Makefile.am --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 96aee59d5c..36991bfa48 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -105,7 +105,7 @@ endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ - ripngd.8 vtysh.1 watchquagga.8 zebra.8 \ + ripngd.8 vtysh.1 watchquagga.8 zebra.8 quagga.1\ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) From 8c05b72b5a3714b714f0883937f796fccc664955 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 5 Jun 2016 18:04:14 -0400 Subject: [PATCH 12/30] redhat: Cleanup some unneeded parameters In the Quagga.spec file we have these fixes: 1) rpmversion was being defined but never used in it's scope. Made it global so it couldbe properly referenced. 2) Use texi2html to tell you it's version instead of rpm Note for the future to convert to mock we will need to find a different methodology to handle this. 3) vtysh/isisd and pimd are turned on by default No need to call them out. Signed-off-by: Donald Sharp Conflicts: redhat/quagga.spec.in --- redhat/quagga.spec.in | 58 ++++++++++--------------------------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 13d7606d1c..c20b5597b0 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -10,15 +10,12 @@ ####################### Quagga configure options ######################### # with-feature options -%{!?with_vtysh: %global with_vtysh 1 } %{!?with_tcp_zebra: %global with_tcp_zebra 0 } %{!?with_pam: %global with_pam 1 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } -%{!?with_isisd: %global with_isisd 1 } -%{!?with_pimd: %global with_pimd 1 } %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } @@ -38,12 +35,12 @@ #### Version String tweak # Remove invalid characters form version string and replace with _ -%{expand: %%define rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} +%{expand: %%global rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} %define quaggaversion @VERSION@ #### Check version of texi2html # Old versions don't support "--number-footnotes" option. -%{expand: %%global texi2htmlversion %(rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1 )} +%{expand: %%global texi2htmlversion %(/usr/bin/texi2html --version | cut -d. -f1)} #### Check for systemd or init.d (upstart) # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) @@ -69,21 +66,7 @@ %{!?quagga_gid: %define quagga_gid 92 } %{!?vty_gid: %define vty_gid 85 } -%define daemon_list zebra ripd ospfd bgpd - -%define daemonv6_list ripngd ospf6d - -%if %{with_isisd} -%define daemon_isisd isisd -%else -%define daemon_isisd "" -%endif - -%if %{with_pimd} -%define daemon_pimd pimd -%else -%define daemon_pimd "" -%endif +%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospfd6d %if %{with_watchquagga} %define daemon_watchquagga watchquagga @@ -91,7 +74,7 @@ %define daemon_watchquagga "" %endif -%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_watchquagga} +%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_watchquagga} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } @@ -112,10 +95,8 @@ Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff -%if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires: ncurses -%endif %if %{with_pam} BuildRequires: pam-devel Requires: pam @@ -192,9 +173,7 @@ developing OSPF-API and quagga applications. %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif -%if %{with_vtysh} --enable-vtysh \ -%endif %if %{with_ospfclient} --enable-ospfclient=yes \ %else @@ -215,11 +194,6 @@ developing OSPF-API and quagga applications. %else --enable-rtadv=no \ %endif -%if %{with_isisd} - --enable-isisd \ -%else - --disable-isisd \ -%endif %if %{with_pam} --with-libpam \ %endif @@ -240,7 +214,14 @@ developing OSPF-API and quagga applications. %else --disable-watchquagga \ %endif +<<<<<<< HEAD --enable-gcc-rdynamic +======= + --enable-gcc-rdynamic \ + --enable-isisd=yes \ + --enable-systemd=yes \ + --enable-poll=yes +>>>>>>> 5713748... rebase me make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" @@ -330,9 +311,7 @@ zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif -%if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" -%endif %if "%{initsystem}" == "systemd" for daemon in %all_daemons ; do @@ -504,19 +483,12 @@ rm -rf %{buildroot} %endif %{_sbindir}/ripngd %{_sbindir}/ospf6d -%if %{with_pimd} -%{_sbindir}/pimd -%endif -%if %{with_isisd} %{_sbindir}/isisd -%endif %if %{with_shared} %attr(755,root,root) %{_libdir}/lib*.so %attr(755,root,root) %{_libdir}/lib*.so.* %endif -%if %{with_vtysh} %{_bindir}/* -%endif %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" %config %{_unitdir}/*.service @@ -530,12 +502,8 @@ rm -rf %{buildroot} %config /etc/rc.d/init.d/bgpd %config /etc/rc.d/init.d/ripngd %config /etc/rc.d/init.d/ospf6d - %if %{with_isisd} - %config /etc/rc.d/init.d/isisd - %endif - %if %{with_pimd} - %config /etc/rc.d/init.d/pimd - %endif + %config /etc/rc.d/init.d/isisd + %config /etc/rc.d/init.d/pimd %endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga From 97da92655c3de967742564ca6d27485688fc61f1 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 4 Jun 2016 19:55:21 -0400 Subject: [PATCH 13/30] configure: Ensure systemd development is present If a users specifies that they should use systemd then ensure that the systemd can be compiled against it. Signed-off-by: Donald Sharp Conflicts: configure.ac --- configure.ac | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 30fa7bd023..6719580976 100755 --- a/configure.ac +++ b/configure.ac @@ -328,10 +328,16 @@ if test x"${enable_time_check}" != x"no" ; then fi fi -if test "${enable_systemd}" = "yes" ; then - AC_DEFINE(HAVE_SYSTEMD,,Compile systemd support in) - LIBS="$LIBS -lsystemd " -fi +case "${enable_systemd}" in + "no") ;; + "yes") + AC_CHECK_LIB(systemd, sd_notify, LIBS="$LIBS -lsystemd") + if test $ac_cv_lib_systemd_sd_notify = no; then + AC_MSG_ERROR([enable systemd has been specified but systemd development env not found on your system]) + fi + ;; + "*") ;; +esac if test "${enable_poll}" = "yes" ; then AC_DEFINE(HAVE_POLL,,Compile systemd support in) From c2f4c19cdc46601a651d620fa78b8e0186b23f34 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 4 Jun 2016 19:55:22 -0400 Subject: [PATCH 14/30] configure: Auto pick-up the correct json env Fix the code to allow Quagga to automatically compile with the correct json library. Signed-off-by: Donald Sharp Conflicts: configure.ac --- configure.ac | 8 ++++++-- lib/json.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6719580976..78d3cda268 100755 --- a/configure.ac +++ b/configure.ac @@ -49,8 +49,6 @@ dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow AC_SUBST(pkgsrcdir) AC_SUBST(pkgsrcrcdir) -LIBS="$LIBS -L/usr/include/json/ -ljson" - dnl ------------ dnl Check CFLAGS dnl ------------ @@ -314,6 +312,12 @@ if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -Wpacked -Wpadded" fi +AC_CHECK_HEADERS(json-c/json.h) +AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") +if test $ac_cv_lib_json_c_json_object_get = no; then + AC_MSG_ERROR([lib json is needed to compile]) +fi + if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then LDFLAGS="${LDFLAGS} -rdynamic" diff --git a/lib/json.h b/lib/json.h index e69b10acd2..561f7cc405 100644 --- a/lib/json.h +++ b/lib/json.h @@ -22,7 +22,11 @@ #ifndef _QUAGGA_JSON_H #define _QUAGGA_JSON_H +#if defined(HAVE_JSON_C_JSON_H) +#include +#else #include +#endif extern int use_json(const int argc, const char *argv[]); extern void json_object_string_add(struct json_object* obj, const char *key, From 909344ea4006f9975336c1019c4a42ca47fcd952 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 4 Jun 2016 19:55:23 -0400 Subject: [PATCH 15/30] debian: Remove obsoleted configure options. configure.ac has moved on, catch debian up with it. Signed-off-by: Donald Sharp --- debian/rules | 8 -------- 1 file changed, 8 deletions(-) diff --git a/debian/rules b/debian/rules index 0b859d6585..e5e3ad8c11 100755 --- a/debian/rules +++ b/debian/rules @@ -38,13 +38,6 @@ override_dh_auto_configure: --sbindir=/usr/lib/quagga \ --sysconfdir=/etc/quagga \ $(USE_SNMP) \ - --enable-vtysh \ - --enable-isisd \ - --enable-watchquagga \ - --enable-ospf-te \ - --enable-opaque-lsa \ - --enable-ipv6 \ - --enable-ospfclient=yes \ --enable-ospfapi=yes \ --enable-multipath=256 \ --enable-user=quagga \ @@ -52,7 +45,6 @@ override_dh_auto_configure: --enable-vty-group=quaggavty \ --enable-configfile-mask=0640 \ --enable-logfile-mask=0640 \ - --enable-rtadv \ --enable-werror \ --enable-gcc-rdynamic \ --with-libpam \ From fb8211bbae660361bd57bdf97e9f4deb0af5ceb9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 12:54:39 -0400 Subject: [PATCH 16/30] redhat: V6 compilation is on by default Let's not call it out as a separate item anymore. Signed-off-by: Donald Sharp (cherry picked from commit 341969b3db27bd384dc453ec0e6b4a9a6513ab8f) --- redhat/quagga.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index c20b5597b0..0e689b420a 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -74,7 +74,7 @@ %define daemon_watchquagga "" %endif -%define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_watchquagga} +%define all_daemons %{daemon_list} %{daemon_watchquagga} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } From 48eefa681673d6f3ccd7dc247fdae3487b2f5bd4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 19:00:24 -0400 Subject: [PATCH 17/30] redhat: Changes to allow Cumulus start/stop methodology Change the redhat .spec and control files to allow redhat systemd interaction to be the same as the debian style. This will allow users to use Quagga consistently across platforms. Signed-off-by: Donald Sharp Conflicts: redhat/Makefile.am --- redhat/Makefile.am | 8 +++---- redhat/bgpd.service | 14 ------------- redhat/isisd.service | 14 ------------- redhat/ospf6d.service | 14 ------------- redhat/ospfd.service | 14 ------------- redhat/quagga.spec.in | 49 +++++++++++++++++++++++-------------------- redhat/ripd.service | 14 ------------- redhat/ripngd.service | 14 ------------- redhat/zebra.service | 14 ------------- 9 files changed, 30 insertions(+), 125 deletions(-) delete mode 100644 redhat/bgpd.service delete mode 100644 redhat/isisd.service delete mode 100644 redhat/ospf6d.service delete mode 100644 redhat/ospfd.service delete mode 100644 redhat/ripd.service delete mode 100644 redhat/ripngd.service delete mode 100644 redhat/zebra.service diff --git a/redhat/Makefile.am b/redhat/Makefile.am index 695d7eae84..b52cc3150a 100644 --- a/redhat/Makefile.am +++ b/redhat/Makefile.am @@ -1,7 +1,7 @@ -EXTRA_DIST = bgpd.init bgpd.service isisd.init \ - isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ +EXTRA_DIST = bgpd.init isisd.init \ + ospf6d.init ospfd.init \ quagga.logrotate quagga.pam quagga.spec \ - quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ - watchquagga.init zebra.init zebra.service \ + quagga.sysconfig ripd.init ripngd.init \ + watchquagga.init zebra.init \ README.rpm_build.md diff --git a/redhat/bgpd.service b/redhat/bgpd.service deleted file mode 100644 index 5040284dbb..0000000000 --- a/redhat/bgpd.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=BGP routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/bgpd.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/isisd.service b/redhat/isisd.service deleted file mode 100644 index 4cdf67d67e..0000000000 --- a/redhat/isisd.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=IS-IS routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/isisd.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/ospf6d.service b/redhat/ospf6d.service deleted file mode 100644 index 3c9c466899..0000000000 --- a/redhat/ospf6d.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=OSPF routing daemon for IPv6 -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/ospf6d.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/ospfd.service b/redhat/ospfd.service deleted file mode 100644 index 5e3de23935..0000000000 --- a/redhat/ospfd.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=OSPF routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/ospfd.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 0e689b420a..253fd7c0a0 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -11,13 +11,13 @@ ####################### Quagga configure options ######################### # with-feature options %{!?with_tcp_zebra: %global with_tcp_zebra 0 } -%{!?with_pam: %global with_pam 1 } +%{!?with_pam: %global with_pam 0 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } %{!?with_shared: %global with_shared 1 } -%{!?with_multipath: %global with_multipath 64 } +%{!?with_multipath: %global with_multipath 256 } %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavty } %{!?with_fpm: %global with_fpm 0 } @@ -25,9 +25,12 @@ # path defines %define _sysconfdir /etc/quagga +%define _sbindir /usr/lib/quagga %define zeb_src %{_builddir}/%{name}-%{quaggaversion} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc +%define quagga_tools %{zeb_src}/tools +%define cumulus_dir %{zeb_src}/cumulus/etc # defines for configure %define _localstatedir /var/run/quagga @@ -52,7 +55,7 @@ # Note: For systems with systemd, watchquagga will NOT be built. Systemd # takes over the role of restarting crashed processes. Value will # be overwritten with 0 below for systemd independent on the setting here - %global with_watchquagga 0 + %global with_watchquagga 1 %endif # if FPM is enabled, then enable tcp_zebra as well @@ -62,9 +65,9 @@ %endif # misc internal defines -%{!?quagga_uid: %define quagga_uid 92 } -%{!?quagga_gid: %define quagga_gid 92 } -%{!?vty_gid: %define vty_gid 85 } +%{!?quagga_uid: %global quagga_uid 92 } +%{!?quagga_gid: %global quagga_gid 92 } +%{!?vty_gid: %global vty_gid 85 } %define daemon_list zebra ripd ospfd bgpd isisd ripngd ospfd6d @@ -80,7 +83,7 @@ %{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) -%{!?release_rev: %define release_rev 01 } +%{!?release_rev: %global release_rev 01 } Summary: Routing daemon Name: quagga @@ -159,6 +162,7 @@ developing OSPF-API and quagga applications. #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ + --sbindir=%{_sbindir} \ --sysconfdir=%{_sysconfdir} \ --libdir=%{_libdir} \ --libexecdir=%{_libexecdir} \ @@ -214,14 +218,10 @@ developing OSPF-API and quagga applications. %else --disable-watchquagga \ %endif -<<<<<<< HEAD - --enable-gcc-rdynamic -======= --enable-gcc-rdynamic \ --enable-isisd=yes \ --enable-systemd=yes \ --enable-poll=yes ->>>>>>> 5713748... rebase me make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" @@ -234,22 +234,19 @@ texi2html --number-footnotes --number-sections quagga.texi popd %install -mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ +mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d,default} \ %{buildroot}/var/log/quagga %{buildroot}%{_infodir} make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf %{buildroot}/usr/share/info/dir + # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} -for daemon in %{all_daemons} ; do - if [ x"${daemon}" != x"" ] ; then - install %{zeb_rh_src}/${daemon}.service \ - %{buildroot}%{_unitdir}/${daemon}.service - fi -done +install %{quagga_tools}/quagga.service \ + %{buildroot}%{_unitdir}/quagga.service %else mkdir -p %{buildroot}/etc/rc.d/init.d for daemon in %{all_daemons} ; do @@ -260,12 +257,13 @@ for daemon in %{all_daemons} ; do done %endif +install %{cumulus_dir}/quagga/debian.conf %{buildroot}/etc/quagga +install %{cumulus_dir}/quagga/daemons %{buildroot}/etc/quagga +install -m644 %{cumulus_dir}/default/quagga %{buildroot}/etc/default install -m644 %{zeb_rh_src}/quagga.pam \ %{buildroot}/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ %{buildroot}/etc/logrotate.d/quagga -install -m644 %{zeb_rh_src}/quagga.sysconfig \ - %{buildroot}/etc/sysconfig/quagga install -d -m750 %{buildroot}/var/run/quagga %pre @@ -315,7 +313,7 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty" %if "%{initsystem}" == "systemd" for daemon in %all_daemons ; do - %systemd_post ${daemon}.service + %systemd_post quagga.service done %else for daemon in %all_daemons ; do @@ -478,6 +476,11 @@ rm -rf %{buildroot} %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd +%{_sbindir}/ssd +%{_sbindir}/quagga +%{_sbindir}/quagga-reload.py +%{_sbindir}/quagga-reload.pyc +%{_sbindir}/quagga-reload.pyo %if %{with_watchquagga} %{_sbindir}/watchquagga %endif @@ -491,7 +494,7 @@ rm -rf %{buildroot} %{_bindir}/* %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" - %config %{_unitdir}/*.service + %config %{_unitdir}/quagga.service %else %config /etc/rc.d/init.d/zebra %if %{with_watchquagga} @@ -505,7 +508,7 @@ rm -rf %{buildroot} %config /etc/rc.d/init.d/isisd %config /etc/rc.d/init.d/pimd %endif -%config(noreplace) /etc/sysconfig/quagga +%config(noreplace) /etc/default/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* diff --git a/redhat/ripd.service b/redhat/ripd.service deleted file mode 100644 index d35dc47a12..0000000000 --- a/redhat/ripd.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=RIP routing daemon -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/ripd.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/ripngd.service b/redhat/ripngd.service deleted file mode 100644 index 567e88806c..0000000000 --- a/redhat/ripngd.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=RIP routing daemon for IPv6 -BindTo=zebra.service -After=syslog.target network.target zebra.service -ConditionPathExists=/etc/quagga/ripngd.conf - -[Service] -Type=forking -EnvironmentFile=/etc/sysconfig/quagga -ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf -Restart=on-abort - -[Install] -WantedBy=network.target diff --git a/redhat/zebra.service b/redhat/zebra.service deleted file mode 100644 index 27c3a5229f..0000000000 --- a/redhat/zebra.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=GNU Zebra routing manager -After=syslog.target network.target -ConditionPathExists=/etc/quagga/zebra.conf - -[Service] -Type=forking -EnvironmentFile=-/etc/sysconfig/quagga -ExecStartPre=/sbin/ip route flush proto zebra -ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf -Restart=on-abort - -[Install] -WantedBy=network.target From 62cd657cddfb82b0f2efa1091817fee91bbd111a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 19:05:17 -0400 Subject: [PATCH 18/30] cumulus: Changes to make this code work for redhat Modify code base to allow rpm building. Signed-off-by: Donald Sharp --- cumulus/.gitignore | 2 + cumulus/Makefile.am | 5 + .../etc/default/quagga | 0 cumulus/start-stop-daemon.c | 1058 +++++++++++++++++ 4 files changed, 1065 insertions(+) create mode 100644 cumulus/.gitignore create mode 100644 cumulus/Makefile.am rename debian/quagga.default => cumulus/etc/default/quagga (100%) create mode 100644 cumulus/start-stop-daemon.c diff --git a/cumulus/.gitignore b/cumulus/.gitignore new file mode 100644 index 0000000000..2a198f5d45 --- /dev/null +++ b/cumulus/.gitignore @@ -0,0 +1,2 @@ +*.o +ssd diff --git a/cumulus/Makefile.am b/cumulus/Makefile.am new file mode 100644 index 0000000000..852af344af --- /dev/null +++ b/cumulus/Makefile.am @@ -0,0 +1,5 @@ + +sbin_PROGRAMS = ssd +EXTRA_DIST = etc/quagga/debian.conf etc/quagga/daemons etc/default/quagga + +ssd_SOURCES = start-stop-daemon.c diff --git a/debian/quagga.default b/cumulus/etc/default/quagga similarity index 100% rename from debian/quagga.default rename to cumulus/etc/default/quagga diff --git a/cumulus/start-stop-daemon.c b/cumulus/start-stop-daemon.c new file mode 100644 index 0000000000..e317bb801c --- /dev/null +++ b/cumulus/start-stop-daemon.c @@ -0,0 +1,1058 @@ +/* + * A rewrite of the original Debian's start-stop-daemon Perl script + * in C (faster - it is executed many times during system startup). + * + * Written by Marek Michalkiewicz , + * public domain. Based conceptually on start-stop-daemon.pl, by Ian + * Jackson . May be used and distributed + * freely for any purpose. Changes by Christian Schwarz + * , to make output conform to the Debian + * Console Message Standard, also placed in public domain. Minor + * changes by Klee Dienes , also placed in the Public + * Domain. + * + * Changes by Ben Collins , added --chuid, --background + * and --make-pidfile options, placed in public domain aswell. + * + * Port to OpenBSD by Sontri Tomo Huynh + * and Andreas Schuldei + * + * Changes by Ian Jackson: added --retry (and associated rearrangements). + * + * Modified for Gentoo rc-scripts by Donny Davies : + * I removed the BSD/Hurd/OtherOS stuff, added #include + * and stuck in a #define VERSION "1.9.18". Now it compiles without + * the whole automake/config.h dance. + */ + +#ifdef HAVE_LXC +#define _GNU_SOURCE +#include +#endif /* HAVE_LXC */ + +#include +#define VERSION "1.9.18" + +#define MIN_POLL_INTERVAL 20000 /*us*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int testmode = 0; +static int quietmode = 0; +static int exitnodo = 1; +static int start = 0; +static int stop = 0; +static int background = 0; +static int mpidfile = 0; +static int signal_nr = 15; +static const char *signal_str = NULL; +static int user_id = -1; +static int runas_uid = -1; +static int runas_gid = -1; +static const char *userspec = NULL; +static char *changeuser = NULL; +static const char *changegroup = NULL; +static char *changeroot = NULL; +static const char *cmdname = NULL; +static char *execname = NULL; +static char *startas = NULL; +static const char *pidfile = NULL; +static char what_stop[1024]; +static const char *schedule_str = NULL; +static const char *progname = ""; +static int nicelevel = 0; + +static struct stat exec_stat; + +struct pid_list { + struct pid_list *next; + pid_t pid; +}; + +static struct pid_list *found = NULL; +static struct pid_list *killed = NULL; + +struct schedule_item { + enum { sched_timeout, sched_signal, sched_goto, sched_forever } type; + int value; /* seconds, signal no., or index into array */ + /* sched_forever is only seen within parse_schedule and callees */ +}; + +static int schedule_length; +static struct schedule_item *schedule = NULL; + +LIST_HEAD(namespace_head, namespace); + +struct namespace { + LIST_ENTRY(namespace) list; + char *path; + int nstype; +}; + +static struct namespace_head namespace_head; + +static void *xmalloc(int size); +static void push(struct pid_list **list, pid_t pid); +static void do_help(void); +static void parse_options(int argc, char * const *argv); +static int pid_is_user(pid_t pid, uid_t uid); +static int pid_is_cmd(pid_t pid, const char *name); +static void check(pid_t pid); +static void do_pidfile(const char *name); +static void do_stop(int signal_nr, int quietmode, + int *n_killed, int *n_notkilled, int retry_nr); +static int pid_is_exec(pid_t pid, const struct stat *esb); + +#ifdef __GNUC__ +static void fatal(const char *format, ...) + __attribute__((noreturn, format(printf, 1, 2))); +static void badusage(const char *msg) + __attribute__((noreturn)); +#else +static void fatal(const char *format, ...); +static void badusage(const char *msg); +#endif + +/* This next part serves only to construct the TVCALC macro, which + * is used for doing arithmetic on struct timeval's. It works like this: + * TVCALC(result, expression); + * where result is a struct timeval (and must be an lvalue) and + * expression is the single expression for both components. In this + * expression you can use the special values TVELEM, which when fed a + * const struct timeval* gives you the relevant component, and + * TVADJUST. TVADJUST is necessary when subtracting timevals, to make + * it easier to renormalise. Whenver you subtract timeval elements, + * you must make sure that TVADJUST is added to the result of the + * subtraction (before any resulting multiplication or what have you). + * TVELEM must be linear in TVADJUST. + */ +typedef long tvselector(const struct timeval*); +static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; } +static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; } +#define TVCALC_ELEM(result, expr, sec, adj) \ +{ \ + const long TVADJUST = adj; \ + long (*const TVELEM)(const struct timeval*) = tvselector_##sec; \ + (result).tv_##sec = (expr); \ +} +#define TVCALC(result,expr) \ +do { \ + TVCALC_ELEM(result, expr, sec, (-1)); \ + TVCALC_ELEM(result, expr, usec, (+1000000)); \ + (result).tv_sec += (result).tv_usec / 1000000; \ + (result).tv_usec %= 1000000; \ +} while(0) + + +static void +fatal(const char *format, ...) +{ + va_list arglist; + + fprintf(stderr, "%s: ", progname); + va_start(arglist, format); + vfprintf(stderr, format, arglist); + va_end(arglist); + putc('\n', stderr); + exit(2); +} + + +static void * +xmalloc(int size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr) + return ptr; + fatal("malloc(%d) failed", size); +} + +static void +xgettimeofday(struct timeval *tv) +{ + if (gettimeofday(tv,0) != 0) + fatal("gettimeofday failed: %s", strerror(errno)); +} + +static void +push(struct pid_list **list, pid_t pid) +{ + struct pid_list *p; + + p = xmalloc(sizeof(*p)); + p->next = *list; + p->pid = pid; + *list = p; +} + +static void +clear(struct pid_list **list) +{ + struct pid_list *here, *next; + + for (here = *list; here != NULL; here = next) { + next = here->next; + free(here); + } + + *list = NULL; +} + +static char * +next_dirname(const char *s) +{ + char *cur; + + cur = (char *)s; + + if (*cur != '\0') { + for (; *cur != '/'; ++cur) + if (*cur == '\0') + return cur; + + for (; *cur == '/'; ++cur) + ; + } + + return cur; +} + +static void +add_namespace(const char *path) +{ + int nstype; + const char *nsdirname, *nsname, *cur; + struct namespace *namespace; + + cur = (char *)path; + nsdirname = nsname = ""; + + while ((cur = next_dirname(cur))[0] != '\0') { + nsdirname = nsname; + nsname = cur; + } + + if (!memcmp(nsdirname, "ipcns/", strlen("ipcns/"))) + nstype = CLONE_NEWIPC; + else if (!memcmp(nsdirname, "netns/", strlen("netns/"))) + nstype = CLONE_NEWNET; + else if (!memcmp(nsdirname, "utcns/", strlen("utcns/"))) + nstype = CLONE_NEWUTS; + else + badusage("invalid namepspace path"); + + namespace = xmalloc(sizeof(*namespace)); + namespace->path = (char *)path; + namespace->nstype = nstype; + LIST_INSERT_HEAD(&namespace_head, namespace, list); +} + +#ifdef HAVE_LXC +static void +set_namespaces() +{ + struct namespace *namespace; + int fd; + + LIST_FOREACH(namespace, &namespace_head, list) { + if ((fd = open(namespace->path, O_RDONLY)) == -1) + fatal("open namespace %s: %s", namespace->path, strerror(errno)); + if (setns(fd, namespace->nstype) == -1) + fatal("setns %s: %s", namespace->path, strerror(errno)); + } +} +#else +static void +set_namespaces() +{ + if (!LIST_EMPTY(&namespace_head)) + fatal("LCX namespaces not supported"); +} +#endif + +static void +do_help(void) +{ + printf( +"start-stop-daemon " VERSION " for Debian - small and fast C version written by\n" +"Marek Michalkiewicz , public domain.\n" +"\n" +"Usage:\n" +" start-stop-daemon -S|--start options ... -- arguments ...\n" +" start-stop-daemon -K|--stop options ...\n" +" start-stop-daemon -H|--help\n" +" start-stop-daemon -V|--version\n" +"\n" +"Options (at least one of --exec|--pidfile|--user is required):\n" +" -x|--exec program to start/check if it is running\n" +" -p|--pidfile pid file to check\n" +" -c|--chuid \n" +" change to this user/group before starting process\n" +" -u|--user | stop processes owned by this user\n" +" -n|--name stop processes with this name\n" +" -s|--signal signal to send (default TERM)\n" +" -a|--startas program to start (default is )\n" +" -N|--nicelevel add incr to the process's nice level\n" +" -b|--background force the process to detach\n" +" -m|--make-pidfile create the pidfile before starting\n" +" -R|--retry check whether processes die, and retry\n" +" -t|--test test mode, don't do anything\n" +" -o|--oknodo exit status 0 (not 1) if nothing done\n" +" -q|--quiet be more quiet\n" +" -v|--verbose be more verbose\n" +"Retry is |//... where is one of\n" +" -|[-] send that signal\n" +" wait that many seconds\n" +" forever repeat remainder forever\n" +"or may be just , meaning //KILL/\n" +"\n" +"Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo)\n" +" 3 = trouble 2 = with --retry, processes wouldn't die\n"); +} + + +static void +badusage(const char *msg) +{ + if (msg) + fprintf(stderr, "%s: %s\n", progname, msg); + fprintf(stderr, "Try `%s --help' for more information.\n", progname); + exit(3); +} + +struct sigpair { + const char *name; + int signal; +}; + +const struct sigpair siglist[] = { + { "ABRT", SIGABRT }, + { "ALRM", SIGALRM }, + { "FPE", SIGFPE }, + { "HUP", SIGHUP }, + { "ILL", SIGILL }, + { "INT", SIGINT }, + { "KILL", SIGKILL }, + { "PIPE", SIGPIPE }, + { "QUIT", SIGQUIT }, + { "SEGV", SIGSEGV }, + { "TERM", SIGTERM }, + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { "CHLD", SIGCHLD }, + { "CONT", SIGCONT }, + { "STOP", SIGSTOP }, + { "TSTP", SIGTSTP }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU } +}; + +static int parse_integer (const char *string, int *value_r) { + unsigned long ul; + char *ep; + + if (!string[0]) + return -1; + + ul= strtoul(string,&ep,10); + if (ul > INT_MAX || *ep != '\0') + return -1; + + *value_r= ul; + return 0; +} + +static int parse_signal (const char *signal_str, int *signal_nr) +{ + unsigned int i; + + if (parse_integer(signal_str, signal_nr) == 0) + return 0; + + for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) { + if (strcmp (signal_str, siglist[i].name) == 0) { + *signal_nr = siglist[i].signal; + return 0; + } + } + return -1; +} + +static void +parse_schedule_item(const char *string, struct schedule_item *item) { + const char *after_hyph; + + if (!strcmp(string,"forever")) { + item->type = sched_forever; + } else if (isdigit(string[0])) { + item->type = sched_timeout; + if (parse_integer(string, &item->value) != 0) + badusage("invalid timeout value in schedule"); + } else if ((after_hyph = string + (string[0] == '-')) && + parse_signal(after_hyph, &item->value) == 0) { + item->type = sched_signal; + } else { + badusage("invalid schedule item (must be [-], " + "-, or `forever'"); + } +} + +static void +parse_schedule(const char *schedule_str) { + char item_buf[20]; + const char *slash; + int count, repeatat; + ptrdiff_t str_len; + + count = 0; + for (slash = schedule_str; *slash; slash++) + if (*slash == '/') + count++; + + schedule_length = (count == 0) ? 4 : count+1; + schedule = xmalloc(sizeof(*schedule) * schedule_length); + + if (count == 0) { + schedule[0].type = sched_signal; + schedule[0].value = signal_nr; + parse_schedule_item(schedule_str, &schedule[1]); + if (schedule[1].type != sched_timeout) { + badusage ("--retry takes timeout, or schedule list" + " of at least two items"); + } + schedule[2].type = sched_signal; + schedule[2].value = SIGKILL; + schedule[3]= schedule[1]; + } else { + count = 0; + repeatat = -1; + while (schedule_str != NULL) { + slash = strchr(schedule_str,'/'); + str_len = slash ? slash - schedule_str : (ptrdiff_t)strlen(schedule_str); + if (str_len >= (ptrdiff_t)sizeof(item_buf)) + badusage("invalid schedule item: far too long" + " (you must delimit items with slashes)"); + memcpy(item_buf, schedule_str, str_len); + item_buf[str_len] = 0; + schedule_str = slash ? slash+1 : NULL; + + parse_schedule_item(item_buf, &schedule[count]); + if (schedule[count].type == sched_forever) { + if (repeatat >= 0) + badusage("invalid schedule: `forever'" + " appears more than once"); + repeatat = count; + continue; + } + count++; + } + if (repeatat >= 0) { + schedule[count].type = sched_goto; + schedule[count].value = repeatat; + count++; + } + assert(count == schedule_length); + } +} + +static void +parse_options(int argc, char * const *argv) +{ + static struct option longopts[] = { + { "help", 0, NULL, 'H'}, + { "stop", 0, NULL, 'K'}, + { "start", 0, NULL, 'S'}, + { "version", 0, NULL, 'V'}, + { "startas", 1, NULL, 'a'}, + { "name", 1, NULL, 'n'}, + { "oknodo", 0, NULL, 'o'}, + { "pidfile", 1, NULL, 'p'}, + { "quiet", 0, NULL, 'q'}, + { "signal", 1, NULL, 's'}, + { "test", 0, NULL, 't'}, + { "user", 1, NULL, 'u'}, + { "chroot", 1, NULL, 'r'}, + { "namespace", 1, NULL, 'd'}, + { "verbose", 0, NULL, 'v'}, + { "exec", 1, NULL, 'x'}, + { "chuid", 1, NULL, 'c'}, + { "nicelevel", 1, NULL, 'N'}, + { "background", 0, NULL, 'b'}, + { "make-pidfile", 0, NULL, 'm'}, + { "retry", 1, NULL, 'R'}, + { NULL, 0, NULL, 0} + }; + int c; + + for (;;) { + c = getopt_long(argc, argv, "HKSVa:n:op:qr:d:s:tu:vx:c:N:bmR:", + longopts, (int *) 0); + if (c == -1) + break; + switch (c) { + case 'H': /* --help */ + do_help(); + exit(0); + case 'K': /* --stop */ + stop = 1; + break; + case 'S': /* --start */ + start = 1; + break; + case 'V': /* --version */ + printf("start-stop-daemon " VERSION "\n"); + exit(0); + case 'a': /* --startas */ + startas = optarg; + break; + case 'n': /* --name */ + cmdname = optarg; + break; + case 'o': /* --oknodo */ + exitnodo = 0; + break; + case 'p': /* --pidfile */ + pidfile = optarg; + break; + case 'q': /* --quiet */ + quietmode = 1; + break; + case 's': /* --signal */ + signal_str = optarg; + break; + case 't': /* --test */ + testmode = 1; + break; + case 'u': /* --user | */ + userspec = optarg; + break; + case 'v': /* --verbose */ + quietmode = -1; + break; + case 'x': /* --exec */ + execname = optarg; + break; + case 'c': /* --chuid | */ + /* we copy the string just in case we need the + * argument later. */ + changeuser = strdup(optarg); + changeuser = strtok(changeuser, ":"); + changegroup = strtok(NULL, ":"); + break; + case 'r': /* --chroot /new/root */ + changeroot = optarg; + break; + case 'd': /* --namespace /.../||/name */ + add_namespace(optarg); + break; + case 'N': /* --nice */ + nicelevel = atoi(optarg); + break; + case 'b': /* --background */ + background = 1; + break; + case 'm': /* --make-pidfile */ + mpidfile = 1; + break; + case 'R': /* --retry | */ + schedule_str = optarg; + break; + default: + badusage(NULL); /* message printed by getopt */ + } + } + + if (signal_str != NULL) { + if (parse_signal (signal_str, &signal_nr) != 0) + badusage("signal value must be numeric or name" + " of signal (KILL, INTR, ...)"); + } + + if (schedule_str != NULL) { + parse_schedule(schedule_str); + } + + if (start == stop) + badusage("need one of --start or --stop"); + + if (!execname && !pidfile && !userspec && !cmdname) + badusage("need at least one of --exec, --pidfile, --user or --name"); + + if (!startas) + startas = execname; + + if (start && !startas) + badusage("--start needs --exec or --startas"); + + if (mpidfile && pidfile == NULL) + badusage("--make-pidfile is only relevant with --pidfile"); + + if (background && !start) + badusage("--background is only relevant with --start"); + +} + +static int +pid_is_exec(pid_t pid, const struct stat *esb) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d/exe", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino); +} + + +static int +pid_is_user(pid_t pid, uid_t uid) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == uid); +} + + +static int +pid_is_cmd(pid_t pid, const char *name) +{ + char buf[32]; + FILE *f; + int c; + + sprintf(buf, "/proc/%d/stat", pid); + f = fopen(buf, "r"); + if (!f) + return 0; + while ((c = getc(f)) != EOF && c != '(') + ; + if (c != '(') { + fclose(f); + return 0; + } + /* this hopefully handles command names containing ')' */ + while ((c = getc(f)) != EOF && c == *name) + name++; + fclose(f); + return (c == ')' && *name == '\0'); +} + + +static void +check(pid_t pid) +{ + if (execname && !pid_is_exec(pid, &exec_stat)) + return; + if (userspec && !pid_is_user(pid, user_id)) + return; + if (cmdname && !pid_is_cmd(pid, cmdname)) + return; + push(&found, pid); +} + +static void +do_pidfile(const char *name) +{ + FILE *f; + pid_t pid; + + f = fopen(name, "r"); + if (f) { + if (fscanf(f, "%d", &pid) == 1) + check(pid); + fclose(f); + } else if (errno != ENOENT) + fatal("open pidfile %s: %s", name, strerror(errno)); + +} + +/* WTA: this needs to be an autoconf check for /proc/pid existance. + */ +static void +do_procinit(void) +{ + DIR *procdir; + struct dirent *entry; + int foundany; + pid_t pid; + + procdir = opendir("/proc"); + if (!procdir) + fatal("opendir /proc: %s", strerror(errno)); + + foundany = 0; + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &pid) != 1) + continue; + foundany++; + check(pid); + } + closedir(procdir); + if (!foundany) + fatal("nothing in /proc - not mounted?"); +} + +static void +do_findprocs(void) +{ + clear(&found); + + if (pidfile) + do_pidfile(pidfile); + else + do_procinit(); +} + +/* return 1 on failure */ +static void +do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr) +{ + struct pid_list *p; + + do_findprocs(); + + *n_killed = 0; + *n_notkilled = 0; + + if (!found) + return; + + clear(&killed); + + for (p = found; p; p = p->next) { + if (testmode) + printf("Would send signal %d to %d.\n", + signal_nr, p->pid); + else if (kill(p->pid, signal_nr) == 0) { + push(&killed, p->pid); + (*n_killed)++; + } else { + printf("%s: warning: failed to kill %d: %s\n", + progname, p->pid, strerror(errno)); + (*n_notkilled)++; + } + } + if (quietmode < 0 && killed) { + printf("Stopped %s (pid", what_stop); + for (p = killed; p; p = p->next) + printf(" %d", p->pid); + putchar(')'); + if (retry_nr > 0) + printf(", retry #%d", retry_nr); + printf(".\n"); + } +} + + +static void +set_what_stop(const char *str) +{ + strncpy(what_stop, str, sizeof(what_stop)); + what_stop[sizeof(what_stop)-1] = '\0'; +} + +static int +run_stop_schedule(void) +{ + int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr; + struct timeval stopat, before, after, interval, maxinterval; + + if (testmode) { + if (schedule != NULL) { + printf("Ignoring --retry in test mode\n"); + schedule = NULL; + } + } + + if (cmdname) + set_what_stop(cmdname); + else if (execname) + set_what_stop(execname); + else if (pidfile) + sprintf(what_stop, "process in pidfile `%.200s'", pidfile); + else if (userspec) + sprintf(what_stop, "process(es) owned by `%.200s'", userspec); + else + fatal("internal error, please report"); + + anykilled = 0; + retry_nr = 0; + + if (schedule == NULL) { + do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0); + if (n_notkilled > 0 && quietmode <= 0) + printf("%d pids were not killed\n", n_notkilled); + if (n_killed) + anykilled = 1; + goto x_finished; + } + + for (position = 0; position < schedule_length; ) { + value= schedule[position].value; + n_notkilled = 0; + + switch (schedule[position].type) { + + case sched_goto: + position = value; + continue; + + case sched_signal: + do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++); + if (!n_killed) + goto x_finished; + else + anykilled = 1; + goto next_item; + + case sched_timeout: + /* We want to keep polling for the processes, to see if they've exited, + * or until the timeout expires. + * + * This is a somewhat complicated algorithm to try to ensure that we + * notice reasonably quickly when all the processes have exited, but + * don't spend too much CPU time polling. In particular, on a fast + * machine with quick-exiting daemons we don't want to delay system + * shutdown too much, whereas on a slow one, or where processes are + * taking some time to exit, we want to increase the polling + * interval. + * + * The algorithm is as follows: we measure the elapsed time it takes + * to do one poll(), and wait a multiple of this time for the next + * poll. However, if that would put us past the end of the timeout + * period we wait only as long as the timeout period, but in any case + * we always wait at least MIN_POLL_INTERVAL (20ms). The multiple + * (`ratio') starts out as 2, and increases by 1 for each poll to a + * maximum of 10; so we use up to between 30% and 10% of the + * machine's resources (assuming a few reasonable things about system + * performance). + */ + xgettimeofday(&stopat); + stopat.tv_sec += value; + ratio = 1; + for (;;) { + xgettimeofday(&before); + if (timercmp(&before,&stopat,>)) + goto next_item; + + do_stop(0, 1, &n_killed, &n_notkilled, 0); + if (!n_killed) + goto x_finished; + + xgettimeofday(&after); + + if (!timercmp(&after,&stopat,<)) + goto next_item; + + if (ratio < 10) + ratio++; + + TVCALC(interval, ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST)); + TVCALC(maxinterval, TVELEM(&stopat) - TVELEM(&after) + TVADJUST); + + if (timercmp(&interval,&maxinterval,>)) + interval = maxinterval; + + if (interval.tv_sec == 0 && + interval.tv_usec <= MIN_POLL_INTERVAL) + interval.tv_usec = MIN_POLL_INTERVAL; + + r = select(0,0,0,0,&interval); + if (r < 0 && errno != EINTR) + fatal("select() failed for pause: %s", + strerror(errno)); + } + + default: + assert(!"schedule[].type value must be valid"); + + } + + next_item: + position++; + } + + if (quietmode <= 0) + printf("Program %s, %d process(es), refused to die.\n", + what_stop, n_killed); + + return 2; + +x_finished: + if (!anykilled) { + if (quietmode <= 0) + printf("No %s found running; none killed.\n", what_stop); + return exitnodo; + } else { + return 0; + } +} + +/* +int main(int argc, char **argv) NONRETURNING; +*/ + +int +main(int argc, char **argv) +{ + progname = argv[0]; + + LIST_INIT(&namespace_head); + + parse_options(argc, argv); + argc -= optind; + argv += optind; + + if (execname && stat(execname, &exec_stat)) + fatal("stat %s: %s", execname, strerror(errno)); + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + fatal("user `%s' not found\n", userspec); + + user_id = pw->pw_uid; + } + + if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) { + struct group *gr = getgrnam(changegroup); + if (!gr) + fatal("group `%s' not found\n", changegroup); + runas_gid = gr->gr_gid; + } + if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) { + struct passwd *pw = getpwnam(changeuser); + if (!pw) + fatal("user `%s' not found\n", changeuser); + runas_uid = pw->pw_uid; + if (changegroup == NULL) { /* pass the default group of this user */ + changegroup = ""; /* just empty */ + runas_gid = pw->pw_gid; + } + } + + if (stop) { + int i = run_stop_schedule(); + exit(i); + } + + do_findprocs(); + + if (found) { + if (quietmode <= 0) + printf("%s already running.\n", execname); + exit(exitnodo); + } + if (testmode) { + printf("Would start %s ", startas); + while (argc-- > 0) + printf("%s ", *argv++); + if (changeuser != NULL) { + printf(" (as user %s[%d]", changeuser, runas_uid); + if (changegroup != NULL) + printf(", and group %s[%d])", changegroup, runas_gid); + else + printf(")"); + } + if (changeroot != NULL) + printf(" in directory %s", changeroot); + if (nicelevel) + printf(", and add %i to the priority", nicelevel); + printf(".\n"); + exit(0); + } + if (quietmode < 0) + printf("Starting %s...\n", startas); + *--argv = startas; + if (changeroot != NULL) { + if (chdir(changeroot) < 0) + fatal("Unable to chdir() to %s", changeroot); + if (chroot(changeroot) < 0) + fatal("Unable to chroot() to %s", changeroot); + } + if (changeuser != NULL) { + if (setgid(runas_gid)) + fatal("Unable to set gid to %d", runas_gid); + if (initgroups(changeuser, runas_gid)) + fatal("Unable to set initgroups() with gid %d", runas_gid); + if (setuid(runas_uid)) + fatal("Unable to set uid to %s", changeuser); + } + + if (background) { /* ok, we need to detach this process */ + int i, fd; + if (quietmode < 0) + printf("Detatching to start %s...", startas); + i = fork(); + if (i<0) { + fatal("Unable to fork.\n"); + } + if (i) { /* parent */ + if (quietmode < 0) + printf("done.\n"); + exit(0); + } + /* child continues here */ + /* now close all extra fds */ + for (i=getdtablesize()-1; i>=0; --i) close(i); + /* change tty */ + fd = open("/dev/tty", O_RDWR); + ioctl(fd, TIOCNOTTY, 0); + close(fd); + chdir("/"); + umask(022); /* set a default for dumb programs */ + setpgid(0,0); /* set the process group */ + fd=open("/dev/null", O_RDWR); /* stdin */ + dup(fd); /* stdout */ + dup(fd); /* stderr */ + } + if (nicelevel) { + errno = 0; + if (nice(nicelevel) < 0 && errno) + fatal("Unable to alter nice level by %i: %s", nicelevel, + strerror(errno)); + } + if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */ + FILE *pidf = fopen(pidfile, "w"); + pid_t pidt = getpid(); + if (pidf == NULL) + fatal("Unable to open pidfile `%s' for writing: %s", pidfile, + strerror(errno)); + fprintf(pidf, "%d\n", pidt); + fclose(pidf); + } + set_namespaces(); + execv(startas, argv); + fatal("Unable to start %s: %s", startas, strerror(errno)); +} From 4481b5b894f8bcb4d6da51742e8e69ca13b1ca3d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 19:07:49 -0400 Subject: [PATCH 19/30] debian: Modifications to allow redhat to work properly Modify the control files to allow redhat to build properly. Signed-off-by: Donald Sharp --- debian/quagga.install | 2 +- {debian => tools}/quagga.service | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {debian => tools}/quagga.service (100%) diff --git a/debian/quagga.install b/debian/quagga.install index ec1f0b275f..6a70be9925 100644 --- a/debian/quagga.install +++ b/debian/quagga.install @@ -18,5 +18,5 @@ usr/share/man/man8/isisd.8 usr/share/man/man8/watchquagga.8 usr/share/snmp/mibs/ cumulus/etc/* etc/ -debian/*.service lib/systemd/system +tools/*.service lib/systemd/system debian/quagga.conf usr/lib/tmpfiles.d diff --git a/debian/quagga.service b/tools/quagga.service similarity index 100% rename from debian/quagga.service rename to tools/quagga.service From 29366ffbe13cf2356baaff0bd981d55408dcc619 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 19:08:43 -0400 Subject: [PATCH 20/30] tools: Use the now included start-stop-daemon Redhat does not have a way to run the start-stop-daemon. This code is widely available on the internet and very small. Use the compiled start-stop-daemon(ssd) if it is included with the system. Signed-off-by: Donald Sharp --- tools/quagga | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/quagga b/tools/quagga index cf9aa661d9..19ce0b3952 100755 --- a/tools/quagga +++ b/tools/quagga @@ -27,6 +27,13 @@ RELOAD_SCRIPT=/usr/lib/quagga/quagga-reload.py . /lib/lsb/init-functions +if [ -f /usr/lib/quagga/ssd ]; then + SSD=/usr/lib/quagga/ssd +else + SSD=`which start-stop-daemon` +fi + +echo ${SSD} # Print the name of the pidfile. pidfile() { @@ -107,7 +114,7 @@ start() echo -n " $1" fi - start-stop-daemon \ + ${SSD} \ --start \ --pidfile=`pidfile $1` \ --exec "$D_PATH/$1" \ @@ -120,7 +127,7 @@ start() return; fi - start-stop-daemon \ + ${SSD} \ --start \ --pidfile=`pidfile $1-$2` \ --exec "$D_PATH/$1" \ @@ -133,7 +140,7 @@ start() return; fi - start-stop-daemon \ + ${SSD} \ --start \ --pidfile=`pidfile $1` \ --exec "$D_PATH/$1" \ @@ -159,7 +166,7 @@ stop() else PIDFILE=`pidfile $inst` PID=`cat $PIDFILE 2>/dev/null` - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --oknodo --pidfile "$PIDFILE" --exec "$D_PATH/$1" + ${SSD} --stop --quiet --retry=TERM/30/KILL/5 --oknodo --pidfile "$PIDFILE" --exec "$D_PATH/$1" # # Now we have to wait until $DAEMON has _really_ stopped. # @@ -322,7 +329,7 @@ stop_prio() fi for pidfile in $file_list_suffix.pid; do PID=`cat $pidfile 2>/dev/null` - start-stop-daemon --stop --quiet --oknodo --pidfile "$pidfile" + ${SSD} --stop --quiet --oknodo --pidfile "$pidfile" echo -n "." rm -rf "$pidfile" done @@ -374,7 +381,7 @@ start_prio() # to MI version if started "$daemon_name"; then PIDFILE=`pidfile $daemon_name` - start-stop-daemon \ + ${SSD} \ --stop --quiet --oknodo \ --pidfile "$PIDFILE" \ --exec "$D_PATH/$daemon_name" @@ -395,7 +402,7 @@ start_prio() # single instance to MI version eval "file_list_suffix="$V_PATH"/"$daemon_name-*"" for pidfile in $file_list_suffix.pid; do - start-stop-daemon --stop --quiet --oknodo --pidfile "$pidfile" + ${SSD} --stop --quiet --oknodo --pidfile "$pidfile" echo -n "." rm -rf "$pidfile" done From 9d92810cf1516568b0b5cef6077c9603c7636bfb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 13 Jun 2016 19:10:17 -0400 Subject: [PATCH 21/30] quagga: Modify code to build properly in tools and cumulus The tools and cumulus directories were not properly being included for the 'make dist' step to allow for proper distribution of code. Signed-off-by: Donald Sharp Conflicts: Makefile.am --- Makefile.am | 4 ++-- configure.ac | 2 ++ tools/Makefile.am | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tools/Makefile.am diff --git a/Makefile.am b/Makefile.am index 7e01a22d1a..4f3835b0ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,11 +2,11 @@ SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ - redhat @SOLARIS@ tests + redhat @SOLARIS@ tests tools cumulus DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ - solaris + solaris tools cumulus EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ diff --git a/configure.ac b/configure.ac index 78d3cda268..113c1619f8 100755 --- a/configure.ac +++ b/configure.ac @@ -1750,6 +1750,8 @@ AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile tests/bgpd.tests/Makefile tests/libzebra.tests/Makefile redhat/Makefile + tools/Makefile + cumulus/Makefile pkgsrc/Makefile redhat/quagga.spec lib/version.h diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000000..125bfee2c2 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,4 @@ +sbin_SCRIPTS = quagga-reload.py quagga + +EXTRA_DIST = quagga.service quagga-reload.py quagga + From e77e22d21e8833ec167951e2a5e8f6ca5c9e7346 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 14 Jun 2016 15:06:37 -0400 Subject: [PATCH 22/30] redhat: Fix runtime dependency and quaggavty group 1) Fix runtime to depend on initscripts 2) Fix quagga user to get quaggavty group Signed-off-by: Donald Sharp --- redhat/quagga.spec.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/redhat/quagga.spec.in b/redhat/quagga.spec.in index 253fd7c0a0..cadc1fb8c9 100644 --- a/redhat/quagga.spec.in +++ b/redhat/quagga.spec.in @@ -99,7 +99,7 @@ Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: texi2html texinfo autoconf patch libcap-devel groff BuildRequires: readline readline-devel ncurses ncurses-devel -Requires: ncurses +Requires: ncurses initscripts %if %{with_pam} BuildRequires: pam-devel Requires: pam @@ -284,7 +284,11 @@ if getent passwd %quagga_user >/dev/null ; then : ; else \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi +%if 0%{?vty_group:1} +/usr/sbin/usermod -a -G %vty_group %quagga_user %endif +%endif + %post # zebra_spec_add_service From 03718c3d128a15aa56b1ed55e02ffa2f75d44232 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 15 Jun 2016 12:31:42 -0400 Subject: [PATCH 23/30] debian: Fix rules file Fix the rules file to put back isis and vtysh Signed-off-by: Donald Sharp --- debian/rules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/rules b/debian/rules index e5e3ad8c11..7a48448068 100755 --- a/debian/rules +++ b/debian/rules @@ -39,6 +39,8 @@ override_dh_auto_configure: --sysconfdir=/etc/quagga \ $(USE_SNMP) \ --enable-ospfapi=yes \ + --enable-vtysh=yes \ + --enable-isisd=yes \ --enable-multipath=256 \ --enable-user=quagga \ --enable-group=quagga \ From 530d701611dc489161af6f34547174d147655a5a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 10 Jun 2016 14:53:53 -0400 Subject: [PATCH 24/30] configure.ac: Add back HAVE_SYSTEMD When the change was made to add some additional code to make sure systemd was actually installed on the system, the HAVE_SYSTEMD #define was accidently removed. Signed-off-by: Donald Sharp --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 113c1619f8..8758d9d3c1 100755 --- a/configure.ac +++ b/configure.ac @@ -338,6 +338,8 @@ case "${enable_systemd}" in AC_CHECK_LIB(systemd, sd_notify, LIBS="$LIBS -lsystemd") if test $ac_cv_lib_systemd_sd_notify = no; then AC_MSG_ERROR([enable systemd has been specified but systemd development env not found on your system]) + else + AC_DEFINE(HAVE_SYSTEMD,,Compile systemd support in) fi ;; "*") ;; From 6776485deef32900c119a61d43faecb515d3b20b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 20 Jun 2016 08:21:00 -0400 Subject: [PATCH 25/30] quagga: Allow compile time determination of v6 RR semantics The patches to allow kernel v6 Route Replacement semantics to work correctly are on a very recent kernel. If you are compiling on a linux kernel where it's broken, just compile with --disable-rr-semantics. Signed-off-by: Donald Sharp (cherry picked from commit 76981cd383e4bed69454bcc4151a0aae89e8ca84) --- configure.ac | 6 ++++++ zebra/rt_netlink.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/configure.ac b/configure.ac index 8758d9d3c1..8338ad1462 100755 --- a/configure.ac +++ b/configure.ac @@ -304,6 +304,8 @@ AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) AC_ARG_ENABLE(cumulus, [ --enable-cumulus enable Cumulus Switch Special Extensions]) +AC_ARG_ENABLE(rr-semantics, + AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" @@ -345,6 +347,10 @@ case "${enable_systemd}" in "*") ;; esac +if test "${enable_rr_semantics}" != "no" ; then + AC_DEFINE(HAVE_V6_RR_SEMANTICS,, Compile in v6 Route Replacement Semantics) +fi + if test "${enable_poll}" = "yes" ; then AC_DEFINE(HAVE_POLL,,Compile systemd support in) fi diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e52fcd4342..1f7b1a9cff 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2390,7 +2390,12 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib) int kernel_update_ipv6 (struct prefix *p, struct rib *rib) { +#if defined (HAVE_V6_RR_SEMANTICS) return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6, 1); +#else + kernel_delete_ipv6 (p, rib); + return kernel_add_ipv6 (p, rib); +#endif } int From 2376c3f225ee601e2e025e1813006ab79c3fd0a6 Mon Sep 17 00:00:00 2001 From: radhika Date: Tue, 21 Jun 2016 03:39:58 -0700 Subject: [PATCH 26/30] bfd: Fix for missing BFD client regs/deregs from quagga clients Ticket: CM-11256 Signed-off-by: Radhika Mahankali Reviewed-by: Donald Sharp Reviewed-by: Kanna Rajagopal Testing: Unit, PTM smoke, OSPF smoke, BGP Smoke Issue: BFD client registrations are not being sent to PTM from BGP/OSPF clients when the quagga clients have no BFD configuration. This can create stale BFD sessions in PTM when BFD is removed from quagga configuration before quagga is restarted. BFD client de-registrations from BGP/OSPF also go missing sometimes when quagga is restarted. This also will cause stale BFD sessions in PTM. Root Cause: BFD client registrations were being sent at the time of BGP/OSPF daemon initialization. But, they were being sent to zebra before the socket connection between zebra and BGP/OSPF was established. This causes the missing BFD client registrations. BFD client de-registrations are sent from zebra when zebra detects socket close for BGP/OSPF daemons. Based on the timing, the de-registrations may happen after socket between PTM and zebra is closed. This will result in missing de-registrations. Fix: Moved sending of BFD client registration messages to zebra connected callback to make sure that they are sent after the BGP/OSPF daemons connect with zebra. Added BFD client de-registrations for BGP/OSPF to be also sent when zebra daemon gets restart signal. They are sent from the signal handler only if it was not already handled in zebra client socket close callback. --- bgpd/bgp_bfd.c | 3 --- bgpd/bgp_zebra.c | 5 ++++- ospf6d/ospf6_bfd.c | 3 --- ospf6d/ospf6_zebra.c | 4 ++++ ospfd/ospf_bfd.c | 3 --- ospfd/ospf_zebra.c | 4 ++++ zebra/zebra_ptm.c | 32 ++++++++++++++++++++++---------- zebra/zebra_ptm.h | 5 ++++- zebra/zserv.c | 2 +- 9 files changed, 39 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index b64fbee04d..b8b0053695 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -711,7 +711,4 @@ bgp_bfd_init(void) install_element (BGP_NODE, &no_neighbor_bfd_cmd); install_element (BGP_NODE, &no_neighbor_bfd_val_cmd); install_element (BGP_NODE, &no_neighbor_bfd_type_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 457f865bea..102e38e4be 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "queue.h" #include "memory.h" #include "lib/json.h" +#include "lib/bfd.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -43,7 +44,6 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" -#include "bgpd/bgp_bfd.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -2053,6 +2053,9 @@ bgp_zebra_connected (struct zclient *zclient) bgp_zebra_instance_register (bgp); + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + /* TODO - What if we have peers and networks configured, do we have to * kick-start them? */ diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index 503c7e0cd7..f9bb6f0031 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -420,7 +420,4 @@ ospf6_bfd_init(void) install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 9c738233b4..3137a33c50 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -28,6 +28,7 @@ #include "stream.h" #include "zclient.h" #include "memory.h" +#include "lib/bfd.h" #include "ospf6_proto.h" #include "ospf6_top.h" @@ -654,6 +655,9 @@ DEFUN (no_redistribute_ospf6, static void ospf6_zebra_connected (struct zclient *zclient) { + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + zclient_send_reg_requests (zclient, VRF_DEFAULT); } diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index ec486c4688..c87bcb0afb 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -452,7 +452,4 @@ ospf_bfd_init(void) install_element (INTERFACE_NODE, &ip_ospf_bfd_param_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_bfd_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_bfd_param_cmd); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index ffdfd750d2..16cd2d2479 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -34,6 +34,7 @@ #include "filter.h" #include "plist.h" #include "log.h" +#include "lib/bfd.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -1557,6 +1558,9 @@ ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) static void ospf_zebra_connected (struct zclient *zclient) { + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + zclient_send_reg_requests (zclient, VRF_DEFAULT); } diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index bf6afb0216..931fc73e43 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -131,11 +131,13 @@ zebra_ptm_init (void) void zebra_ptm_finish(void) { - if (ptm_cb.ptm_sock != -1) - close(ptm_cb.ptm_sock); + int proto; - if (ptm_cb.wb) - buffer_free(ptm_cb.wb); + for (proto = 0; proto < ZEBRA_ROUTE_MAX; proto++) + if (CHECK_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG)) + zebra_ptm_bfd_client_deregister(proto); + + buffer_flush_all(ptm_cb.wb, ptm_cb.ptm_sock); if (ptm_cb.out_data) free(ptm_cb.out_data); @@ -150,6 +152,12 @@ zebra_ptm_finish(void) thread_cancel (ptm_cb.t_write); if (ptm_cb.t_timer) thread_cancel (ptm_cb.t_timer); + + if (ptm_cb.wb) + buffer_free(ptm_cb.wb); + + if (ptm_cb.ptm_sock != -1) + close(ptm_cb.ptm_sock); } static int @@ -999,24 +1007,26 @@ zebra_ptm_bfd_client_register (struct zserv *client, int sock, u_short length) zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, ptm_cb.out_data); zebra_ptm_send_message(ptm_cb.out_data, data_len); + + SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); return 0; } /* BFD client deregister */ void -zebra_ptm_bfd_client_deregister (struct zserv *client) +zebra_ptm_bfd_client_deregister (int proto) { void *out_ctxt; char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; - if (client->proto != ZEBRA_ROUTE_OSPF && client->proto != ZEBRA_ROUTE_BGP - && client->proto != ZEBRA_ROUTE_OSPF6) + if (proto != ZEBRA_ROUTE_OSPF && proto != ZEBRA_ROUTE_BGP + && proto != ZEBRA_ROUTE_OSPF6) return; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bfd_client_deregister msg for client %s", - zebra_route_string(client->proto)); + zlog_err("bfd_client_deregister msg for client %s", + zebra_route_string(proto)); if (ptm_cb.ptm_sock == -1) { @@ -1030,7 +1040,7 @@ zebra_ptm_bfd_client_deregister (struct zserv *client) sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD); ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); - sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); + sprintf(tmp_buf, "%s", zebra_route_string(proto)); ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, tmp_buf); @@ -1039,7 +1049,9 @@ zebra_ptm_bfd_client_deregister (struct zserv *client) if (IS_ZEBRA_DEBUG_SEND) zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, ptm_cb.out_data); + zebra_ptm_send_message(ptm_cb.out_data, data_len); + UNSET_FLAG(ptm_cb.client_flags[proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); } int diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 27c0e42f99..71c85d9094 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -27,6 +27,8 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #define ZEBRA_PTM_MAX_SOCKBUF 3200 /* 25B *128 ports */ #define ZEBRA_PTM_SEND_MAX_SOCKBUF 512 +#define ZEBRA_PTM_BFD_CLIENT_FLAG_REG (1 << 1) /* client registered with BFD */ + /* Zebra ptm context block */ struct zebra_ptm_cb { @@ -44,6 +46,7 @@ struct zebra_ptm_cb int ptm_enable; int pid; + u_int8_t client_flags[ZEBRA_ROUTE_MAX]; }; #define ZEBRA_PTM_STATUS_DOWN 0 @@ -72,5 +75,5 @@ int zebra_ptm_bfd_client_register (struct zserv *client, int sock, void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); void zebra_ptm_if_write (struct vty *vty, struct zebra_if *zebra_ifp); -void zebra_ptm_bfd_client_deregister (struct zserv *client); +void zebra_ptm_bfd_client_deregister (int proto); #endif diff --git a/zebra/zserv.c b/zebra/zserv.c index d6de0792e1..1529bc286c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1752,7 +1752,7 @@ static void zebra_client_close (struct zserv *client) { /* Send client de-registration to BFD */ - zebra_ptm_bfd_client_deregister(client); + zebra_ptm_bfd_client_deregister(client->proto); /* Cleanup any registered nexthops - across all VRFs. */ zebra_client_close_cleanup_rnh (client); From 39dcf9acd87b18ab00f9f71ec15fdd89fff4b3c8 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 21 Jun 2016 14:24:29 +0000 Subject: [PATCH 27/30] Fix build warnings in start-stop-daemon.c Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-11484 --- cumulus/start-stop-daemon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cumulus/start-stop-daemon.c b/cumulus/start-stop-daemon.c index e317bb801c..ea63fbc217 100644 --- a/cumulus/start-stop-daemon.c +++ b/cumulus/start-stop-daemon.c @@ -107,7 +107,7 @@ LIST_HEAD(namespace_head, namespace); struct namespace { LIST_ENTRY(namespace) list; - char *path; + const char *path; int nstype; }; @@ -222,12 +222,12 @@ clear(struct pid_list **list) *list = NULL; } -static char * +static const char * next_dirname(const char *s) { - char *cur; + const char *cur; - cur = (char *)s; + cur = (const char *)s; if (*cur != '\0') { for (; *cur != '/'; ++cur) @@ -248,7 +248,7 @@ add_namespace(const char *path) const char *nsdirname, *nsname, *cur; struct namespace *namespace; - cur = (char *)path; + cur = (const char *)path; nsdirname = nsname = ""; while ((cur = next_dirname(cur))[0] != '\0') { @@ -266,7 +266,7 @@ add_namespace(const char *path) badusage("invalid namepspace path"); namespace = xmalloc(sizeof(*namespace)); - namespace->path = (char *)path; + namespace->path = (const char *)path; namespace->nstype = nstype; LIST_INSERT_HEAD(&namespace_head, namespace, list); } From ab5f8310801f1870a7c5c22e1595e4452c558ddb Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 21 Jun 2016 14:52:43 +0000 Subject: [PATCH 28/30] quagga-reload.py thinks the BGP ASN changed when it did not Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-11463 --- tools/quagga-reload.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index 27fc3830c6..9c0cbb48d6 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -567,7 +567,11 @@ def compare_context_objects(newconf, running): if running_ctx_keys not in newconf.contexts: # Check if bgp's local ASN has changed. If yes, just restart it - if "router bgp" in running_ctx_keys[0]: + # We check that the len is 1 here so that we only look at ('router bgp 10') + # and not ('router bgp 10', 'address-family ipv4 unicast'). The + # latter could cause a false restart_bgpd positive if ipv4 unicast is in + # running but not in newconf. + if "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) == 1: restart_bgpd = True continue From 655f79c9d2352c4c57b883aad0da6cd4528f4dde Mon Sep 17 00:00:00 2001 From: Dinesh G Dutt Date: Wed, 6 Jul 2016 06:50:23 -0700 Subject: [PATCH 29/30] Don't print 'neighbor activate' if its default for IPv4 unicast AFI/SAFI Ticket: CM-11460 Reviewed By: CCR-4927 Testing Done: Quagga's default "show running" model is to only print the non-default config. Historically, IPv4 unicast has always had a default 'activate' model unless its been configured otherwise. In 3.0, we introduced a print of the 'activate' statement for IPv4 unicast independent of whether it was the default or not. This causes quagga reload to break as the user doesn't configure 'activate' for IPv4 unicast, and so any config changes will also not have it. However 'show running' will display it, causing quagga reload to think that the AFI/SAFI has been deactivated and bounce the sessions incorrectly. This patch reverts to the original quagga behavior/model of not printing the 'activate' line for IPv4 unicast if its the default. --- bgpd/bgpd.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f23cc13725..ca72d2403a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6621,9 +6621,17 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp, { if (peer->afc[afi][safi]) { - afi_header_vty_out (vty, afi, safi, write, - " neighbor %s activate%s", - addr, VTY_NEWLINE); + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) + { + if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) + { + vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); + } + } + else + afi_header_vty_out (vty, afi, safi, write, + " neighbor %s activate%s", + addr, VTY_NEWLINE); } } From cc146ecc00f96137027cc909a78e83f8ec02c08c Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Tue, 12 Jul 2016 20:10:05 +0000 Subject: [PATCH 30/30] quagga-reload.py needs a --stdout option Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-11791 --- tools/quagga-reload.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index 9c0cbb48d6..9650822d1e 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -624,13 +624,14 @@ if __name__ == '__main__': group.add_argument('--reload', action='store_true', help='Apply the deltas', default=False) group.add_argument('--test', action='store_true', help='Show the deltas', default=False) parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False) + parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False) parser.add_argument('filename', help='Location of new quagga config file') args = parser.parse_args() # Logging # For --test log to stdout # For --reload log to /var/log/quagga/quagga-reload.log - if args.test: + if args.test or args.stdout: logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)5s: %(message)s') elif args.reload: