Merge 'patch-tracking/4/proposed/netdef-solaris' into accepted
diff --git a/.gitignore b/.gitignore
index 48e6b38..e8de252 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,4 +37,4 @@
*.loT
m4/*.m4
!m4/ax_sys_weak_alias.m4
-
+cscope.*
diff --git a/HACKING.md b/HACKING.md
new file mode 100644
index 0000000..3a449da
--- /dev/null
+++ b/HACKING.md
@@ -0,0 +1,500 @@
+---
+title: Conventions for working on Quagga
+papersize: a4paper
+geometry: scale=0.82
+fontsize: 11pt
+toc: true
+date: \today
+include-before:
+ \large This is a living document. Suggestions for updates, via the
+ [quagga-dev list](http://lists.quagga.net/mailman/listinfo/quagga-dev),
+ are welcome. \newpage
+...
+
+\newpage
+
+GUIDELINES FOR HACKING ON QUAGGA {#sec:guidelines}
+================================
+
+GNU coding standards apply. Indentation follows the result of
+invoking GNU indent (as of 2.2.8a) with the -–nut argument.
+
+Originally, tabs were used instead of spaces, with tabs are every 8 columns.
+However, tab’s interoperability issues mean space characters are now preferred for
+new changes. We generally only clean up whitespace when code is unmaintainable
+due to whitespace issues, to minimise merging conflicts.
+
+Be particularly careful not to break platforms/protocols that you
+cannot test.
+
+New code should have good comments, which explain why the code is correct.
+Changes to existing code should in many cases upgrade the comments when
+necessary for a reviewer to conclude that the change has no unintended
+consequences.
+
+Each file in the Git repository should have a git format-placeholder (like
+an RCS Id keyword), somewhere very near the top, commented out appropriately
+for the file type. The placeholder used for Quagga (replacing \<dollar\>
+with \$) is:
+
+`$QuaggaId: <dollar>Format:%an, %ai, %h<dollar> $`
+
+See line 2 of HACKING.tex, the source for this document, for an example.
+
+This placeholder string will be expanded out by the ‘git archive’ commands,
+which is used to generate the tar archives for snapshots and releases.
+
+Please document fully the proper use of a new function in the header file
+in which it is declared. And please consult existing headers for
+documentation on how to use existing functions. In particular, please consult
+these header files:
+
+<span>lib/log.h</span> logging levels and usage guidance
+
+<span>[more to be added]</span>
+
+If changing an exported interface, please try to deprecate the interface in
+an orderly manner. If at all possible, try to retain the old deprecated
+interface as is, or functionally equivalent. Make a note of when the
+interface was deprecated and guard the deprecated interface definitions in
+the header file, i.e.:
+
+ /* Deprecated: 20050406 */
+ #if !defined(QUAGGA_NO_DEPRECATED_INTERFACES)
+ #warning "Using deprecated <libname> (interface(s)|function(s))"
+ ...
+ #endif /* QUAGGA_NO_DEPRECATED_INTERFACES */
+
+This is to ensure that the core Quagga sources do not use the deprecated
+interfaces (you should update Quagga sources to use new interfaces, if
+applicable), while allowing external sources to continue to build.
+Deprecated interfaces should be excised in the next unstable cycle.
+
+Note: If you wish, you can test for GCC and use a function
+marked with the ’deprecated’ attribute. However, you must provide the
+warning for other compilers.
+
+If changing or removing a command definition, *ensure* that you
+properly deprecate it - use the \_DEPRECATED form of the appropriate DEFUN
+macro. This is *critical*. Even if the command can no longer
+function, you *MUST* still implement it as a do-nothing stub.
+
+Failure to follow this causes grief for systems administrators, as an
+upgrade may cause daemons to fail to start because of unrecognised commands.
+Deprecated commands should be excised in the next unstable cycle. A list of
+deprecated commands should be collated for each release.
+
+See also section [sec:dll-versioning] below regarding SHARED LIBRARY
+VERSIONING.
+
+YOUR FIRST CONTRIBUTIONS
+========================
+
+Routing protocols can be very complex sometimes. Then, working with an
+Opensource community can be complex too, but usually friendly with
+anyone who is ready to be willing to do it properly.
+
+- First, start doing simple tasks. Quagga’s patchwork is a good place
+ to start with. Pickup some patches, apply them on your git trie,
+ review them and send your ack’t or review comments. Then, a
+ maintainer will apply the patch if ack’t or the author will have to
+ provide a new update. It help a lot to drain the patchwork queues.
+ See <http://patchwork.quagga.net/project/quagga/list/>
+
+- The more you’ll review patches from patchwork, the more the Quagga’s
+ maintainers will be willing to consider some patches you will be
+ sending.
+
+- start using git clone, pwclient
+ <http://patchwork.quagga.net/help/pwclient/>
+
+ $ pwclient list -s new
+ ID State Name
+ -- ----- ----
+ 179 New [quagga-dev,6648] Re: quagga on FreeBSD 4.11 (gcc-2.95)
+ 181 New [quagga-dev,6660] proxy-arp patch
+ [...]
+
+ $ pwclient git-am 1046
+
+HANDY GUIDELINES FOR MAINTAINERS
+================================
+
+Get your cloned trie:
+
+ git clone vjardin@git.sv.gnu.org:/srv/git/quagga.git
+
+Apply some ack’t patches:
+
+ pwclient git-am 1046
+ Applying patch #1046 using 'git am'
+ Description: [quagga-dev,11595] zebra: route_unlock_node is missing in "show ip[v6] route <prefix>" commands
+ Applying: zebra: route_unlock_node is missing in "show ip[v6] route <prefix>" commands
+
+Run a quick review. If the ack’t was not done properly, you know who you have
+to blame.
+
+Push the patches:
+
+ git push
+
+Set the patch to accepted on patchwork
+
+ pwclient update -s Accepted 1046
+
+COMPILE-TIME CONDITIONAL CODE
+=============================
+
+Please think very carefully before making code conditional at compile time,
+as it increases maintenance burdens and user confusion. In particular,
+please avoid gratuitous -–enable-… switches to the configure script -
+typically code should be good enough to be in Quagga, or it shouldn’t be
+there at all.
+
+When code must be compile-time conditional, try have the compiler make it
+conditional rather than the C pre-processor - so that it will still be
+checked by the compiler, even if disabled. I.e. this:
+
+ if (SOME_SYMBOL)
+ frobnicate();
+
+rather than:
+
+ #ifdef SOME_SYMBOL
+ frobnicate ();
+ #endif /* SOME_SYMBOL */
+
+Note that the former approach requires ensuring that SOME\_SYMBOL will
+be defined (watch your AC\_DEFINEs).
+
+COMMIT MESSAGES
+===============
+
+The commit message requirements are:
+
+- The message *MUST* provide a suitable one-line summary followed by a
+ blank line as the very first line of the message, in the form:
+
+ `topic: high-level, one line summary`
+
+ Where topic would tend to be name of a subdirectory, and/or daemon, unless
+ there’s a more suitable topic (e.g. ’build’). This topic is used to
+ organise change summaries in release announcements.
+
+- It should have a suitable “body”, which tries to address the
+ following areas, so as to help reviewers and future browsers of the
+ code-base understand why the change is correct (note also the code
+ comment requirements):
+
+ - The motivation for the change (does it fix a bug, if so which?
+ add a feature?)
+
+ - The general approach taken, and trade-offs versus any other
+ approaches.
+
+ - Any testing undertaken or other information affecting the confidence
+ that can be had in the change.
+
+ - Information to allow reviewers to be able to tell which specific
+ changes to the code are intended (and hence be able to spot any accidental
+ unintended changes).
+
+The one-line summary must be limited to 54 characters, and all other
+lines to 72 characters.
+
+Commit message bodies in the Quagga project have typically taken the
+following form:
+
+- An optional introduction, describing the change generally.
+
+- A short description of each specific change made, preferably:
+
+ - file by file
+
+ - function by function (use of “ditto”, or globs is allowed)
+
+Contributors are strongly encouraged to follow this form.
+
+This itemised commit messages allows reviewers to have confidence that the
+author has self-reviewed every line of the patch, as well as providing
+reviewers a clear index of which changes are intended, and descriptions for
+them (C-to-english descriptions are not desirable - some discretion is
+useful). For short patches, a per-function/file break-down may be
+redundant. For longer patches, such a break-down may be essential. A
+contrived example (where the general discussion is obviously somewhat
+redundant, given the one-line summary):
+
+> zebra: Enhance frob FSM to detect loss of frob
+>
+> Add a new DOWN state to the frob state machine to allow the barinator to
+> detect loss of frob.
+>
+> * frob.h: (struct frob) Add DOWN state flag.
+> * frob.c: (frob_change) set/clear DOWN appropriately on state change.
+> * bar.c: (barinate) Check frob for DOWN state.
+
+Please have a look at the git commit logs to get a feel for what the norms
+are.
+
+Note that the commit message format follows git norms, so that “git log
+–oneline” will have useful output.
+
+HACKING THE BUILD SYSTEM
+========================
+
+If you change or add to the build system (configure.ac, any Makefile.am,
+etc.), try to check that the following things still work:
+
+- make dist
+
+- resulting dist tarball builds
+
+- out-of-tree builds
+
+The quagga.net site relies on make dist to work to generate snapshots. It
+must work. Common problems are to forget to have some additional file
+included in the dist, or to have a make rule refer to a source file without
+using the srcdir variable.
+
+RELEASE PROCEDURE
+=================
+
+- Tag the appropriate commit with a release tag (follow existing
+ conventions).
+
+ [This enables recreating the release, and is just good CM practice.]
+
+- Create a fresh tar archive of the quagga.net repository, and do a
+ test build:
+
+ vim configure.ac
+ git commit -m "release: 0.99.99.99"
+ git tag -u 54CD2E60 quagga-0.99.99.99
+ git push savannah tag quagga-0.99.99.99
+
+ git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp
+ git log quagga-0.99.99.98..quagga-0.99.99.99 > \
+ /tmp/quagga-release/quagga-0.99.99.99.changelog.txt
+ cd /tmp/quagga-release
+
+ autoreconf -i
+ ./configure
+ make
+ make dist-gzip
+
+ gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar
+ xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz
+ gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar
+
+ scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga
+
+
+ Do NOT do this in a subdirectory of the Quagga sources, autoconf
+ will think it’s a sub-package and fail to include neccessary files.
+
+- Add the version number on https://bugzilla.quagga.net/, under
+ Administration, Products, “Quagga”, Edit versions, Add a version.
+
+- Edit the wiki on
+ https://wiki.quagga.net/wiki/index.php/Release\_status
+
+- Post a news entry on Savannah
+
+- Send a mail to quagga-dev and quagga-users
+
+The tarball which ‘make dist’ creates is the tarball to be released! The
+git-archive step ensures you’re working with code corresponding to that in
+the official repository, and also carries out keyword expansion. If any
+errors occur, move tags as needed and start over from the fresh checkouts.
+Do not append to tarballs, as this has produced non-standards-conforming
+tarballs in the past.
+
+See also: <http://wiki.quagga.net/index.php/Main/Processes>
+
+[TODO: collation of a list of deprecated commands. Possibly can be
+scripted to extract from vtysh/vtysh\_cmd.c]
+
+TOOL VERSIONS
+=============
+
+Require versions of support tools are listed in INSTALL.quagga.txt.
+Required versions should only be done with due deliberation, as it can
+cause environments to no longer be able to compile quagga.
+
+SHARED LIBRARY VERSIONING {#sec:dll-versioning}
+=========================
+
+[this section is at the moment just gdt’s opinion]
+
+Quagga builds several shared libaries (lib/libzebra, ospfd/libospf,
+ospfclient/libsopfapiclient). These may be used by external programs,
+e.g. a new routing protocol that works with the zebra daemon, or
+ospfapi clients. The libtool info pages (node Versioning) explain
+when major and minor version numbers should be changed. These values
+are set in Makefile.am near the definition of the library. If you
+make a change that requires changing the shared library version,
+please update Makefile.am.
+
+libospf exports far more than it should, and is needed by ospfapi
+clients. Only bump libospf for changes to functions for which it is
+reasonable for a user of ospfapi to call, and please err on the side
+of not bumping.
+
+There is no support intended for installing part of zebra. The core
+library libzebra and the included daemons should always be built and
+installed together.
+
+GIT COMMIT SUBMISSION {#sec:git-submission}
+=====================
+
+The preferred method for submitting changes is to provide git commits via a
+publicly-accessible git repository, which the maintainers can easily pull.
+
+The commits should be in a branch based off the Quagga.net master - a
+“feature branch”. Ideally there should be no commits to this branch other
+than those in master, and those intended to be submitted. However, merge
+commits to this branch from the Quagga master are permitted, though strongly
+discouraged - use another (potentially local and throw-away) branch to test
+merge with the latest Quagga master.
+
+Recommended practice is to keep different logical sets of changes on
+separate branches - “topic” or “feature” branches. This allows you to still
+merge them together to one branch (potentially local and/or “throw-away”)
+for testing or use, while retaining smaller, independent branches that are
+easier to merge.
+
+All content guidelines in section [sec:patch-submission], PATCH
+SUBMISSION apply.
+
+PATCH SUBMISSION {#sec:patch-submission}
+================
+
+- For complex changes, contributors are strongly encouraged to first
+ start a design discussion on the quagga-dev list *before* starting
+ any coding.
+
+- Send a clean diff against the ’master’ branch of the quagga.git
+ repository, in unified diff format, preferably with the ’-p’
+ argument to show C function affected by any chunk, and with the -w
+ and -b arguments to minimise changes. E.g:
+
+ git diff -up mybranch..remotes/quagga.net/master
+
+ It is preferable to use git format-patch, and even more preferred to
+ publish a git repository (see GIT COMMIT SUBMISSION, section
+ [sec:git-submission]).
+
+ If not using git format-patch, Include the commit message in the
+ email.
+
+- After a commit, code should have comments explaining to the reviewer
+ why it is correct, without reference to history. The commit message
+ should explain why the change is correct.
+
+- Include NEWS entries as appropriate.
+
+- Include only one semantic change or group of changes per patch.
+
+- Do not make gratuitous changes to whitespace. See the w and b
+ arguments to diff.
+
+- Changes should be arranged so that the least controversial and most
+ trivial are first, and the most complex or more controversial are
+ last. This will maximise how many the Quagga maintainers can merge,
+ even if some other commits need further work.
+
+- Providing a unit-test is strongly encouraged. Doing so will make it
+ much easier for maintainers to have confidence that they will be
+ able to support your change.
+
+- New code should be arranged so that it easy to verify and test. E.g.
+ stateful logic should be separated out from functional logic as much
+ as possible: wherever possible, move complex logic out to smaller
+ helper functions which access no state other than their arguments.
+
+- State on which platforms and with what daemons the patch has been
+ tested. Understand that if the set of testing locations is small,
+ and the patch might have unforeseen or hard to fix consequences that
+ there may be a call for testers on quagga-dev, and that the patch
+ may be blocked until test results appear.
+
+ If there are no users for a platform on quagga-dev who are able and
+ willing to verify -current occasionally, that platform may be
+ dropped from the “should be checked” list.
+
+PATCH APPLICATION
+=================
+
+- Only apply patches that meet the submission guidelines.
+
+- If the patch might break something, issue a call for testing on the
+ mailing-list.
+
+- Give an appropriate commit message (see above), and use the –author
+ argument to git-commit, if required, to ensure proper attribution
+ (you should still be listed as committer)
+
+- Immediately after commiting, double-check (with git-log and/or
+ gitk). If there’s a small mistake you can easily fix it with ‘git
+ commit –amend ..’
+
+- When merging a branch, always use an explicit merge commit. Giving
+ –no-ff ensures a merge commit is created which documents “this human
+ decided to merge this branch at this time”.
+
+STABLE PLATFORMS AND DAEMONS
+============================
+
+The list of platforms that should be tested follow. This is a list
+derived from what quagga is thought to run on and for which
+maintainers can test or there are people on quagga-dev who are able
+and willing to verify that -current does or does not work correctly.
+
+- BSD (Free, Net or Open, any platform)
+
+- GNU/Linux (any distribution, i386)
+
+- Solaris (strict alignment, any platform)
+
+- future: NetBSD/sparc64
+
+The list of daemons that are thought to be stable and that should be
+tested are:
+
+- zebra
+
+- bgpd
+
+- ripd
+
+- ospfd
+
+- ripngd
+
+Daemons which are in a testing phase are
+
+- ospf6d
+
+- isisd
+
+- watchquagga
+
+IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS
+==================================================
+
+The source code of Quagga is based on two vendors:
+
+`zebra_org` (<http://www.zebra.org/>) `isisd_sf`
+(<http://isisd.sf.net/>)
+
+To import code from further sources, e.g. for archival purposes without
+necessarily having to review and/or fix some changeset, create a branch
+from ‘master’:
+
+ git checkout -b archive/foo master
+ <apply changes>
+ git commit -a "Joe Bar <joe@example.com>"
+ git push quagga archive/foo
+
+presuming ‘quagga’ corresponds to a file in your .git/remotes with
+configuration for the appropriate Quagga.net repository.
diff --git a/HACKING.tex b/HACKING.tex
deleted file mode 100644
index be86ae1..0000000
--- a/HACKING.tex
+++ /dev/null
@@ -1,533 +0,0 @@
-%% -*- mode: text; -*-
-%% $QuaggaId: Format:%an, %ai, %h$ $
-
-\documentclass[oneside]{article}
-\usepackage{parskip}
-\usepackage[bookmarks,colorlinks=true]{hyperref}
-
-\title{Conventions for working on Quagga}
-
-\begin{document}
-\maketitle
-
-This is a living document. Suggestions for updates, via the
-\href{http://lists.quagga.net/mailman/listinfo/quagga-dev}{quagga-dev list},
-are welcome.
-
-\tableofcontents
-
-\section{GUIDELINES FOR HACKING ON QUAGGA}
-\label{sec:guidelines}
-
-
-GNU coding standards apply. Indentation follows the result of
-invoking GNU indent (as of 2.2.8a) with the --nut argument.
-
-Originally, tabs were used instead of spaces, with tabs are every 8 columns.
-However, tab's interoperability issues mean space characters are now preferred for
-new changes. We generally only clean up whitespace when code is unmaintainable
-due to whitespace issues, to minimise merging conflicts.
-
-Be particularly careful not to break platforms/protocols that you
-cannot test.
-
-New code should have good comments, which explain why the code is correct.
-Changes to existing code should in many cases upgrade the comments when
-necessary for a reviewer to conclude that the change has no unintended
-consequences.
-
-Each file in the Git repository should have a git format-placeholder (like
-an RCS Id keyword), somewhere very near the top, commented out appropriately
-for the file type. The placeholder used for Quagga (replacing <dollar> with
-\$) is:
-
- \verb|$QuaggaId: <dollar>Format:%an, %ai, %h<dollar> $|
-
-See line 2 of HACKING.tex, the source for this document, for an example.
-
-This placeholder string will be expanded out by the `git archive' commands,
-which is used to generate the tar archives for snapshots and releases.
-
-Please document fully the proper use of a new function in the header file
-in which it is declared. And please consult existing headers for
-documentation on how to use existing functions. In particular, please consult
-these header files:
-
-\begin{description}
- \item{lib/log.h} logging levels and usage guidance
- \item{[more to be added]}
-\end{description}
-
-If changing an exported interface, please try to deprecate the interface in
-an orderly manner. If at all possible, try to retain the old deprecated
-interface as is, or functionally equivalent. Make a note of when the
-interface was deprecated and guard the deprecated interface definitions in
-the header file, i.e.:
-
-\begin{verbatim}
-/* Deprecated: 20050406 */
-#if !defined(QUAGGA_NO_DEPRECATED_INTERFACES)
-#warning "Using deprecated <libname> (interface(s)|function(s))"
-...
-#endif /* QUAGGA_NO_DEPRECATED_INTERFACES */
-\end{verbatim}
-
-This is to ensure that the core Quagga sources do not use the deprecated
-interfaces (you should update Quagga sources to use new interfaces, if
-applicable), while allowing external sources to continue to build.
-Deprecated interfaces should be excised in the next unstable cycle.
-
-Note: If you wish, you can test for GCC and use a function
-marked with the 'deprecated' attribute. However, you must provide the
-warning for other compilers.
-
-If changing or removing a command definition, \emph{ensure} that you
-properly deprecate it - use the \_DEPRECATED form of the appropriate DEFUN
-macro. This is \emph{critical}. Even if the command can no longer
-function, you \emph{MUST} still implement it as a do-nothing stub.
-
-Failure to follow this causes grief for systems administrators, as an
-upgrade may cause daemons to fail to start because of unrecognised commands.
-Deprecated commands should be excised in the next unstable cycle. A list of
-deprecated commands should be collated for each release.
-
-See also section~\ref{sec:dll-versioning} below regarding SHARED LIBRARY
-VERSIONING.
-
-\section{YOUR FIRST CONTRIBUTIONS}
-
-Routing protocols can be very complex sometimes. Then, working with an
-Opensource community can be complex too, but usually friendly with
-anyone who is ready to be willing to do it properly.
-
-\begin{itemize}
-
- \item First, start doing simple tasks. Quagga's patchwork is a good place
- to start with. Pickup some patches, apply them on your git trie,
- review them and send your ack't or review comments. Then, a
- maintainer will apply the patch if ack't or the author will
- have to provide a new update. It help a lot to drain the
- patchwork queues.
- See \url{http://patchwork.quagga.net/project/quagga/list/}
-
- \item The more you'll review patches from patchwork, the more the
- Quagga's maintainers will be willing to consider some patches you will
- be sending.
-
- \item start using git clone, pwclient \url{http://patchwork.quagga.net/help/pwclient/}
-
-\begin{verbatim}
-$ pwclient list -s new
-ID State Name
--- ----- ----
-179 New [quagga-dev,6648] Re: quagga on FreeBSD 4.11 (gcc-2.95)
-181 New [quagga-dev,6660] proxy-arp patch
-[...]
-
-$ pwclient git-am 1046
-\end{verbatim}
-
-\end{itemize}
-
-\section{HANDY GUIDELINES FOR MAINTAINERS}
-
-Get your cloned trie:
-\begin{verbatim}
- git clone vjardin@git.sv.gnu.org:/srv/git/quagga.git
-\end{verbatim}
-
-Apply some ack't patches:
-\begin{verbatim}
- pwclient git-am 1046
- Applying patch #1046 using 'git am'
- Description: [quagga-dev,11595] zebra: route_unlock_node is missing in "show ip[v6] route <prefix>" commands
- Applying: zebra: route_unlock_node is missing in "show ip[v6] route <prefix>" commands
-\end{verbatim}
-
-Run a quick review. If the ack't was not done properly, you know who you have
-to blame.
-
-Push the patches:
-\begin{verbatim}
- git push
-\end{verbatim}
-
-Set the patch to accepted on patchwork
-\begin{verbatim}
- pwclient update -s Accepted 1046
-\end{verbatim}
-
-\section{COMPILE-TIME CONDITIONAL CODE}
-
-Please think very carefully before making code conditional at compile time,
-as it increases maintenance burdens and user confusion. In particular,
-please avoid gratuitous --enable-\ldots switches to the configure script -
-typically code should be good enough to be in Quagga, or it shouldn't be
-there at all.
-
-When code must be compile-time conditional, try have the compiler make it
-conditional rather than the C pre-processor - so that it will still be
-checked by the compiler, even if disabled. I.e. this:
-
-\begin{verbatim}
- if (SOME_SYMBOL)
- frobnicate();
-\end{verbatim}
-
-rather than:
-
-\begin{verbatim}
- #ifdef SOME_SYMBOL
- frobnicate ();
- #endif /* SOME_SYMBOL */
-\end{verbatim}
-
-Note that the former approach requires ensuring that SOME\_SYMBOL will be
-defined (watch your AC\_DEFINEs).
-
-
-\section{COMMIT MESSAGES}
-
-The commit message requirements are:
-
-\begin{itemize}
-
-\item The message \emph{MUST} provide a suitable one-line summary followed
- by a blank line as the very first line of the message, in the form:
-
- \verb|topic: high-level, one line summary|
-
- Where topic would tend to be name of a subdirectory, and/or daemon, unless
- there's a more suitable topic (e.g. 'build'). This topic is used to
- organise change summaries in release announcements.
-
-\item It should have a suitable "body", which tries to address the
- following areas, so as to help reviewers and future browsers of the
- code-base understand why the change is correct (note also the code
- comment requirements):
-
- \begin{itemize}
-
- \item The motivation for the change (does it fix a bug, if so which?
- add a feature?)
-
- \item The general approach taken, and trade-offs versus any other
- approaches.
-
- \item Any testing undertaken or other information affecting the confidence
- that can be had in the change.
-
- \item Information to allow reviewers to be able to tell which specific
- changes to the code are intended (and hence be able to spot any accidental
- unintended changes).
-
- \end{itemize}
-\end{itemize}
-
-The one-line summary must be limited to 54 characters, and all other
-lines to 72 characters.
-
-Commit message bodies in the Quagga project have typically taken the
-following form:
-
-\begin{itemize}
-\item An optional introduction, describing the change generally.
-\item A short description of each specific change made, preferably:
- \begin{itemize} \item file by file
- \begin{itemize} \item function by function (use of "ditto", or globs is
- allowed)
- \end{itemize}
- \end{itemize}
-\end{itemize}
-
-Contributors are strongly encouraged to follow this form.
-
-This itemised commit messages allows reviewers to have confidence that the
-author has self-reviewed every line of the patch, as well as providing
-reviewers a clear index of which changes are intended, and descriptions for
-them (C-to-english descriptions are not desirable - some discretion is
-useful). For short patches, a per-function/file break-down may be
-redundant. For longer patches, such a break-down may be essential. A
-contrived example (where the general discussion is obviously somewhat
-redundant, given the one-line summary):
-
-\begin{quote}\begin{verbatim}
-zebra: Enhance frob FSM to detect loss of frob
-
-Add a new DOWN state to the frob state machine to allow the barinator to
-detect loss of frob.
-
-* frob.h: (struct frob) Add DOWN state flag.
-* frob.c: (frob_change) set/clear DOWN appropriately on state change.
-* bar.c: (barinate) Check frob for DOWN state.
-\end{verbatim}\end{quote}
-
-Please have a look at the git commit logs to get a feel for what the norms
-are.
-
-Note that the commit message format follows git norms, so that ``git
-log --oneline'' will have useful output.
-
-\section{HACKING THE BUILD SYSTEM}
-
-If you change or add to the build system (configure.ac, any Makefile.am,
-etc.), try to check that the following things still work:
-
-\begin{itemize}
-\item make dist
-\item resulting dist tarball builds
-\item out-of-tree builds
-\end{itemize}
-
-The quagga.net site relies on make dist to work to generate snapshots. It
-must work. Common problems are to forget to have some additional file
-included in the dist, or to have a make rule refer to a source file without
-using the srcdir variable.
-
-
-\section{RELEASE PROCEDURE}
-
-\begin{itemize}
-\item Tag the appropriate commit with a release tag (follow existing
- conventions).
-
- [This enables recreating the release, and is just good CM practice.]
-
-\item Create a fresh tar archive of the quagga.net repository, and do a test
- build:
-
- \begin{verbatim}
- vim configure.ac
- git commit -m "release: 0.99.99.99"
- git tag -u 54CD2E60 quagga-0.99.99.99
- git push savannah tag quagga-0.99.99.99
-
- git archive --prefix=quagga-release/ quagga-0.99.99.99 | tar xC /tmp
- git log quagga-0.99.99.98..quagga-0.99.99.99 > \
- /tmp/quagga-release/quagga-0.99.99.99.changelog.txt
- cd /tmp/quagga-release
-
- autoreconf -i
- ./configure
- make
- make dist-gzip
-
- gunzip < quagga-0.99.99.99.tar.gz > quagga-0.99.99.99.tar
- xz -6e < quagga-0.99.99.99.tar > quagga-0.99.99.99.tar.xz
- gpg -u 54CD2E60 -a --detach-sign quagga-0.99.99.99.tar
-
- scp quagga-0.99.99.99.* username@dl.sv.nongnu.org:/releases/quagga
- \end{verbatim}
-
- Do NOT do this in a subdirectory of the Quagga sources, autoconf will think
- it's a sub-package and fail to include neccessary files.
-
-\item Add the version number on https://bugzilla.quagga.net/, under
- Administration, Products, "Quagga", Edit versions, Add a version.
-\item Edit the wiki on https://wiki.quagga.net/wiki/index.php/Release\_status
-\item Post a news entry on Savannah
-\item Send a mail to quagga-dev and quagga-users
-\end{itemize}
-
-The tarball which `make dist' creates is the tarball to be released! The
-git-archive step ensures you're working with code corresponding to that in
-the official repository, and also carries out keyword expansion. If any
-errors occur, move tags as needed and start over from the fresh checkouts.
-Do not append to tarballs, as this has produced non-standards-conforming
-tarballs in the past.
-
-See also: \url{http://wiki.quagga.net/index.php/Main/Processes}
-
-[TODO: collation of a list of deprecated commands. Possibly can be scripted
-to extract from vtysh/vtysh\_cmd.c]
-
-
-\section{TOOL VERSIONS}
-
-Require versions of support tools are listed in INSTALL.quagga.txt.
-Required versions should only be done with due deliberation, as it can
-cause environments to no longer be able to compile quagga.
-
-
-\section{SHARED LIBRARY VERSIONING}
-\label{sec:dll-versioning}
-
-[this section is at the moment just gdt's opinion]
-
-Quagga builds several shared libaries (lib/libzebra, ospfd/libospf,
-ospfclient/libsopfapiclient). These may be used by external programs,
-e.g. a new routing protocol that works with the zebra daemon, or
-ospfapi clients. The libtool info pages (node Versioning) explain
-when major and minor version numbers should be changed. These values
-are set in Makefile.am near the definition of the library. If you
-make a change that requires changing the shared library version,
-please update Makefile.am.
-
-libospf exports far more than it should, and is needed by ospfapi
-clients. Only bump libospf for changes to functions for which it is
-reasonable for a user of ospfapi to call, and please err on the side
-of not bumping.
-
-There is no support intended for installing part of zebra. The core
-library libzebra and the included daemons should always be built and
-installed together.
-
-
-\section{GIT COMMIT SUBMISSION}
-\label{sec:git-submission}
-
-The preferred method for submitting changes is to provide git commits via a
-publicly-accessible git repository, which the maintainers can easily pull.
-
-The commits should be in a branch based off the Quagga.net master - a
-"feature branch". Ideally there should be no commits to this branch other
-than those in master, and those intended to be submitted. However, merge
-commits to this branch from the Quagga master are permitted, though strongly
-discouraged - use another (potentially local and throw-away) branch to test
-merge with the latest Quagga master.
-
-Recommended practice is to keep different logical sets of changes on
-separate branches - "topic" or "feature" branches. This allows you to still
-merge them together to one branch (potentially local and/or "throw-away")
-for testing or use, while retaining smaller, independent branches that are
-easier to merge.
-
-All content guidelines in section \ref{sec:patch-submission}, PATCH
-SUBMISSION apply.
-
-
-\section{PATCH SUBMISSION}
-\label{sec:patch-submission}
-
-\begin{itemize}
-
-\item For complex changes, contributors are strongly encouraged to first
- start a design discussion on the quagga-dev list \emph{before}
- starting any coding.
-
-\item Send a clean diff against the 'master' branch of the quagga.git
- repository, in unified diff format, preferably with the '-p' argument to
- show C function affected by any chunk, and with the -w and -b arguments to
- minimise changes. E.g:
-
- git diff -up mybranch..remotes/quagga.net/master
-
- It is preferable to use git format-patch, and even more preferred to
- publish a git repository (see GIT COMMIT SUBMISSION, section
- \ref{sec:git-submission}).
-
- If not using git format-patch, Include the commit message in the email.
-
-\item After a commit, code should have comments explaining to the reviewer
- why it is correct, without reference to history. The commit message
- should explain why the change is correct.
-
-\item Include NEWS entries as appropriate.
-
-\item Include only one semantic change or group of changes per patch.
-
-\item Do not make gratuitous changes to whitespace. See the w and b arguments
- to diff.
-
-\item Changes should be arranged so that the least controversial and most
- trivial are first, and the most complex or more controversial are
- last. This will maximise how many the Quagga maintainers can merge,
- even if some other commits need further work.
-
-\item Providing a unit-test is strongly encouraged. Doing so will make it
- much easier for maintainers to have confidence that they will be able
- to support your change.
-
-\item New code should be arranged so that it easy to verify and test. E.g.
- stateful logic should be separated out from functional logic as much as
- possible: wherever possible, move complex logic out to smaller helper
- functions which access no state other than their arguments.
-
-\item State on which platforms and with what daemons the patch has been
- tested. Understand that if the set of testing locations is small,
- and the patch might have unforeseen or hard to fix consequences that
- there may be a call for testers on quagga-dev, and that the patch
- may be blocked until test results appear.
-
- If there are no users for a platform on quagga-dev who are able and
- willing to verify -current occasionally, that platform may be
- dropped from the "should be checked" list.
-
-\end{itemize}
-
-\section{PATCH APPLICATION}
-
-\begin{itemize}
-
-\item Only apply patches that meet the submission guidelines.
-
-\item If the patch might break something, issue a call for testing on the
- mailing-list.
-
-\item Give an appropriate commit message (see above), and use the --author
- argument to git-commit, if required, to ensure proper attribution (you
- should still be listed as committer)
-
-\item Immediately after commiting, double-check (with git-log and/or gitk).
- If there's a small mistake you can easily fix it with `git commit
- --amend ..'
-
-\item When merging a branch, always use an explicit merge commit. Giving
- --no-ff ensures a merge commit is created which documents ``this human
- decided to merge this branch at this time''.
-\end{itemize}
-
-\section{STABLE PLATFORMS AND DAEMONS}
-
-The list of platforms that should be tested follow. This is a list
-derived from what quagga is thought to run on and for which
-maintainers can test or there are people on quagga-dev who are able
-and willing to verify that -current does or does not work correctly.
-
-\begin{itemize}
- \item BSD (Free, Net or Open, any platform)
- \item GNU/Linux (any distribution, i386)
- \item Solaris (strict alignment, any platform)
- \item future: NetBSD/sparc64
-\end{itemize}
-
-The list of daemons that are thought to be stable and that should be
-tested are:
-
-\begin{itemize}
- \item zebra
- \item bgpd
- \item ripd
- \item ospfd
- \item ripngd
-\end{itemize}
-Daemons which are in a testing phase are
-
-\begin{itemize}
- \item ospf6d
- \item isisd
- \item watchquagga
-\end{itemize}
-
-\section{IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS}
-
-The source code of Quagga is based on two vendors:
-
- \verb|zebra_org| (\url{http://www.zebra.org/})
- \verb|isisd_sf| (\url{http://isisd.sf.net/})
-
-To import code from further sources, e.g. for archival purposes without
-necessarily having to review and/or fix some changeset, create a branch from
-`master':
-
-\begin{verbatim}
- git checkout -b archive/foo master
- <apply changes>
- git commit -a "Joe Bar <joe@example.com>"
- git push quagga archive/foo
-\end{verbatim}
-
-presuming `quagga' corresponds to a file in your .git/remotes with
-configuration for the appropriate Quagga.net repository.
-
-\end{document}
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 0aec3ef..9d49f34 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -98,6 +98,12 @@
return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
}
+static void
+assegment_data_free (as_t *asdata)
+{
+ XFREE (MTYPE_AS_SEG_DATA, asdata);
+}
+
/* Get a new segment. Note that 0 is an allowed length,
* and will result in a segment with no allocated data segment.
* the caller should immediately assign data to the segment, as the segment
@@ -126,7 +132,7 @@
return;
if (seg->as)
- XFREE (MTYPE_AS_SEG_DATA, seg->as);
+ assegment_data_free (seg->as);
memset (seg, 0xfe, sizeof(struct assegment));
XFREE (MTYPE_AS_SEG, seg);
@@ -194,13 +200,14 @@
if (num >= AS_SEGMENT_MAX)
return seg; /* we don't do huge prepends */
- newas = assegment_data_new (seg->length + num);
-
+ if ((newas = assegment_data_new (seg->length + num)) == NULL)
+ return seg;
+
for (i = 0; i < num; i++)
newas[i] = asnum;
memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
- XFREE (MTYPE_AS_SEG_DATA, seg->as);
+ assegment_data_free (seg->as);
seg->as = newas;
seg->length += num;
@@ -1879,6 +1886,7 @@
void
aspath_finish (void)
{
+ hash_clean (ashash, (void (*)(void *))aspath_free);
hash_free (ashash);
ashash = NULL;
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 3f09103..ef19bc4 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -203,6 +203,7 @@
static void
cluster_finish (void)
{
+ hash_clean (cluster_hash, (void (*)(void *))cluster_free);
hash_free (cluster_hash);
cluster_hash = NULL;
}
@@ -279,6 +280,7 @@
static void
transit_finish (void)
{
+ hash_clean (transit_hash, (void (*)(void *))transit_free);
hash_free (transit_hash);
transit_hash = NULL;
}
@@ -452,9 +454,20 @@
attrhash = hash_create (attrhash_key_make, attrhash_cmp);
}
+/*
+ * special for hash_clean below
+ */
+static void
+attr_vfree (void *attr)
+{
+ bgp_attr_extra_free ((struct attr *)attr);
+ XFREE (MTYPE_ATTR, attr);
+}
+
static void
attrhash_finish (void)
{
+ hash_clean(attrhash, attr_vfree);
hash_free (attrhash);
attrhash = NULL;
}
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 05c30ff..359fce3 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -115,7 +115,7 @@
damp->t_reuse = NULL;
damp->t_reuse =
- thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
+ thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
t_now = bgp_clock ();
@@ -447,7 +447,7 @@
/* Register reuse timer. */
if (! damp->t_reuse)
damp->t_reuse =
- thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
+ thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
return 0;
}
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
index a3c9526..3d88dee 100644
--- a/bgpd/bgp_dump.c
+++ b/bgpd/bgp_dump.c
@@ -156,13 +156,13 @@
secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
interval = interval - secs_into_day % interval; /* always > 0 */
}
- bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
+ bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
bgp_dump, interval);
}
else
{
/* One-off dump: execute immediately, don't affect any scheduled dumps */
- bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func,
+ bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
bgp_dump, 0);
}
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index a749f8e..752d6e2 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -26,7 +26,7 @@
#define BGP_READ_ON(T,F,V) \
do { \
if (!(T) && (peer->status != Deleted)) \
- THREAD_READ_ON(master,T,F,peer,V); \
+ THREAD_READ_ON(bm->master,T,F,peer,V); \
} while (0)
#define BGP_READ_OFF(T) \
@@ -38,7 +38,7 @@
#define BGP_WRITE_ON(T,F,V) \
do { \
if (!(T) && (peer->status != Deleted)) \
- THREAD_WRITE_ON(master,(T),(F),peer,(V)); \
+ THREAD_WRITE_ON(bm->master,(T),(F),peer,(V)); \
} while (0)
#define BGP_WRITE_OFF(T) \
@@ -50,7 +50,7 @@
#define BGP_TIMER_ON(T,F,V) \
do { \
if (!(T) && (peer->status != Deleted)) \
- THREAD_TIMER_ON(master,(T),(F),peer,(V)); \
+ THREAD_TIMER_ON(bm->master,(T),(F),peer,(V)); \
} while (0)
#define BGP_TIMER_OFF(T) \
@@ -62,13 +62,13 @@
#define BGP_EVENT_ADD(P,E) \
do { \
if ((P)->status != Deleted) \
- thread_add_event (master, bgp_event, (P), (E)); \
+ thread_add_event (bm->master, bgp_event, (P), (E)); \
} while (0)
#define BGP_EVENT_FLUSH(P) \
do { \
assert (peer); \
- thread_cancel_event (master, (P)); \
+ thread_cancel_event (bm->master, (P)); \
} while (0)
/* Prototypes. */
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 7c2988c..591a6f9 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -37,6 +37,7 @@
#include "plist.h"
#include "stream.h"
#include "vrf.h"
+#include "workqueue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -105,9 +106,6 @@
/* Route retain mode flag. */
static int retain_mode = 0;
-/* Master of threads. */
-struct thread_master *master;
-
/* Manually specified configuration file name. */
char *config_file = NULL;
@@ -199,10 +197,12 @@
{
zlog_notice ("Terminating on signal");
- if (! retain_mode)
- bgp_terminate ();
+ if (! retain_mode)
+ {
+ bgp_terminate ();
+ zprivs_terminate (&bgpd_privs);
+ }
- zprivs_terminate (&bgpd_privs);
bgp_exit (0);
}
@@ -237,7 +237,27 @@
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
bgp_delete (bgp);
list_free (bm->bgp);
-
+ bm->bgp = NULL;
+
+ /*
+ * bgp_delete can re-allocate the process queues after they were
+ * deleted in bgp_terminate. delete them again.
+ *
+ * It might be better to ensure the RIBs (including static routes)
+ * are cleared by bgp_terminate() during its call to bgp_cleanup_routes(),
+ * which currently only deletes the kernel routes.
+ */
+ if (bm->process_main_queue)
+ {
+ work_queue_free (bm->process_main_queue);
+ bm->process_main_queue = NULL;
+ }
+ if (bm->process_rsclient_queue)
+ {
+ work_queue_free (bm->process_rsclient_queue);
+ bm->process_rsclient_queue = NULL;
+ }
+
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket))
{
@@ -302,8 +322,8 @@
stream_free (bgp_nexthop_buf);
/* reverse bgp_master_init */
- if (master)
- thread_master_free (master);
+ if (bm->master)
+ thread_master_free (bm->master);
if (zlog_default)
closezlog (zlog_default);
@@ -416,15 +436,12 @@
}
}
- /* Make thread master. */
- master = bm->master;
-
/* Initializations. */
srandom (time (NULL));
- signal_init (master, array_size(bgp_signals), bgp_signals);
+ signal_init (bm->master, array_size(bgp_signals), bgp_signals);
zprivs_init (&bgpd_privs);
cmd_init (1);
- vty_init (master);
+ vty_init (bm->master);
memory_init ();
vrf_init ();
@@ -453,13 +470,14 @@
vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH);
/* Print banner. */
- zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d", QUAGGA_VERSION,
+ zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d pid %d", QUAGGA_VERSION,
vty_port,
(bm->address ? bm->address : "<all>"),
- bm->port);
+ bm->port,
+ getpid ());
/* Start finite state machine, here we go! */
- while (thread_fetch (master, &thread))
+ while (thread_fetch (bm->master, &thread))
thread_call (&thread);
/* Not reached. */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 8a1ed70..a72d5ed 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -170,11 +170,12 @@
int
str2prefix_rd (const char *str, struct prefix_rd *prd)
{
- int ret;
+ int ret; /* ret of called functions */
+ int lret; /* local ret, of this func */
char *p;
char *p2;
- struct stream *s;
- char *half;
+ struct stream *s = NULL;
+ char *half = NULL;
struct in_addr addr;
s = stream_new (8);
@@ -182,12 +183,13 @@
prd->family = AF_UNSPEC;
prd->prefixlen = 64;
+ lret = 0;
p = strchr (str, ':');
if (! p)
- return 0;
+ goto out;
if (! all_digit (p + 1))
- return 0;
+ goto out;
half = XMALLOC (MTYPE_TMP, (p - str) + 1);
memcpy (half, str, (p - str));
@@ -198,10 +200,8 @@
if (! p2)
{
if (! all_digit (half))
- {
- XFREE (MTYPE_TMP, half);
- return 0;
- }
+ goto out;
+
stream_putw (s, RD_TYPE_AS);
stream_putw (s, atoi (half));
stream_putl (s, atol (p + 1));
@@ -210,18 +210,21 @@
{
ret = inet_aton (half, &addr);
if (! ret)
- {
- XFREE (MTYPE_TMP, half);
- return 0;
- }
+ goto out;
+
stream_putw (s, RD_TYPE_IP);
stream_put_in_addr (s, &addr);
stream_putw (s, atol (p + 1));
}
memcpy (prd->val, s->data, 8);
+ lret = 1;
- XFREE(MTYPE_TMP, half);
- return 1;
+out:
+ if (s)
+ stream_free (s);
+ if (half)
+ XFREE(MTYPE_TMP, half);
+ return lret;
}
int
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 7059e8a..3c5e6c5 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -207,7 +207,7 @@
zlog_err ("accept_sock is nevative value %d", accept_sock);
return -1;
}
- listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock);
+ listener->thread = thread_add_read (bm->master, bgp_accept, listener, accept_sock);
/* Accept client connection. */
bgp_sock = sockunion_accept (accept_sock, &su);
@@ -276,6 +276,7 @@
#ifdef SO_BINDTODEVICE
int ret;
struct ifreq ifreq;
+ int myerrno;
if (! peer->ifname)
return 0;
@@ -287,13 +288,15 @@
ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
&ifreq, sizeof (ifreq));
-
+ myerrno = errno;
+
if (bgpd_privs.change (ZPRIVS_LOWER) )
zlog_err ("bgp_bind: could not lower privs");
if (ret < 0)
{
- zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
+ zlog (peer->log, LOG_INFO, "bind to interface %s failed, errno=%d",
+ peer->ifname, myerrno);
return ret;
}
#endif /* SO_BINDTODEVICE */
@@ -480,7 +483,7 @@
listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener));
listener->fd = sock;
memcpy(&listener->su, sa, salen);
- listener->thread = thread_add_read (master, bgp_accept, listener, sock);
+ listener->thread = thread_add_read (bm->master, bgp_accept, listener, sock);
listnode_add (bm->listen_sockets, listener);
return 0;
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 20302e3..145a1d8 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -529,7 +529,7 @@
bgp_scan_timer (struct thread *t)
{
bgp_scan_thread =
- thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
+ thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("Performing BGP general scanning");
@@ -648,9 +648,9 @@
addr = ifc->address;
+ p = *(CONNECTED_PREFIX(ifc));
if (addr->family == AF_INET)
{
- PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
@@ -674,7 +674,6 @@
#ifdef HAVE_IPV6
else if (addr->family == AF_INET6)
{
- PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
@@ -715,9 +714,9 @@
addr = ifc->address;
+ p = *(CONNECTED_PREFIX(ifc));
if (addr->family == AF_INET)
{
- PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
apply_mask_ipv4 ((struct prefix_ipv4 *) &p);
if (prefix_ipv4_any ((struct prefix_ipv4 *) &p))
@@ -742,7 +741,6 @@
#ifdef HAVE_IPV6
else if (addr->family == AF_INET6)
{
- PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
apply_mask_ipv6 ((struct prefix_ipv6 *) &p);
if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6))
@@ -1105,7 +1103,7 @@
safi_t safi;
bgp_import_thread =
- thread_add_timer (master, bgp_import, NULL, bgp_import_interval);
+ thread_add_timer (bm->master, bgp_import, NULL, bgp_import_interval);
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("Import timer expired.");
@@ -1232,7 +1230,7 @@
{
thread_cancel (bgp_scan_thread);
bgp_scan_thread =
- thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
+ thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
}
return CMD_SUCCESS;
@@ -1251,7 +1249,7 @@
{
thread_cancel (bgp_scan_thread);
bgp_scan_thread =
- thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval);
+ thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
}
return CMD_SUCCESS;
@@ -1402,9 +1400,9 @@
void
bgp_scan_init (void)
{
- zlookup = zclient_new ();
+ zlookup = zclient_new (bm->master);
zlookup->sock = -1;
- zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0);
+ zlookup->t_connect = thread_add_event (bm->master, zlookup_connect, zlookup, 0);
bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT;
@@ -1423,10 +1421,10 @@
#endif /* HAVE_IPV6 */
/* Make BGP scan thread. */
- bgp_scan_thread = thread_add_timer (master, bgp_scan_timer,
+ bgp_scan_thread = thread_add_timer (bm->master, bgp_scan_timer,
NULL, bgp_scan_interval);
/* Make BGP import there. */
- bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0);
+ bgp_import_thread = thread_add_timer (bm->master, bgp_import, NULL, 0);
install_element (BGP_NODE, &bgp_scan_time_cmd);
install_element (BGP_NODE, &no_bgp_scan_time_cmd);
@@ -1441,29 +1439,29 @@
void
bgp_scan_finish (void)
{
- /* Only the current one needs to be reset. */
- bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]);
-
- bgp_table_unlock (cache1_table[AFI_IP]);
+ if (cache1_table[AFI_IP])
+ bgp_table_unlock (cache1_table[AFI_IP]);
cache1_table[AFI_IP] = NULL;
- bgp_table_unlock (cache2_table[AFI_IP]);
+ if (cache2_table[AFI_IP])
+ bgp_table_unlock (cache2_table[AFI_IP]);
cache2_table[AFI_IP] = NULL;
-
- bgp_table_unlock (bgp_connected_table[AFI_IP]);
+
+ if (bgp_connected_table[AFI_IP])
+ bgp_table_unlock (bgp_connected_table[AFI_IP]);
bgp_connected_table[AFI_IP] = NULL;
#ifdef HAVE_IPV6
- /* Only the current one needs to be reset. */
- bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]);
-
- bgp_table_unlock (cache1_table[AFI_IP6]);
+ if (cache1_table[AFI_IP6])
+ bgp_table_unlock (cache1_table[AFI_IP6]);
cache1_table[AFI_IP6] = NULL;
- bgp_table_unlock (cache2_table[AFI_IP6]);
+ if (cache2_table[AFI_IP6])
+ bgp_table_unlock (cache2_table[AFI_IP6]);
cache2_table[AFI_IP6] = NULL;
- bgp_table_unlock (bgp_connected_table[AFI_IP6]);
+ if (bgp_connected_table[AFI_IP6])
+ bgp_table_unlock (bgp_connected_table[AFI_IP6]);
bgp_connected_table[AFI_IP6] = NULL;
#endif /* HAVE_IPV6 */
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2616351..e534bee 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1094,10 +1094,10 @@
}
void
-bgp_zebra_init (void)
+bgp_zebra_init (struct thread_master *master)
{
/* Set default values. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_BGP);
zclient->zebra_connected = bgp_zebra_connected;
zclient->router_id_update = bgp_router_id_update;
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 8099193..50f727d 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -25,7 +25,7 @@
extern struct stream *bgp_nexthop_buf;
-extern void bgp_zebra_init (void);
+extern void bgp_zebra_init (struct thread_master *master);
extern int bgp_if_update_all (void);
extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 0068037..90e77f2 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -737,6 +737,9 @@
if (peer->clear_node_queue)
work_queue_free (peer->clear_node_queue);
+ if (peer->notify.data)
+ XFREE(MTYPE_TMP, peer->notify.data);
+
bgp_sync_delete (peer);
memset (peer, 0, sizeof (struct peer));
@@ -1978,7 +1981,7 @@
if (name)
bgp->name = strdup (name);
- THREAD_TIMER_ON (master, bgp->t_startup, bgp_startup_timer_expire,
+ THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
bgp, bgp->restart_time);
return bgp;
@@ -1988,7 +1991,7 @@
struct bgp *
bgp_get_default (void)
{
- if (bm->bgp->head)
+ if (bm && bm->bgp && bm->bgp->head)
return (listgetdata (listhead (bm->bgp)));
return NULL;
}
@@ -5421,7 +5424,7 @@
bgp_vty_init ();
/* Init zebra. */
- bgp_zebra_init ();
+ bgp_zebra_init (bm->master);
/* BGP inits. */
bgp_attr_init ();
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7ae0acb..95c16de 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -834,8 +834,6 @@
extern struct bgp_master *bm;
-extern struct thread_master *master;
-
/* Prototypes. */
extern void bgp_terminate (void);
extern void bgp_reset (void);
diff --git a/doc/ospfd.texi b/doc/ospfd.texi
index 856a2ba..7ddc9db 100644
--- a/doc/ospfd.texi
+++ b/doc/ospfd.texi
@@ -216,6 +216,7 @@
@deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
+@anchor{OSPF network command}
This command specifies the OSPF enabled interface(s). If the interface has
an address from range 192.168.1.0/24 then the command below enables ospf
on this interface so router can provide network information to the other
@@ -239,6 +240,10 @@
then we test whether the prefix in the network command contains
the destination prefix. Otherwise, we test whether the network command prefix
contains the local address prefix of the interface.
+
+In some cases it may be more convenient to enable OSPF on a per
+interface/subnet basis (@pxref{OSPF ip ospf area command}).
+
@end deffn
@node OSPF area
@@ -406,6 +411,19 @@
@node OSPF interface
@section OSPF interface
+@deffn {Interface Command} {ip ospf area @var{AREA} [@var{ADDR}]} {}
+@deffnx {Interface Command} {no ip ospf area [@var{ADDR}]} {}
+@anchor{OSPF ip ospf area command}
+
+Enable OSPF on the interface, optionally restricted to just the IP address
+given by @var{ADDR}, putting it in the @var{AREA} area. Per interface area
+settings take precedence to network commands (@pxref{OSPF network command}).
+
+If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF
+via this command may result in a slight performance improvement.
+
+@end deffn
+
@deffn {Interface Command} {ip ospf authentication-key @var{AUTH_KEY}} {}
@deffnx {Interface Command} {no ip ospf authentication-key} {}
Set OSPF authentication key to a simple password. After setting @var{AUTH_KEY},
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 0b1dac1..0470c5b 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1789,7 +1789,18 @@
}
else
{
- lsp_regenerate (area, lvl);
+ /*
+ * lsps are not regenerated if lsp_regenerate function is called
+ * directly. However if the lsp_regenerate call is queued for
+ * later execution it works.
+ */
+ area->lsp_regenerate_pending[lvl - 1] = 1;
+ if (lvl == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+ lsp_l1_refresh, area, 0);
+ else if (lvl == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+ lsp_l2_refresh, area, 0);
}
}
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index e1af71f..fba7b10 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -339,7 +339,7 @@
/* create the global 'isis' instance */
isis_new (1);
- isis_zebra_init ();
+ isis_zebra_init (master);
/* parse config file */
/* this is needed three times! because we have interfaces before the areas */
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index d202264..a9ecd40 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -230,12 +230,24 @@
LLC_LEN, MSG_PEEK,
(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
- if (bytesread < 0)
+ if ((bytesread < 0) || (s_addr.sll_ifindex != (int)circuit->interface->ifindex))
{
- zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, "
- "recvfrom(): %s",
- circuit->interface->name, circuit->fd, bytesread,
- safe_strerror (errno));
+ if (bytesread < 0)
+ {
+ zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, "
+ "bytesread %d, recvfrom(): %s",
+ circuit->interface->name, circuit->fd, bytesread,
+ safe_strerror (errno));
+ }
+ if (s_addr.sll_ifindex != (int)circuit->interface->ifindex)
+ {
+ zlog_warn("packet is received on multiple interfaces: "
+ "socket interface %d, circuit interface %d, "
+ "packet type %u",
+ s_addr.sll_ifindex, circuit->interface->ifindex,
+ s_addr.sll_pkttype);
+ }
+
/* get rid of the packet */
bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
MSG_DONTWAIT, (struct sockaddr *) &s_addr,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 6d0c157..8a78417 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -602,9 +602,9 @@
}
void
-isis_zebra_init ()
+isis_zebra_init (struct thread_master *master)
{
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_ISIS);
zclient->zebra_connected = isis_zebra_connected;
zclient->router_id_update = isis_router_id_update_zebra;
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 889cd9b..0011478 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -24,7 +24,7 @@
extern struct zclient *zclient;
-void isis_zebra_init (void);
+void isis_zebra_init (struct thread_master *);
void isis_zebra_route_update (struct prefix *prefix,
struct isis_route_info *route_info);
int isis_distribute_list_update (int routetype);
diff --git a/lib/command.c b/lib/command.c
index 2084160..37767e9 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2794,34 +2794,69 @@
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
}
+/**
+ * Parse one line of config, walking up the parse tree attempting to find a match
+ *
+ * @param vty The vty context in which the command should be executed.
+ * @param cmd Pointer where the struct cmd_element* of the match command
+ * will be stored, if any. May be set to NULL if this info is
+ * not needed.
+ * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
+ * or not.
+ * @return The status of the command that has been executed or an error code
+ * as to why no command could be executed.
+ */
+int
+command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
+{
+ vector vline;
+ int saved_node;
+ int ret;
+
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of comment line */
+ if (vline == NULL)
+ return CMD_SUCCESS;
+
+ /* Execute configuration command : this is strict match */
+ ret = cmd_execute_command_strict (vline, vty, cmd);
+
+ saved_node = vty->node;
+
+ while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
+ ret != CMD_SUCCESS && ret != CMD_WARNING &&
+ ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) {
+ vty->node = node_parent(vty->node);
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+
+ // If climbing the tree did not work then ignore the command and
+ // stay at the same node
+ if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
+ ret != CMD_SUCCESS && ret != CMD_WARNING &&
+ ret != CMD_ERR_NOTHING_TODO)
+ {
+ vty->node = saved_node;
+ }
+
+ cmd_free_strvec (vline);
+
+ return ret;
+}
+
/* Configration make from file. */
int
config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
{
int ret;
*line_num = 0;
- vector vline;
while (fgets (vty->buf, VTY_BUFSIZ, fp))
{
++(*line_num);
- vline = cmd_make_strvec (vty->buf);
- /* In case of comment line */
- if (vline == NULL)
- continue;
- /* Execute configuration command : this is strict match */
- ret = cmd_execute_command_strict (vline, vty, NULL);
-
- /* Try again with setting node to CONFIG_NODE */
- while (ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
- {
- vty->node = node_parent(vty->node);
- ret = cmd_execute_command_strict (vline, vty, NULL);
- }
-
- cmd_free_strvec (vline);
+ ret = command_config_read_one_line (vty, NULL, 0);
if (ret != CMD_SUCCESS && ret != CMD_WARNING
&& ret != CMD_ERR_NOTHING_TODO)
diff --git a/lib/command.h b/lib/command.h
index bb0122f..6030069 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -527,6 +527,7 @@
extern vector cmd_describe_command (vector, struct vty *, int *status);
extern char **cmd_complete_command (vector, struct vty *, int *status);
extern const char *cmd_prompt (enum node_type);
+extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node);
extern int config_from_file (struct vty *, FILE *, unsigned int *line_num);
extern enum node_type node_parent (enum node_type);
extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int);
diff --git a/lib/routemap.c b/lib/routemap.c
index 1e1510e..7302e23 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -897,6 +897,9 @@
route_match_vec = NULL;
vector_free (route_set_vec);
route_set_vec = NULL;
+ /* cleanup route_map */
+ while (route_map_master.head)
+ route_map_delete (route_map_master.head);
}
/* VTY related functions. */
diff --git a/lib/smux.c b/lib/smux.c
index 70be492..03da99f 100644
--- a/lib/smux.c
+++ b/lib/smux.c
@@ -113,7 +113,7 @@
};
/* thread master */
-static struct thread_master *master;
+static struct thread_master *smux_master;
static int
oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
@@ -1239,13 +1239,13 @@
switch (event)
{
case SMUX_SCHEDULE:
- smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
+ smux_connect_thread = thread_add_event (smux_master, smux_connect, NULL, 0);
break;
case SMUX_CONNECT:
- smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
+ smux_connect_thread = thread_add_timer (smux_master, smux_connect, NULL, 10);
break;
case SMUX_READ:
- smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
+ smux_read_thread = thread_add_read (smux_master, smux_read, NULL, sock);
break;
default:
break;
@@ -1474,7 +1474,7 @@
smux_init (struct thread_master *tm)
{
/* copy callers thread master */
- master = tm;
+ smux_master = tm;
/* Make MIB tree. */
treelist = list_new();
diff --git a/lib/vty.c b/lib/vty.c
index 5c4a23b..8befcb0 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2573,7 +2573,7 @@
}
/* Master of the threads. */
-static struct thread_master *master;
+static struct thread_master *vty_master;
static void
vty_event (enum event event, int sock, struct vty *vty)
@@ -2583,23 +2583,23 @@
switch (event)
{
case VTY_SERV:
- vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
+ vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
break;
#ifdef VTYSH
case VTYSH_SERV:
- vty_serv_thread = thread_add_read (master, vtysh_accept, vty, sock);
+ vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
break;
case VTYSH_READ:
- vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
+ vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
break;
case VTYSH_WRITE:
- vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
+ vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
break;
#endif /* VTYSH */
case VTY_READ:
- vty->t_read = thread_add_read (master, vty_read, vty, sock);
+ vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
/* Time out treatment. */
if (vty->v_timeout)
@@ -2607,12 +2607,12 @@
if (vty->t_timeout)
thread_cancel (vty->t_timeout);
vty->t_timeout =
- thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+ thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
}
break;
case VTY_WRITE:
if (! vty->t_write)
- vty->t_write = thread_add_write (master, vty_flush, vty, sock);
+ vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
break;
case VTY_TIMEOUT_RESET:
if (vty->t_timeout)
@@ -2623,7 +2623,7 @@
if (vty->v_timeout)
{
vty->t_timeout =
- thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+ thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
}
break;
}
@@ -3035,7 +3035,7 @@
vtyvec = vector_init (VECTOR_MIN_SIZE);
- master = master_thread;
+ vty_master = master_thread;
atexit (vty_stdio_reset);
diff --git a/lib/zclient.c b/lib/zclient.c
index 0ce46fe..bfff9a3 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -39,8 +39,6 @@
/* Prototype for event manager. */
static void zclient_event (enum event, struct zclient *);
-extern struct thread_master *master;
-
const char *zclient_serv_path = NULL;
/* This file local debug flag. */
@@ -48,7 +46,7 @@
/* Allocate zclient structure. */
struct zclient *
-zclient_new ()
+zclient_new (struct thread_master *master)
{
struct zclient *zclient;
zclient = XCALLOC (MTYPE_ZCLIENT, sizeof (struct zclient));
@@ -56,6 +54,7 @@
zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
zclient->wb = buffer_new(0);
+ zclient->master = master;
return zclient;
}
@@ -258,8 +257,8 @@
return zclient_failed(zclient);
break;
case BUFFER_PENDING:
- zclient->t_write = thread_add_write(master, zclient_flush_data,
- zclient, zclient->sock);
+ zclient->t_write = thread_add_write (zclient->master, zclient_flush_data,
+ zclient, zclient->sock);
break;
case BUFFER_EMPTY:
break;
@@ -284,8 +283,8 @@
THREAD_OFF(zclient->t_write);
break;
case BUFFER_PENDING:
- THREAD_WRITE_ON(master, zclient->t_write,
- zclient_flush_data, zclient, zclient->sock);
+ THREAD_WRITE_ON (zclient->master, zclient->t_write,
+ zclient_flush_data, zclient, zclient->sock);
break;
}
return 0;
@@ -1092,7 +1091,7 @@
case ZCLIENT_SCHEDULE:
if (! zclient->t_connect)
zclient->t_connect =
- thread_add_event (master, zclient_connect, zclient, 0);
+ thread_add_event (zclient->master, zclient_connect, zclient, 0);
break;
case ZCLIENT_CONNECT:
if (zclient->fail >= 10)
@@ -1102,12 +1101,12 @@
zclient->fail < 3 ? 10 : 60);
if (! zclient->t_connect)
zclient->t_connect =
- thread_add_timer (master, zclient_connect, zclient,
+ thread_add_timer (zclient->master, zclient_connect, zclient,
zclient->fail < 3 ? 10 : 60);
break;
case ZCLIENT_READ:
zclient->t_read =
- thread_add_read (master, zclient_read, zclient, zclient->sock);
+ thread_add_read (zclient->master, zclient_read, zclient, zclient->sock);
break;
}
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 3490b32..aa935c1 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -40,6 +40,9 @@
/* Structure for the zebra client. */
struct zclient
{
+ /* The thread master we schedule ourselves on */
+ struct thread_master *master;
+
/* Socket to zebra daemon. */
int sock;
@@ -132,7 +135,7 @@
};
/* Prototypes of zebra client service functions. */
-extern struct zclient *zclient_new (void);
+extern struct zclient *zclient_new (struct thread_master *);
extern void zclient_init (struct zclient *, int);
extern int zclient_start (struct zclient *);
extern void zclient_stop (struct zclient *);
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 951e11d..d37e508 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -578,10 +578,10 @@
}
void
-ospf6_zebra_init (void)
+ospf6_zebra_init (struct thread_master *master)
{
/* Allocate zebra structure. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_OSPF6);
zclient->zebra_connected = ospf6_zebra_connected;
zclient->router_id_update = ospf6_router_id_update_zebra;
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index a219450..05694d3 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -44,7 +44,7 @@
extern void ospf6_zebra_no_redistribute (int);
#define ospf6_zebra_is_redistribute(type) \
vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)
-extern void ospf6_zebra_init (void);
+extern void ospf6_zebra_init(struct thread_master *);
extern int config_write_ospf6_debug_zebra (struct vty *vty);
extern void install_element_ospf6_debug_zebra (void);
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index 3cdd5c1..c2baa31 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -1764,7 +1764,7 @@
ospf6_area_init ();
ospf6_interface_init ();
ospf6_neighbor_init ();
- ospf6_zebra_init ();
+ ospf6_zebra_init (master);
ospf6_lsa_init ();
ospf6_spf_init ();
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index ed698c8..2ed426f 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -30,8 +30,17 @@
#define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params)
#define IF_OIFS(I) (IF_OSPF_IF_INFO (I)->oifs)
#define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params)
-
+
+/* Despite the name, this macro probably is for specialist use only */
#define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config)
+
+/* Test whether an OSPF interface parameter is set, generally, given some
+ * existing ospf interface
+ */
+#define OSPF_IF_PARAM_IS_SET(O,P) \
+ (OSPF_IF_PARAM_CONFIGURED ((O)->params, P) || \
+ OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp)->P))
+
#define OSPF_IF_PARAM(O, P) \
(OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\
(O)->params->P:IF_DEF_PARAMS((O)->ifp)->P)
@@ -47,6 +56,7 @@
DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */
DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */
DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */
+ DECLARE_IF_PARAM (struct in_addr, if_area); /* Enable OSPF on this interface with area if_area */
DECLARE_IF_PARAM (u_char, type); /* type of interface */
#define OSPF_IF_ACTIVE 0
#define OSPF_IF_PASSIVE 1
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index 826fc98..1e4184f 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -298,7 +298,7 @@
/* OSPFd inits. */
ospf_if_init ();
- ospf_zebra_init ();
+ ospf_zebra_init (master);
/* OSPF vty inits. */
ospf_vty_init ();
@@ -312,15 +312,6 @@
ospf_opaque_init ();
#endif /* HAVE_OPAQUE_LSA */
- /* Need to initialize the default ospf structure, so the interface mode
- commands can be duly processed if they are received before 'router ospf',
- when quagga(ospfd) is restarted */
- if (!ospf_get())
- {
- zlog_err("OSPF instance init failed: %s", strerror(errno));
- exit (1);
- }
-
/* Get configuration file. */
vty_read_config (config_file, config_default);
diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c
index c3bdf99..23a6417 100644
--- a/ospfd/ospf_neighbor.c
+++ b/ospfd/ospf_neighbor.c
@@ -45,8 +45,8 @@
/* Fill in the the 'key' as appropriate to retrieve the entry for nbr
* from the ospf_interface's nbrs table. Indexed by interface address
- * for all cases except Virtual-link interfaces, where neighbours are
- * indexed by router-ID instead.
+ * for all cases except Virtual-link and PointToPoint interfaces, where
+ * neighbours are indexed by router-ID instead.
*/
static void
ospf_nbr_key (struct ospf_interface *oi, struct ospf_neighbor *nbr,
@@ -56,7 +56,8 @@
key->prefixlen = IPV4_MAX_BITLEN;
/* vlinks are indexed by router-id */
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK ||
+ oi->type == OSPF_IFTYPE_POINTOPOINT)
key->u.prefix4 = nbr->router_id;
else
key->u.prefix4 = nbr->src;
@@ -291,8 +292,8 @@
#endif /* HAVE_OPAQUE_LSA */
/* lookup nbr by address - use this only if you know you must
- * otherwise use the ospf_nbr_lookup() wrapper, which deals
- * with virtual link neighbours
+ * otherwise use the ospf_nbr_lookup() wrapper, which deals
+ * with virtual link and PointToPoint neighbours
*/
struct ospf_neighbor *
ospf_nbr_lookup_by_addr (struct route_table *nbrs,
@@ -384,7 +385,8 @@
ospf_nbr_lookup (struct ospf_interface *oi, struct ip *iph,
struct ospf_header *ospfh)
{
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK ||
+ oi->type == OSPF_IFTYPE_POINTOPOINT)
return (ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id));
else
return (ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src));
@@ -444,8 +446,9 @@
key.family = AF_INET;
key.prefixlen = IPV4_MAX_BITLEN;
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- key.u.prefix4 = ospfh->router_id; /* index vlink nbrs by router-id */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK ||
+ oi->type == OSPF_IFTYPE_POINTOPOINT)
+ key.u.prefix4 = ospfh->router_id;/* index vlink and ptp nbrs by router-id */
else
key.u.prefix4 = iph->ip_src;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c6f3b40..45a19c0 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -292,6 +292,41 @@
}
}
+/* get the appropriate ospf parameters structure, checking if
+ * there's a valid interface address at the argi'th argv index
+ */
+enum {
+ VTY_SET = 0,
+ VTY_UNSET,
+};
+#define OSPF_VTY_GET_IF_PARAMS(ifp,params,argi,addr,set) \
+ (params) = IF_DEF_PARAMS ((ifp)); \
+ \
+ if (argc == (argi) + 1) \
+ { \
+ int ret = inet_aton(argv[(argi)], &(addr)); \
+ if (!ret) \
+ { \
+ vty_out (vty, "Please specify interface address by A.B.C.D%s", \
+ VTY_NEWLINE); \
+ return CMD_WARNING; \
+ } \
+ (params) = ospf_get_if_params ((ifp), (addr)); \
+ \
+ if (set) \
+ ospf_if_update_params ((ifp), (addr)); \
+ else if ((params) == NULL) \
+ return CMD_SUCCESS; \
+ }
+
+#define OSPF_VTY_PARAM_UNSET(params,var,ifp,addr) \
+ UNSET_IF_PARAM ((params), var); \
+ if ((params) != IF_DEF_PARAMS ((ifp))) \
+ { \
+ ospf_free_if_params ((ifp), (addr)); \
+ ospf_if_update_params ((ifp), (addr)); \
+ }
+
DEFUN (ospf_passive_interface,
ospf_passive_interface_addr_cmd,
"passive-interface IFNAME A.B.C.D",
@@ -453,7 +488,7 @@
"OSPF area ID in IP address format\n"
"OSPF area ID as a decimal value\n")
{
- struct ospf *ospf= vty->index;
+ struct ospf *ospf = vty->index;
struct prefix_ipv4 p;
struct in_addr area_id;
int ret, format;
@@ -5883,6 +5918,70 @@
"OSPF interface commands\n"
"Link state transmit delay\n")
+DEFUN (ip_ospf_area,
+ ip_ospf_area_cmd,
+ "ip ospf area (A.B.C.D|<0-4294967295>) [A.B.C.D]",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Enable OSPF on this interface\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Address of interface\n")
+{
+ struct interface *ifp = vty->index;
+ struct in_addr area_id;
+ struct in_addr addr;
+ int format;
+ struct ospf_if_params *params;
+
+ VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]);
+
+ OSPF_VTY_GET_IF_PARAMS(ifp, params, 1, addr, VTY_SET);
+
+ if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
+ {
+ vty_out (vty, "There is already an interface area statement.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (memcmp (ifp->name, "VLINK", 5) == 0)
+ {
+ vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ SET_IF_PARAM (params, if_area);
+ params->if_area = area_id;
+ ospf_interface_area_set (ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_ospf_area,
+ no_ip_ospf_area_cmd,
+ "no ip ospf area [A.B.C.D]",
+ NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Disable OSPF on this interface\n"
+ "Address of interface\n")
+{
+ struct interface *ifp = vty->index;
+ struct ospf_if_params *params;
+ struct in_addr addr;
+
+ OSPF_VTY_GET_IF_PARAMS(ifp, params, 0, addr, VTY_UNSET);
+
+ if (!OSPF_IF_PARAM_CONFIGURED(params, if_area))
+ return CMD_SUCCESS;
+
+ OSPF_VTY_PARAM_UNSET(params, if_area, ifp, addr);
+
+ ospf_interface_area_unset (ifp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ospf_redistribute_source,
ospf_redistribute_source_cmd,
"redistribute " QUAGGA_REDIST_STR_OSPFD
@@ -6947,6 +7046,15 @@
vty_out (vty, "%s", VTY_NEWLINE);
}
+ /* Area print. */
+ if (OSPF_IF_PARAM_CONFIGURED (params, if_area))
+ {
+ vty_out (vty, " ip ospf area %s", inet_ntoa (params->if_area));
+ if (params != IF_DEF_PARAMS (ifp))
+ vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
/* MTU ignore print. */
if (OSPF_IF_PARAM_CONFIGURED (params, mtu_ignore) &&
params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT)
@@ -7597,6 +7705,10 @@
install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd);
install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd);
+ /* "ip ospf area" commands. */
+ install_element (INTERFACE_NODE, &ip_ospf_area_cmd);
+ install_element (INTERFACE_NODE, &no_ip_ospf_area_cmd);
+
/* These commands are compatibitliy for previous version. */
install_element (INTERFACE_NODE, &ospf_authentication_key_cmd);
install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 588f0fb..cf2ea81 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1304,10 +1304,10 @@
}
void
-ospf_zebra_init ()
+ospf_zebra_init (struct thread_master *master)
{
/* Allocate zebra structure. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_OSPF);
zclient->zebra_connected = ospf_zebra_connected;
zclient->router_id_update = ospf_router_id_update_zebra;
diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h
index 148f652..32a0271 100644
--- a/ospfd/ospf_zebra.h
+++ b/ospfd/ospf_zebra.h
@@ -72,7 +72,7 @@
const char *, const char *);
extern int ospf_distance_unset (struct vty *, struct ospf *, const char *,
const char *, const char *);
-extern void ospf_zebra_init (void);
+extern void ospf_zebra_init (struct thread_master *);
#endif /* _ZEBRA_OSPF_ZEBRA_H */
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 8c7d1c2..c317ed8 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -69,8 +69,10 @@
static void ospf_network_free (struct ospf *, struct ospf_network *);
static void ospf_area_free (struct ospf_area *);
static void ospf_network_run (struct prefix *, struct ospf_area *);
-static void ospf_network_run_interface (struct prefix *, struct ospf_area *,
- struct interface *);
+static void ospf_network_run_interface (struct ospf *, struct interface *,
+ struct prefix *, struct ospf_area *);
+static void ospf_network_run_subnet (struct ospf *, struct connected *,
+ struct prefix *, struct ospf_area *);
static int ospf_network_match_iface (const struct connected *,
const struct prefix *);
static void ospf_finish_final (struct ospf *);
@@ -256,6 +258,16 @@
return listgetdata (listhead (om->ospf));
}
+static int
+ospf_is_ready (struct ospf *ospf)
+{
+ /* OSPF must be on and Router-ID must be configured. */
+ if (!ospf || ospf->router_id.s_addr == 0)
+ return 0;
+
+ return 1;
+}
+
static void
ospf_add (struct ospf *ospf)
{
@@ -743,6 +755,70 @@
return new;
}
+static void
+add_ospf_interface (struct connected *co, struct ospf_area *area)
+{
+ struct ospf_interface *oi;
+
+ oi = ospf_if_new (area->ospf, co->ifp, co->address);
+ oi->connected = co;
+
+ oi->area = area;
+
+ oi->params = ospf_lookup_if_params (co->ifp, oi->address->u.prefix4);
+ oi->output_cost = ospf_if_get_output_cost (oi);
+
+ /* Add pseudo neighbor. */
+ ospf_nbr_add_self (oi);
+
+ /* Relate ospf interface to ospf instance. */
+ oi->ospf = area->ospf;
+
+ /* update network type as interface flag */
+ /* If network type is specified previously,
+ skip network type setting. */
+ oi->type = IF_DEF_PARAMS (co->ifp)->type;
+
+ ospf_area_add_if (oi->area, oi);
+
+ /* if router_id is not configured, dont bring up
+ * interfaces.
+ * ospf_router_id_update() will call ospf_if_update
+ * whenever r-id is configured instead.
+ */
+ if ((area->ospf->router_id.s_addr != 0)
+ && if_is_operative (co->ifp))
+ ospf_if_up (oi);
+}
+
+static void
+update_redistributed (struct ospf *ospf, int add_to_ospf)
+{
+ struct route_node *rn;
+ struct external_info *ei;
+
+ if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
+ if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT))
+ for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT));
+ rn; rn = route_next (rn))
+ if ((ei = rn->info) != NULL)
+ {
+ if (add_to_ospf)
+ {
+ if (ospf_external_info_find_lsa (ospf, &ei->p))
+ if (!ospf_distribute_check_connected (ospf, ei))
+ ospf_external_lsa_flush (ospf, ei->type, &ei->p,
+ ei->ifindex /*, ei->nexthop */);
+ }
+ else
+ {
+ if (!ospf_external_info_find_lsa (ospf, &ei->p))
+ if (ospf_distribute_check_connected (ospf, ei))
+ ospf_external_lsa_originate (ospf, ei);
+ }
+ }
+}
+
static void
ospf_network_free (struct ospf *ospf, struct ospf_network *network)
{
@@ -758,7 +834,6 @@
struct ospf_network *network;
struct ospf_area *area;
struct route_node *rn;
- struct external_info *ei;
int ret = OSPF_AREA_ID_FORMAT_ADDRESS;
rn = route_node_get (ospf->networks, (struct prefix *)p);
@@ -776,16 +851,8 @@
ospf_network_run ((struct prefix *)p, area);
/* Update connected redistribute. */
- if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
- if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT))
- for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT));
- rn; rn = route_next (rn))
- if ((ei = rn->info) != NULL)
- if (ospf_external_info_find_lsa (ospf, &ei->p))
- if (!ospf_distribute_check_connected (ospf, ei))
- ospf_external_lsa_flush (ospf, ei->type, &ei->p,
- ei->ifindex /*, ei->nexthop */);
-
+ update_redistributed(ospf, 1);
+
ospf_area_check_free (ospf, area_id);
return 1;
@@ -797,7 +864,6 @@
{
struct route_node *rn;
struct ospf_network *network;
- struct external_info *ei;
struct listnode *node, *nnode;
struct ospf_interface *oi;
@@ -817,45 +883,66 @@
/* Find interfaces that not configured already. */
for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
{
- int found = 0;
- struct connected *co = oi->connected;
-
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
continue;
- for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
- {
- if (rn->info == NULL)
- continue;
-
- if (ospf_network_match_iface(co,&rn->p))
- {
- found = 1;
- route_unlock_node (rn);
- break;
- }
- }
-
- if (found == 0)
- {
- ospf_if_free (oi);
- ospf_area_check_free (ospf, area_id);
- }
+ ospf_network_run_subnet (ospf, oi->connected, NULL, NULL);
}
/* Update connected redistribute. */
- if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT))
- if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT))
- for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT));
- rn; rn = route_next (rn))
- if ((ei = rn->info) != NULL)
- if (!ospf_external_info_find_lsa (ospf, &ei->p))
- if (ospf_distribute_check_connected (ospf, ei))
- ospf_external_lsa_originate (ospf, ei);
-
+ update_redistributed(ospf, 0);
+
+ ospf_area_check_free (ospf, area_id);
+
return 1;
}
+/* Ensure there's an OSPF instance, as "ip ospf area" enabled OSPF means
+ * there might not be any 'router ospf' config.
+ *
+ * Otherwise, doesn't do anything different to ospf_if_update for now
+ */
+void
+ospf_interface_area_set (struct interface *ifp)
+{
+ struct ospf *ospf = ospf_get();
+
+ ospf_if_update (ospf, ifp);
+ /* if_update does a update_redistributed */
+
+ return;
+}
+
+void
+ospf_interface_area_unset (struct interface *ifp)
+{
+ struct route_node *rn_oi;
+ struct ospf *ospf;
+
+ if ((ospf = ospf_lookup ()) == NULL)
+ return; /* Ospf not ready yet */
+
+ /* Find interfaces that may need to be removed. */
+ for (rn_oi = route_top (IF_OIFS (ifp)); rn_oi; rn_oi = route_next (rn_oi))
+ {
+ struct ospf_interface *oi;
+
+ if ( (oi = rn_oi->info) == NULL)
+ continue;
+
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ continue;
+
+ ospf_network_run_subnet (ospf, oi->connected, NULL, NULL);
+ }
+
+ /* Update connected redistribute. */
+ update_redistributed (ospf, 0); /* interfaces possibly removed */
+
+ return;
+}
+
+
/* Check whether interface matches given network
* returns: 1, true. 0, false
*/
@@ -867,8 +954,101 @@
}
static void
-ospf_network_run_interface (struct prefix *p, struct ospf_area *area,
- struct interface *ifp)
+ospf_update_interface_area (struct connected *co, struct ospf_area *area)
+{
+ struct ospf_interface *oi = ospf_if_table_lookup (co->ifp, co->address);
+
+ /* nothing to be done case */
+ if (oi && oi->area == area)
+ return;
+
+ if (oi)
+ ospf_if_free (oi);
+
+ add_ospf_interface (co, area);
+}
+
+/* Run OSPF for the given subnet, taking into account the following
+ * possible sources of area configuration, in the given order of preference:
+ *
+ * - Whether there is interface+address specific area configuration
+ * - Whether there is a default area for the interface
+ * - Whether there is an area given as a parameter.
+ * - If no specific network prefix/area is supplied, whether there's
+ * a matching network configured.
+ */
+static void
+ospf_network_run_subnet (struct ospf *ospf, struct connected *co,
+ struct prefix *p, struct ospf_area *given_area)
+{
+ struct ospf_interface *oi;
+ struct ospf_if_params *params;
+ struct ospf_area *area = NULL;
+ struct route_node *rn;
+ int configed = 0;
+
+ if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
+ return;
+
+ if (co->address->family != AF_INET)
+ return;
+
+ /* Try determine the appropriate area for this interface + address
+ * Start by checking interface config
+ */
+ if (!(params = ospf_lookup_if_params (co->ifp, co->address->u.prefix4)))
+ params = IF_DEF_PARAMS (co->ifp);
+
+ if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
+ area = (ospf_area_get (ospf, params->if_area,
+ OSPF_AREA_ID_FORMAT_ADDRESS));
+
+ /* If we've found an interface and/or addr specific area, then we're
+ * done
+ */
+ if (area)
+ {
+ ospf_update_interface_area (co, area);
+ return;
+ }
+
+ /* Otherwise, only remaining possibility is a matching network statement */
+ if (p)
+ {
+ assert (given_area != NULL);
+
+ /* Which either was supplied as a parameter.. (e.g. cause a new
+ * network/area was just added)..
+ */
+ if (p->family == co->address->family
+ && ospf_network_match_iface (co, p))
+ ospf_update_interface_area (co, given_area);
+
+ return;
+ }
+
+ /* Else we have to search the existing network/area config to see
+ * if any match..
+ */
+ for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
+ if (rn->info != NULL
+ && ospf_network_match_iface (co, &rn->p))
+ {
+ struct ospf_network *network = (struct ospf_network *) rn->info;
+ area = ospf_area_get (ospf, network->area_id, network->format);
+ ospf_update_interface_area (co, area);
+ configed = 1;
+ }
+
+ /* If the subnet isn't in any area, deconfigure */
+ if (!configed && (oi = ospf_if_table_lookup (co->ifp, co->address)))
+ ospf_if_free (oi);
+}
+
+static void
+ospf_network_run_interface (struct ospf *ospf, struct interface *ifp,
+ struct prefix *p,
+ struct ospf_area *given_area)
{
struct listnode *cnode;
struct connected *co;
@@ -876,51 +1056,14 @@
if (memcmp (ifp->name, "VLINK", 5) == 0)
return;
+ /* Network prefix without area is nonsensical */
+ if (p)
+ assert (given_area != NULL);
+
/* if interface prefix is match specified prefix,
then create socket and join multicast group. */
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co))
- {
-
- if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY))
- continue;
-
- if (p->family == co->address->family
- && ! ospf_if_table_lookup(ifp, co->address)
- && ospf_network_match_iface(co,p))
- {
- struct ospf_interface *oi;
-
- oi = ospf_if_new (area->ospf, ifp, co->address);
- oi->connected = co;
-
- oi->area = area;
-
- oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4);
- oi->output_cost = ospf_if_get_output_cost (oi);
-
- /* Add pseudo neighbor. */
- ospf_nbr_add_self (oi);
-
- /* Relate ospf interface to ospf instance. */
- oi->ospf = area->ospf;
-
- /* update network type as interface flag */
- /* If network type is specified previously,
- skip network type setting. */
- oi->type = IF_DEF_PARAMS (ifp)->type;
-
- ospf_area_add_if (oi->area, oi);
-
- /* if router_id is not configured, dont bring up
- * interfaces.
- * ospf_router_id_update() will call ospf_if_update
- * whenever r-id is configured instead.
- */
- if ((area->ospf->router_id.s_addr != 0)
- && if_is_operative (ifp))
- ospf_if_up (oi);
- }
- }
+ ospf_network_run_subnet (ospf, co, p, given_area);
}
static void
@@ -935,7 +1078,7 @@
/* Get target interface. */
for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp))
- ospf_network_run_interface (p, area, ifp);
+ ospf_network_run_interface (area->ospf, ifp, p, area);
}
void
@@ -968,25 +1111,17 @@
void
ospf_if_update (struct ospf *ospf, struct interface *ifp)
{
- struct route_node *rn;
- struct ospf_network *network;
- struct ospf_area *area;
-
if (!ospf)
ospf = ospf_lookup ();
- /* OSPF must be on and Router-ID must be configured. */
- if (!ospf || ospf->router_id.s_addr == 0)
+ /* OSPF must be ready. */
+ if (!ospf_is_ready (ospf))
return;
- /* Run each netowrk for this interface. */
- for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
- if (rn->info != NULL)
- {
- network = (struct ospf_network *) rn->info;
- area = ospf_area_get (ospf, network->area_id, network->format);
- ospf_network_run_interface (&rn->p, area, ifp);
- }
+ ospf_network_run_interface (ospf, ifp, NULL, NULL);
+
+ /* Update connected redistribute. */
+ update_redistributed(ospf, 1);
}
void
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index c50e615..595c04f 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -563,6 +563,9 @@
extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *);
extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *);
+extern void ospf_interface_area_set (struct interface *);
+extern void ospf_interface_area_unset (struct interface *);
+
extern void ospf_route_map_init (void);
extern void ospf_snmp_init (void);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 6f806a1..930dad0 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -249,35 +249,6 @@
pim_hello_restart_now(ifp); /* send hello and restart timer */
}
-static void on_primary_address_change(struct interface *ifp,
- const char *caller,
- struct in_addr old_addr,
- struct in_addr new_addr)
-{
- struct pim_interface *pim_ifp;
-
- {
- char old_str[100];
- char new_str[100];
- pim_inet4_dump("<old?>", old_addr, old_str, sizeof(old_str));
- pim_inet4_dump("<new?>", new_addr, new_str, sizeof(new_str));
- zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
- __PRETTY_FUNCTION__, caller,
- old_str, new_str, ifp->name);
- }
-
- pim_ifp = ifp->info;
- if (!pim_ifp) {
- return;
- }
-
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- return;
- }
-
- pim_addr_change(ifp);
-}
-
static int detect_primary_address_change(struct interface *ifp,
int force_prim_as_any,
const char *caller)
@@ -309,10 +280,13 @@
}
if (changed) {
- struct in_addr old_addr = pim_ifp->primary_address;
pim_ifp->primary_address = new_prim_addr;
- on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
+ if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
+ return changed;
+ }
+
+ pim_addr_change(ifp);
}
return changed;
@@ -329,14 +303,9 @@
return;
changed = 1; /* true */
- zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
- __PRETTY_FUNCTION__, ifp->name);
-
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug("%s: on interface %s: %s",
- __PRETTY_FUNCTION__,
- ifp->name, changed ? "changed" : "unchanged");
- }
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
+ __PRETTY_FUNCTION__, ifp->name);
if (!changed) {
return;
@@ -382,7 +351,7 @@
if (!if_is_operative(ifp))
return;
- /* if (PIM_DEBUG_ZEBRA) */ {
+ if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(ifc->address, buf, BUFSIZ);
zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
@@ -501,7 +470,7 @@
ifp = ifc->ifp;
zassert(ifp);
- /* if (PIM_DEBUG_ZEBRA) */ {
+ if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(ifc->address, buf, BUFSIZ);
zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
@@ -1055,14 +1024,14 @@
return -4;
}
- {
+ if (PIM_DEBUG_IGMP_EVENTS) {
char group_str[100];
char source_str[100];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str, ifp->name);
+ __PRETTY_FUNCTION__,
+ source_str, group_str, ifp->name);
}
return 0;
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index e253a0e..e801f4e 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -103,9 +103,11 @@
enum pim_ifjoin_state old_state = ch->ifjoin_state;
if (old_state == new_state) {
- zlog_debug("%s calledby %s: non-transition on state %d (%s)",
- __PRETTY_FUNCTION__, caller, new_state,
- pim_ifchannel_ifjoin_name(new_state));
+ if (PIM_DEBUG_PIM_EVENTS) {
+ zlog_debug("%s calledby %s: non-transition on state %d (%s)",
+ __PRETTY_FUNCTION__, caller, new_state,
+ pim_ifchannel_ifjoin_name(new_state));
+ }
return;
}
@@ -286,7 +288,7 @@
if (ch->local_ifmembership == membership)
return;
- /* if (PIM_DEBUG_PIM_EVENTS) */ {
+ if (PIM_DEBUG_PIM_EVENTS) {
char src_str[100];
char grp_str[100];
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
diff --git a/pimd/pim_igmp_join.c b/pimd/pim_igmp_join.c
index b48adb7..62e32c6 100644
--- a/pimd/pim_igmp_join.c
+++ b/pimd/pim_igmp_join.c
@@ -47,18 +47,20 @@
struct in_addr source_addr)
{
struct group_source_req req;
- struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group;
- struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source;
+ struct sockaddr_in group;
+ struct sockaddr_in source;
- memset(group_sa, 0, sizeof(*group_sa));
- group_sa->sin_family = AF_INET;
- group_sa->sin_addr = group_addr;
- group_sa->sin_port = htons(0);
+ memset(&group, 0, sizeof(group));
+ group.sin_family = AF_INET;
+ group.sin_addr = group_addr;
+ group.sin_port = htons(0);
+ memcpy(&req.gsr_group, &group, sizeof(struct sockaddr_in));
- memset(source_sa, 0, sizeof(*source_sa));
- source_sa->sin_family = AF_INET;
- source_sa->sin_addr = source_addr;
- source_sa->sin_port = htons(0);
+ memset(&source, 0, sizeof(source));
+ source.sin_family = AF_INET;
+ source.sin_addr = source_addr;
+ source.sin_port = htons(0);
+ memcpy(&req.gsr_source, &source, sizeof(struct sockaddr_in));
req.gsr_interface = ifindex;
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 95c1816..5f4711e 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -205,7 +205,7 @@
/*
* Initialize zclient "update" and "lookup" sockets
*/
- pim_zebra_init(zebra_sock_path);
+ pim_zebra_init (master, zebra_sock_path);
zlog_notice("Loading configuration - begin");
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index 72a3538..8932dc3 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -125,7 +125,7 @@
/* DR changed ? */
if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
- /* if (PIM_DEBUG_PIM_EVENTS) */ {
+ if (PIM_DEBUG_PIM_EVENTS) {
char dr_old_str[100];
char dr_new_str[100];
pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index cd8a290..66fc59b 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -206,6 +206,20 @@
pim_version, pim_type, pim_msg_len, checksum);
}
+ if (pim_type == PIM_MSG_TYPE_REGISTER ||
+ pim_type == PIM_MSG_TYPE_REG_STOP ||
+ pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
+ pim_type == PIM_MSG_TYPE_GRAFT ||
+ pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
+ pim_type == PIM_MSG_TYPE_CANDIDATE)
+ {
+ if (PIM_DEBUG_PIM_PACKETS) {
+ zlog_debug("Recv PIM packet type %d which is not currently understood",
+ pim_type);
+ }
+ return -1;
+ }
+
if (pim_type == PIM_MSG_TYPE_HELLO) {
int result = pim_hello_recv(ifp,
ip_hdr->ip_src,
diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h
index 6be1a3e..4b378fb 100644
--- a/pimd/pim_pim.h
+++ b/pimd/pim_pim.h
@@ -41,8 +41,14 @@
#define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */
#define PIM_MSG_TYPE_HELLO (0)
+#define PIM_MSG_TYPE_REGISTER (1)
+#define PIM_MSG_TYPE_REG_STOP (2)
#define PIM_MSG_TYPE_JOIN_PRUNE (3)
+#define PIM_MSG_TYPE_BOOTSTRAP (4)
#define PIM_MSG_TYPE_ASSERT (5)
+#define PIM_MSG_TYPE_GRAFT (6)
+#define PIM_MSG_TYPE_GRAFT_ACK (7)
+#define PIM_MSG_TYPE_CANDIDATE (8)
#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg)
#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg)
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index dedc60a..38339da 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -61,7 +61,7 @@
if (num_ifindex > 1) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
+ zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
__FILE__, __PRETTY_FUNCTION__,
num_ifindex, addr_str, first_ifindex);
/* debug warning only, do not return */
@@ -136,22 +136,22 @@
}
rpf->rpf_addr = pim_rpf_find_rpf_addr(up);
- if (PIM_INADDR_IS_ANY(rpf->rpf_addr)) {
+ if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) {
/* RPF'(S,G) not found */
char src_str[100];
char grp_str[100];
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s %s: RPF'(%s,%s) not found: won't send join upstream",
- __FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str);
+ zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
+ __FILE__, __PRETTY_FUNCTION__,
+ src_str, grp_str);
/* warning only */
}
/* detect change in pim_nexthop */
if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
- /* if (PIM_DEBUG_PIM_EVENTS) */ {
+ if (PIM_DEBUG_PIM_EVENTS) {
char src_str[100];
char grp_str[100];
char nhaddr_str[100];
@@ -176,7 +176,7 @@
/* detect change in RPF_interface(S) */
if (save_nexthop.interface != rpf->source_nexthop.interface) {
- /* if (PIM_DEBUG_PIM_EVENTS) */ {
+ if (PIM_DEBUG_PIM_EVENTS) {
char src_str[100];
char grp_str[100];
pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c
index dcf4922..3549331 100644
--- a/pimd/pim_signals.c
+++ b/pimd/pim_signals.c
@@ -37,7 +37,7 @@
static void pim_sighup()
{
- zlog_debug ("SIGHUP received, ignoring");
+ zlog_info ("SIGHUP received, ignoring");
}
static void pim_sigint()
@@ -56,7 +56,7 @@
static void pim_sigusr1()
{
- zlog_debug ("SIGUSR1 received");
+ zlog_info ("SIGUSR1 received");
zlog_rotate (NULL);
}
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 512c0e6..810dbe8 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -157,18 +157,24 @@
}
/* IF ip igmp query-interval */
- vty_out(vty, " %s %d%s",
- PIM_CMD_IP_IGMP_QUERY_INTERVAL,
- pim_ifp->igmp_default_query_interval,
- VTY_NEWLINE);
- ++writes;
+ if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL)
+ {
+ vty_out(vty, " %s %d%s",
+ PIM_CMD_IP_IGMP_QUERY_INTERVAL,
+ pim_ifp->igmp_default_query_interval,
+ VTY_NEWLINE);
+ ++writes;
+ }
/* IF ip igmp query-max-response-time */
- vty_out(vty, " %s %d%s",
- PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC,
- pim_ifp->igmp_query_max_response_time_dsec,
- VTY_NEWLINE);
- ++writes;
+ if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC)
+ {
+ vty_out(vty, " %s %d%s",
+ PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC,
+ pim_ifp->igmp_query_max_response_time_dsec,
+ VTY_NEWLINE);
+ ++writes;
+ }
/* IF ip igmp join */
if (pim_ifp->igmp_join_list) {
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index dfc871b..3c739d2 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -150,8 +150,6 @@
if (!ifp)
return 0;
- zlog_info("INTERFACE UP: %s ifindex=%d", ifp->name, ifp->ifindex);
-
if (PIM_DEBUG_ZEBRA) {
zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
__PRETTY_FUNCTION__,
@@ -182,8 +180,6 @@
if (!ifp)
return 0;
- zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp->name, ifp->ifindex);
-
if (PIM_DEBUG_ZEBRA) {
zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
__PRETTY_FUNCTION__,
@@ -242,8 +238,6 @@
struct connected *c;
struct prefix *p;
- zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD);
-
/*
zebra api notifies address adds/dels events by using the same call
interface_add_read below, see comments in lib/zclient.c
@@ -278,17 +272,19 @@
struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
if (primary_addr.s_addr != p->u.prefix4.s_addr) {
- /* but we had a primary address already */
+ if (PIM_DEBUG_ZEBRA) {
+ /* but we had a primary address already */
- char buf[BUFSIZ];
- char old[100];
+ char buf[BUFSIZ];
+ char old[100];
- prefix2str(p, buf, BUFSIZ);
- pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
+ prefix2str(p, buf, BUFSIZ);
+ pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
- zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
- __PRETTY_FUNCTION__,
- c->ifp->name, old, buf);
+ zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
+ __PRETTY_FUNCTION__,
+ c->ifp->name, old, buf);
+ }
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
}
}
@@ -304,8 +300,6 @@
struct connected *c;
struct prefix *p;
- zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE);
-
/*
zebra api notifies address adds/dels events by using the same call
interface_add_read below, see comments in lib/zclient.c
@@ -655,7 +649,7 @@
zclient_send_requests(zclient, VRF_DEFAULT);
}
-void pim_zebra_init(char *zebra_sock_path)
+void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
{
int i;
@@ -669,7 +663,7 @@
#endif
/* Socket for receiving updates from Zebra daemon */
- qpim_zclient_update = zclient_new();
+ qpim_zclient_update = zclient_new (master);
qpim_zclient_update->zebra_connected = pim_zebra_connected;
qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
@@ -762,7 +756,7 @@
if (num_ifindex > 1) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
+ zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
__FILE__, __PRETTY_FUNCTION__,
num_ifindex, addr_str, first_ifindex);
/* debug warning only, do not return */
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index d624c86..af5baef 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -26,7 +26,7 @@
#include "pim_igmp.h"
#include "pim_ifchannel.h"
-void pim_zebra_init(char *zebra_sock_path);
+void pim_zebra_init (struct thread_master *master, char *zebra_sock_path);
void pim_scan_oil(void);
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index 67896d9..b5b219e 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -122,7 +122,7 @@
{
struct zclient *zlookup;
- zlookup = zclient_new();
+ zlookup = zclient_new (master);
if (!zlookup) {
zlog_err("%s: zclient_new() failure",
__PRETTY_FUNCTION__);
@@ -283,14 +283,14 @@
nexthop_tab[num_ifindex].ifindex = 0;
nexthop_tab[num_ifindex].protocol_distance = distance;
nexthop_tab[num_ifindex].route_metric = metric;
- {
+ if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char nexthop_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str));
- zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s",
- __FILE__, __PRETTY_FUNCTION__,
- nexthop_str, addr_str);
+ zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ nexthop_str, addr_str);
}
++num_ifindex;
break;
@@ -375,7 +375,7 @@
num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab,
PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr);
- if (num_ifindex < 1) {
+ if ((num_ifindex < 1) && PIM_DEBUG_ZEBRA) {
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
@@ -400,15 +400,15 @@
if (first_ifindex > 0) {
/* found: first ifindex is non-recursive nexthop */
- if (lookup > 0) {
+ if ((lookup > 0) && PIM_DEBUG_ZEBRA) {
/* Report non-recursive success after first lookup */
char addr_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
- __FILE__, __PRETTY_FUNCTION__,
- lookup, max_lookup, first_ifindex, addr_str,
- nexthop_tab[0].protocol_distance,
- nexthop_tab[0].route_metric);
+ zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
+ __FILE__, __PRETTY_FUNCTION__,
+ lookup, max_lookup, first_ifindex, addr_str,
+ nexthop_tab[0].protocol_distance,
+ nexthop_tab[0].route_metric);
/* use last address as nexthop address */
nexthop_tab[0].nexthop_addr = addr;
@@ -421,12 +421,12 @@
return num_ifindex;
}
- {
+ if (PIM_DEBUG_ZEBRA) {
char addr_str[100];
char nexthop_str[100];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
pim_inet4_dump("<nexthop?>", nexthop_addr, nexthop_str, sizeof(nexthop_str));
- zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
+ zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
__FILE__, __PRETTY_FUNCTION__,
lookup, max_lookup, nexthop_str, addr_str,
nexthop_tab[0].protocol_distance,
@@ -437,11 +437,13 @@
} /* for (max_lookup) */
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
- __FILE__, __PRETTY_FUNCTION__,
- lookup, max_lookup, addr_str);
+ if (PIM_DEBUG_ZEBRA) {
+ char addr_str[100];
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ lookup, max_lookup, addr_str);
+ }
return -2;
}
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
index 95b1f6d..4ead9b0 100644
--- a/ripd/rip_main.c
+++ b/ripd/rip_main.c
@@ -286,7 +286,7 @@
/* RIP related initialization. */
rip_init ();
rip_if_init ();
- rip_zclient_init ();
+ rip_zclient_init (master);
rip_peer_init ();
/* Get configuration file. */
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
index de98162..0b6c22a 100644
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -710,10 +710,10 @@
}
void
-rip_zclient_init ()
+rip_zclient_init (struct thread_master *master)
{
/* Set default value to the zebra client structure. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_RIP);
zclient->zebra_connected = rip_zebra_connected;
zclient->interface_add = rip_interface_add;
diff --git a/ripd/ripd.c b/ripd/ripd.c
index b42ca72..b708889 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -1168,7 +1168,8 @@
struct prefix_ipv4 ifaddr;
struct prefix_ipv4 ifaddrclass;
int subnetted;
-
+
+ memset(&ifaddr, 0, sizeof(ifaddr));
/* We don't know yet. */
subnetted = -1;
diff --git a/ripd/ripd.h b/ripd/ripd.h
index 4f40e79..a768ccc 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -389,7 +389,7 @@
extern void rip_route_map_init (void);
extern void rip_route_map_reset (void);
extern void rip_snmp_init (void);
-extern void rip_zclient_init (void);
+extern void rip_zclient_init (struct thread_master *);
extern void rip_zclient_start (void);
extern void rip_zclient_reset (void);
extern void rip_offset_init (void);
diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
index d8f2241..1c184e2 100644
--- a/ripngd/ripng_main.c
+++ b/ripngd/ripng_main.c
@@ -281,7 +281,7 @@
/* RIPngd inits. */
ripng_init ();
- zebra_init ();
+ zebra_init (master);
ripng_peer_init ();
/* Get configuration file. */
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index 58f8860..13b1853 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -541,10 +541,10 @@
/* Initialize zebra structure and it's commands. */
void
-zebra_init ()
+zebra_init (struct thread_master *master)
{
/* Allocate zebra structure. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_RIPNG);
zclient->zebra_connected = ripng_zebra_connected;
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
index 28ca41b..6cbbd84 100644
--- a/ripngd/ripngd.h
+++ b/ripngd/ripngd.h
@@ -358,7 +358,7 @@
extern void ripng_route_map_reset (void);
extern void ripng_terminate (void);
/* zclient_init() is done by ripng_zebra.c:zebra_init() */
-extern void zebra_init (void);
+extern void zebra_init (struct thread_master *);
extern void ripng_zclient_start (void);
extern void ripng_zclient_reset (void);
extern void ripng_offset_init (void);
diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c
index 3594753..ed54d9c 100644
--- a/tests/bgp_mpath_test.c
+++ b/tests/bgp_mpath_test.c
@@ -376,7 +376,7 @@
global_test_init (void)
{
master = thread_master_create ();
- zclient = zclient_new ();
+ zclient = zclient_new (master);
bgp_master_init ();
bgp_option_set (BGP_OPT_NO_LISTEN);
diff --git a/tests/test-stream.c b/tests/test-stream.c
index 5997b47..7ef6374 100644
--- a/tests/test-stream.c
+++ b/tests/test-stream.c
@@ -24,7 +24,7 @@
#include <stream.h>
#include <thread.h>
-static long int ham = 0xdeadbeefdeadbeef;
+static unsigned long long ham = 0xdeadbeefdeadbeef;
struct thread_master *master;
static void
@@ -32,7 +32,7 @@
{
size_t getp = stream_get_getp (s);
- printf ("endp: %ld, readable: %ld, writeable: %ld\n",
+ printf ("endp: %zu, readable: %zu, writeable: %zu\n",
stream_get_endp (s),
STREAM_READABLE (s),
STREAM_WRITEABLE (s));
@@ -70,7 +70,7 @@
printf ("c: 0x%hhx\n", stream_getc (s));
printf ("w: 0x%hx\n", stream_getw (s));
printf ("l: 0x%x\n", stream_getl (s));
- printf ("q: 0x%lx\n", stream_getq (s));
+ printf ("q: 0x%" PRIu64 "\n", stream_getq (s));
return 0;
}
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 91791e2..b55c671 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -251,14 +251,6 @@
}
}
-static void
-vtysh_exit_ripd_only (void)
-{
- if (ripd_client)
- vtysh_client_execute (ripd_client, "exit", stdout);
-}
-
-
void
vtysh_pager_init (void)
{
@@ -457,53 +449,11 @@
vtysh_config_from_file (struct vty *vty, FILE *fp)
{
int ret;
- vector vline;
struct cmd_element *cmd;
while (fgets (vty->buf, VTY_BUFSIZ, fp))
{
- if (vty->buf[0] == '!' || vty->buf[1] == '#')
- continue;
-
- vline = cmd_make_strvec (vty->buf);
-
- /* In case of comment line. */
- if (vline == NULL)
- continue;
-
- /* Execute configuration command : this is strict match. */
- ret = cmd_execute_command_strict (vline, vty, &cmd);
-
- /* Try again with setting node to CONFIG_NODE. */
- if (ret != CMD_SUCCESS
- && ret != CMD_SUCCESS_DAEMON
- && ret != CMD_WARNING)
- {
- if (vty->node == KEYCHAIN_KEY_NODE)
- {
- vty->node = KEYCHAIN_NODE;
- vtysh_exit_ripd_only ();
- ret = cmd_execute_command_strict (vline, vty, &cmd);
-
- if (ret != CMD_SUCCESS
- && ret != CMD_SUCCESS_DAEMON
- && ret != CMD_WARNING)
- {
- vtysh_exit_ripd_only ();
- vty->node = CONFIG_NODE;
- ret = cmd_execute_command_strict (vline, vty, &cmd);
- }
- }
- else
- {
- vtysh_execute ("end");
- vtysh_execute ("configure terminal");
- vty->node = CONFIG_NODE;
- ret = cmd_execute_command_strict (vline, vty, &cmd);
- }
- }
-
- cmd_free_strvec (vline);
+ ret = command_config_read_one_line (vty, &cmd, 1);
switch (ret)
{
@@ -1808,6 +1758,34 @@
return CMD_SUCCESS;
}
+DEFUN (vtysh_write_terminal_daemon,
+ vtysh_write_terminal_daemon_cmd,
+ "write terminal (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to terminal\n"
+ "For the zebra daemon\n"
+ "For the rip daemon\n"
+ "For the ripng daemon\n"
+ "For the ospf daemon\n"
+ "For the ospfv6 daemon\n"
+ "For the bgp daemon\n"
+ "For the isis daemon\n"
+ "For the babel daemon\n")
+{
+ unsigned int i;
+ int ret = CMD_SUCCESS;
+
+ for (i = 0; i < array_size(vtysh_client); i++)
+ {
+ if (strcmp(vtysh_client[i].name, argv[0]) == 0)
+ break;
+ }
+
+ ret = vtysh_client_execute(&vtysh_client[i], "show running-config\n", stdout);
+
+ return ret;
+}
+
DEFUN (vtysh_integrated_config,
vtysh_integrated_config_cmd,
"service integrated-vtysh-config",
@@ -1926,6 +1904,20 @@
SHOW_STR
"Current operating configuration\n")
+ALIAS (vtysh_write_terminal_daemon,
+ vtysh_show_running_config_daemon_cmd,
+ "show running-config (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)",
+ SHOW_STR
+ "Current operating configuration\n"
+ "For the zebra daemon\n"
+ "For the rip daemon\n"
+ "For the ripng daemon\n"
+ "For the ospf daemon\n"
+ "For the ospfv6 daemon\n"
+ "For the bgp daemon\n"
+ "For the isis daemon\n"
+ "For the babel daemon\n")
+
DEFUN (vtysh_terminal_length,
vtysh_terminal_length_cmd,
"terminal length <0-512>",
@@ -2447,12 +2439,14 @@
install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd);
install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd);
install_element (ENABLE_NODE, &vtysh_show_running_config_cmd);
+ install_element (ENABLE_NODE, &vtysh_show_running_config_daemon_cmd);
install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd);
install_element (ENABLE_NODE, &vtysh_write_file_cmd);
install_element (ENABLE_NODE, &vtysh_write_cmd);
/* "write terminal" command. */
install_element (ENABLE_NODE, &vtysh_write_terminal_cmd);
+ install_element (ENABLE_NODE, &vtysh_write_terminal_daemon_cmd);
install_element (CONFIG_NODE, &vtysh_integrated_config_cmd);
install_element (CONFIG_NODE, &no_vtysh_integrated_config_cmd);
diff --git a/zebra/client_main.c b/zebra/client_main.c
index 06afc56..43ab299 100644
--- a/zebra/client_main.c
+++ b/zebra/client_main.c
@@ -193,13 +193,15 @@
int
main (int argc, char **argv)
{
+ struct thread_master *master;
FILE *fp;
if (argc == 1)
usage_exit ();
+ master = thread_master_create ();
/* Establish connection to zebra. */
- zclient = zclient_new ();
+ zclient = zclient_new (master);
zclient->enable = 1;
#ifdef HAVE_TCP_ZEBRA
zclient->sock = zclient_socket ();