Merge quagga mainline into the google ISIS code.

The steps were:

  $ git checkout google-is-is
  $ git merge quagga
  $ git checkout google-is-is -- isisd

  # Resolve conflicts in the following:
  lib/md5.h
  zebra/rt_netlink.c
  zebra/zebra_rib.c
  zebra/zserv.c

Note that the content in the isisd directory is left unchanged in the
merge. As a result, changes made to isisd as part of the following
commits on the quagga mainline are dropped.

  # 8ced4e82 is the merge base, e96b3121 is the current quagga master
  $ git log --oneline --reverse 8ced4e82..e96b3121 -- isisd
  5574999 isisd: fix crash on "no router isis" (BZ#536)
  8998075 isisd: raise hello rate for DIS (BZ#539)
  306ca83 isisd: include hash.h, not hash.c
  b82cdeb delete CVS keywords
  2f65867 isisd: indent longopts array
  b511468 quagga: option "-z" ("--socket <path>") added
  05e54ee build: delete .cvsignore files
  b4e45f6 fix zebra protocol after MP-BGP changes
  7fd6cd8 isisd: fix circuit state machine
  907fd95 isisd: send proper LSP after DIS election
  d034aa0 isisd: fix wrong next-hops from SPF
  c25eaff isisd: unexpected kernel routing table (BZ#544)
  e6b03b7 isisd: implement MD5 circuit authentication
This commit is contained in:
Avneesh Sachdev 2012-04-11 23:51:08 -07:00
commit 14d2bbaa3f
212 changed files with 14303 additions and 3494 deletions

View File

@ -1,30 +0,0 @@
config.log
config.h
config.cache
config.status
config.guess
config.sub
ltmain.sh
stamp-h
stamp-h[0-9]*
*-stamp
Makefile
INSTALL
.deps
depcomp
missing
install-sh
autom4te*.cache
configure.lineno
configure
config.h.in
aclocal.m4
Makefile.in
zebra-[0-9.][0-9.][0-9.]*.tar.gz
quagga-[0-9.][0-9.][0-9.]*.tar.gz
quagga-[0-9.][0-9.][0-9.]*.tar.gz.asc
.nfs*
libtool
.arch-inventory
.arch-ids
{arch}

357
HACKING
View File

@ -1,357 +0,0 @@
-*- mode: text; -*-
$QuaggaId: Format:%an, %ai, %h$ $
Contents:
* GUIDELINES FOR HACKING ON QUAGGA
* COMPILE-TIME CONDITIONAL CODE
* COMMIT MESSAGE
* HACKING THE BUILD SYSTEM
* RELEASE PROCEDURE
* SHARED LIBRARY VERSIONING
* RELEASE PROCEDURE
* TOOL VERSIONS
* SHARED LIBRARY VERSIONING
* PATCH SUBMISSION
* PATCH APPLICATION
* STABLE PLATFORMS AND DAEMONS
* IMPORT OR UPDATE VENDOR SPECIFIC ROUTING PROTOCOLS
GUIDELINES FOR HACKING ON QUAGGA
[this is a draft in progress]
GNU coding standards apply. Indentation follows the result of
invoking GNU indent (as of 2.2.8a) with no arguments. Note that this
uses tabs instead of spaces where possible for leading whitespace, and
assumes that tabs are every 8 columns. Do not attempt to redefine the
location of tab stops. Note also that some indentation does not
follow GNU style. This is a historical accident, and we generally
only clean up whitespace when code is unmaintainable due to whitespace
issues, as fewer changes from zebra lead to easier merges.
For GNU emacs, use indentation style "gnu".
For Vim, use the following lines (note that tabs are at 8, and that
softtabstop sets the indentation level):
set tabstop=8
set softtabstop=2
set shiftwidth=2
set noexpandtab
Be particularly careful not to break platforms/protocols that you
cannot test.
New code should have good comments, and 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 for an example;
This placeholder string will be expanded out by the 'git archive' commands,
wihch 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:
lib/log.h logging levels and usage guidance
[more to be added]
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, ie:
/* Deprecated: 20050406 */
#if !defined(QUAGGA_NO_DEPRECATED_INTERFACES)
#warning "Using deprecated <libname> (interface(s)|function(s))"
...
#endif /* QUAGGA_NO_DEPRECATED_INTERFACES */
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. Deprecated commands should be excised in the next
unstable cycle. A list of deprecated commands should be collated for each
release.
See also below regarding SHARED LIBRARY VERSIONING.
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 gratuitious --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. 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 should 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.
* An optional introduction, discussing the general intent of the change.
* A short description of each change made, preferably:
* file by file
* function by function (use of "ditto", or globs is allowed)
to provide a short description of the general intent of the patch, in terms
of the problem it solves and how it achieves it, to help reviewers
understand.
The one-line summary must be limited to 54 characters, and all other
lines to 72 characters.
The reason for such itemised commit messages is to encourage the author to
self-review every line of the patch, as well as provide reviewers an index
of which changes are intended, along with a short description for each.
Some discretion is obviously required. A C-to-english description is not
desireable. For short patches, a per-function/file break-down may be
redundant. For longer patches, such a break-down may be essential.
An example (where the general discussion is obviously somewhat redundant,
given the one-line summary):
zebra: Enhance frob FSM to detect loss of frob
* (general) 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.
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 apppropriate 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:
git-clone git:///code.quagga.net/quagga.git quagga
git-archive --remote=git://code.quagga.net/quagga.git \
--prefix=quagga-release/ master | tar -xf -
cd quagga-release
autoreconf -i
./configure
make
make dist
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
[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 SUBSMISSION
The preferred method for changes is to provide git commits via a
publically-accessible git repository.
All content guidelines in PATCH SUBMISSION apply.
PATCH SUBMISSION
* 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 repostory.
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.
* 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
mailinglist.
* 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 ..'
* By committing a patch, you are responsible for fixing problems
resulting from it (or backing it out).
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) # without capabilities
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.

View File

@ -14,6 +14,11 @@ collected in his git repository.
* public git repositories
** git remote add quagga-re git://github.com/Quagga-RE/quagga-RE.git
Maintained by Denis Ovsienko, and geared towards producing a
production-ready branch of Quagga, in the Quagga-RE-stable branch.
** git remote add equinox git://git.spaceboyz.net/equinox/quagga.git/
This repository has topic branches for patches intended for inclusion

462
HACKING.tex Normal file
View File

@ -0,0 +1,462 @@
%% -*- 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 no arguments. Note that this
uses tabs instead of spaces where possible for leading whitespace, and
assumes that tabs are every 8 columns. Do not attempt to redefine the
location of tab stops. Note also that some indentation does not
follow GNU style. This is a historical accident, and we generally
only clean up whitespace when code is unmaintainable due to whitespace
issues, to minimise merging conflicts.
For GNU emacs, use indentation style ``gnu''.
For Vim, use the following lines (note that tabs are at 8, and that
softtabstop sets the indentation level):
set tabstop=8
set softtabstop=2
set shiftwidth=2
set noexpandtab
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,
wihch 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, ie:
\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{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 gratuitious --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 desireable - 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 apppropriate 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}
git-clone git:///code.quagga.net/quagga.git quagga
git-archive --remote=git://code.quagga.net/quagga.git \
--prefix=quagga-release/ master | tar -xf -
cd quagga-release
autoreconf -i
./configure
make
make dist
\end{verbatim}
\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
publically-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 contraversial and most
trivial are first, and the most complex or more contraversial 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
mailinglist.
\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}

View File

@ -1,5 +1,3 @@
# $Id$
--------------------------------------------------------------------------
Building and Installing Quagga from releases or snapshots:

View File

@ -1,10 +1,10 @@
## Process this file with automake to produce Makefile.in.
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \
@ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
redhat @SOLARIS@
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \
isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
solaris
@ -14,4 +14,14 @@ EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \
tools/mrlg.cgi tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \
tools/zebra.el tools/multiple-bgpd.sh
if HAVE_LATEX
HACKING.pdf: HACKING.tex
$(LATEXMK) -pdf $<
clean-local:
-$(LATEXMK) -C HACKING.tex
endif
ACLOCAL_AMFLAGS = -I m4

7
babeld/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*
!*.c
!*.h
!LICENCE
!Makefile.am
!babeld.conf.sample
!.gitignore

36
babeld/LICENCE Normal file
View File

@ -0,0 +1,36 @@
Code in this directory is made available under the following licence:
---------------------------------------------------------------------------
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------
The code also makes calls to and links with the "libzebra" code of Quagga,
in the lib/ directory of this project, which is subject to the GPL licence
as given in the top-level COPYING file included with Quagga.
Contributors to the code in babeld/ are asked to make their work available
under the same MIT/X11 licence as given immediately above. Please indicate
your assent to this by updating this file and appending the appropriate
Copyright <year> <Author name>, <author contact details>
line to the existing copyright assertion lines in the MIT/X11 licence text
above in this file.

29
babeld/Makefile.am Normal file
View File

@ -0,0 +1,29 @@
## Process this file with automake to produce Makefile.in.
INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
INSTALL_SDATA=@INSTALL@ -m 600
AM_CFLAGS = $(PICFLAGS)
AM_LDFLAGS = $(PILDFLAGS)
noinst_LIBRARIES = libbabel.a
sbin_PROGRAMS = babeld
libbabel_a_SOURCES = \
babel_zebra.c net.c kernel.c util.c source.c neighbour.c \
route.c xroute.c message.c resend.c babel_interface.c babeld.c \
babel_filter.c
noinst_HEADERS = \
babel_zebra.h net.h kernel.h util.h source.h neighbour.h \
route.h xroute.h message.h resend.h babel_interface.h babeld.h \
babel_filter.h
babeld_SOURCES = \
babel_main.c $(libbabel_a_SOURCES)
babeld_LDADD = ../lib/libzebra.la @LIBCAP@
examplesdir = $(exampledir)
dist_examples_DATA = babeld.conf.sample

124
babeld/babel_filter.c Normal file
View File

@ -0,0 +1,124 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "babel_filter.h"
#include "vty.h"
#include "filter.h"
#include "log.h"
#include "plist.h"
#include "distribute.h"
#include "util.h"
int
babel_filter(int output, const unsigned char *prefix, unsigned short plen,
unsigned int ifindex)
{
struct interface *ifp = if_lookup_by_index(ifindex);
babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL;
struct prefix p;
struct distribute *dist;
struct access_list *alist;
struct prefix_list *plist;
int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN;
int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN;
p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
p.prefixlen = v4mapped(prefix) ? plen - 96 : plen;
if (p.family == AF_INET)
uchar_to_inaddr(&p.u.prefix4, prefix);
else
uchar_to_in6addr(&p.u.prefix6, prefix);
if (babel_ifp != NULL && babel_ifp->list[filter]) {
if (access_list_apply (babel_ifp->list[filter], &p)
== FILTER_DENY) {
debugf(BABEL_DEBUG_FILTER,
"%s/%d filtered by distribute in",
p.family == AF_INET ?
inet_ntoa(p.u.prefix4) :
inet6_ntoa (p.u.prefix6),
p.prefixlen);
return INFINITY;
}
}
if (babel_ifp != NULL && babel_ifp->prefix[filter]) {
if (prefix_list_apply (babel_ifp->prefix[filter], &p)
== PREFIX_DENY) {
debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
p.family == AF_INET ?
inet_ntoa(p.u.prefix4) :
inet6_ntoa (p.u.prefix6),
p.prefixlen);
return INFINITY;
}
}
/* All interface filter check. */
dist = distribute_lookup (NULL);
if (dist) {
if (dist->list[distribute]) {
alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
if (alist) {
if (access_list_apply (alist, &p) == FILTER_DENY) {
debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
p.family == AF_INET ?
inet_ntoa(p.u.prefix4) :
inet6_ntoa (p.u.prefix6),
p.prefixlen);
return INFINITY;
}
}
}
if (dist->prefix[distribute]) {
plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
if (plist) {
if (prefix_list_apply (plist, &p) == PREFIX_DENY) {
debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
p.family == AF_INET ?
inet_ntoa(p.u.prefix4) :
inet6_ntoa (p.u.prefix6),
p.prefixlen);
return INFINITY;
}
}
}
}
return 0;
}

49
babeld/babel_filter.h Normal file
View File

@ -0,0 +1,49 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABELD_BABEL_FILTER_H
#define BABELD_BABEL_FILTER_H
#include <zebra.h>
#include "prefix.h"
#include "babel_interface.h"
int babel_filter(int output, const unsigned char *prefix, unsigned short plen,
unsigned int index);
#endif /* BABELD_BABEL_FILTER_H */

1022
babeld/babel_interface.c Normal file

File diff suppressed because it is too large Load Diff

152
babeld/babel_interface.h Normal file
View File

@ -0,0 +1,152 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_INTERFACE_H
#define BABEL_INTERFACE_H
#include <zebra.h>
#include "zclient.h"
#include "vty.h"
#define CONFIG_DEFAULT 0
#define CONFIG_NO 1
#define CONFIG_YES 2
/* babeld interface informations */
struct babel_interface {
unsigned short flags; /* see below */
unsigned short cost;
int channel;
struct timeval hello_timeout;
struct timeval update_timeout;
struct timeval flush_timeout;
struct timeval update_flush_timeout;
unsigned char *ipv4;
int buffered;
int bufsize;
char have_buffered_hello;
char have_buffered_id;
char have_buffered_nh;
char have_buffered_prefix;
unsigned char buffered_id[16];
unsigned char buffered_nh[4];
unsigned char buffered_prefix[16];
unsigned char *sendbuf;
struct buffered_update *buffered_updates;
int num_buffered_updates;
int update_bufsize;
time_t bucket_time;
unsigned int bucket;
time_t last_update_time;
unsigned short hello_seqno;
unsigned hello_interval;
unsigned update_interval;
/* For filter type slot. */
#define BABEL_FILTER_IN 0
#define BABEL_FILTER_OUT 1
#define BABEL_FILTER_MAX 2
struct access_list *list[BABEL_FILTER_MAX]; /* Access-list. */
struct prefix_list *prefix[BABEL_FILTER_MAX]; /* Prefix-list. */
};
typedef struct babel_interface babel_interface_nfo;
static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp)
{
return ((babel_interface_nfo*) ifp->info);
}
/* babel_interface_nfo flags */
#define BABEL_IF_IS_UP (1 << 0)
#define BABEL_IF_WIRED (1 << 1)
#define BABEL_IF_SPLIT_HORIZON (1 << 2)
#define BABEL_IF_LQ (1 << 3)
#define BABEL_IF_FARAWAY (1 << 4)
/* Only INTERFERING can appear on the wire. */
#define BABEL_IF_CHANNEL_UNKNOWN 0
#define BABEL_IF_CHANNEL_INTERFERING 255
#define BABEL_IF_CHANNEL_NONINTERFERING -2
static inline int
if_up(struct interface *ifp)
{
return (if_is_operative(ifp) &&
ifp->connected != NULL &&
(babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP));
}
/* types:
struct interface _ifp, struct listnode node */
#define FOR_ALL_INTERFACES(_ifp, _node) \
for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp))
/* types:
struct interface *ifp, struct connected *_connected, struct listnode *node */
#define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node) \
for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected))
struct buffered_update {
unsigned char id[8];
unsigned char prefix[16];
unsigned char plen;
unsigned char pad[3];
};
/* init function */
void babel_if_init(void);
/* Callback functions for zebra client */
int babel_interface_up (int, struct zclient *, zebra_size_t);
int babel_interface_down (int, struct zclient *, zebra_size_t);
int babel_interface_add (int, struct zclient *, zebra_size_t);
int babel_interface_delete (int, struct zclient *, zebra_size_t);
int babel_interface_address_add (int, struct zclient *, zebra_size_t);
int babel_interface_address_delete (int, struct zclient *, zebra_size_t);
unsigned jitter(babel_interface_nfo *, int);
unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent);
/* return "true" if "address" is one of our ipv6 addresses */
int is_interface_ll_address(struct interface *ifp, const unsigned char *address);
/* Send retraction to all, and reset all interfaces statistics. */
void babel_interface_close_all(void);
extern int babel_enable_if_config_write (struct vty *);
#endif

532
babeld/babel_main.c Normal file
View File

@ -0,0 +1,532 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* include zebra library */
#include <zebra.h>
#include "getopt.h"
#include "if.h"
#include "log.h"
#include "thread.h"
#include "privs.h"
#include "sigevent.h"
#include "version.h"
#include "command.h"
#include "vty.h"
#include "memory.h"
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "kernel.h"
#include "babel_interface.h"
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
#include "resend.h"
#include "babel_zebra.h"
static void babel_init (int argc, char **argv);
static char *babel_get_progname(char *argv_0);
static void babel_fail(void);
static void babel_init_random(void);
static void babel_replace_by_null(int fd);
static void babel_init_signals(void);
static void babel_exit_properly(void);
static void babel_save_state_file(void);
struct thread_master *master; /* quagga's threads handler */
struct timeval babel_now; /* current time */
unsigned char myid[8]; /* unique id (mac address of an interface) */
int debug = 0;
int resend_delay = -1;
static const char *pidfile = PATH_BABELD_PID;
const unsigned char zeroes[16] = {0};
const unsigned char ones[16] =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static const char *state_file = DAEMON_VTY_DIR "/babel-state";
unsigned char protocol_group[16]; /* babel's link-local multicast address */
int protocol_port; /* babel's port */
int protocol_socket = -1; /* socket: communicate with others babeld */
static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
static char *babel_config_file = NULL;
static char *babel_vty_addr = NULL;
static int babel_vty_port = BABEL_VTY_PORT;
/* Babeld options. */
struct option longopts[] =
{
{ "daemon", no_argument, NULL, 'd'},
{ "config_file", required_argument, NULL, 'f'},
{ "pid_file", required_argument, NULL, 'i'},
{ "socket", required_argument, NULL, 'z'},
{ "help", no_argument, NULL, 'h'},
{ "vty_addr", required_argument, NULL, 'A'},
{ "vty_port", required_argument, NULL, 'P'},
{ "user", required_argument, NULL, 'u'},
{ "group", required_argument, NULL, 'g'},
{ "version", no_argument, NULL, 'v'},
{ 0 }
};
/* babeld privileges */
static zebra_capabilities_t _caps_p [] =
{
ZCAP_NET_RAW,
ZCAP_BIND
};
static struct zebra_privs_t babeld_privs =
{
#if defined(QUAGGA_USER)
.user = QUAGGA_USER,
#endif
#if defined QUAGGA_GROUP
.group = QUAGGA_GROUP,
#endif
#ifdef VTY_GROUP
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = 2,
.cap_num_i = 0
};
int
main(int argc, char **argv)
{
struct thread thread;
/* and print banner too */
babel_init(argc, argv);
while (thread_fetch (master, &thread)) {
thread_call (&thread);
}
return 0;
}
static void
babel_usage (char *progname, int status)
{
if (status != 0)
fprintf (stderr, "Try `%s --help' for more information.\n", progname);
else
{
printf ("Usage : %s [OPTION...]\n\
Daemon which manages Babel routing protocol.\n\n\
-d, --daemon Runs in daemon mode\n\
-f, --config_file Set configuration file name\n\
-i, --pid_file Set process identifier file name\n\
-z, --socket Set path of zebra socket\n\
-A, --vty_addr Set vty's bind address\n\
-P, --vty_port Set vty's port number\n\
-u, --user User to run as\n\
-g, --group Group to run as\n\
-v, --version Print program version\n\
-h, --help Display this help and exit\n\
\n\
Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
}
exit (status);
}
/* make initialisations witch don't need infos about kernel(interfaces, etc.) */
static void
babel_init(int argc, char **argv)
{
int rc, opt;
int do_daemonise = 0;
char *progname = NULL;
/* Set umask before anything for security */
umask (0027);
progname = babel_get_progname(argv[0]);
/* set default log (lib/log.h) */
zlog_default = openzlog(progname, ZLOG_BABEL,
LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
/* set log destination as stdout until the config file is read */
zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING);
babel_init_random();
/* set the Babel's default link-local multicast address and Babel's port */
parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
protocol_port = 6696;
/* get options */
while(1) {
opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
if(opt < 0)
break;
switch(opt) {
case 0:
break;
case 'd':
do_daemonise = -1;
break;
case 'f':
babel_config_file = optarg;
break;
case 'i':
pidfile = optarg;
break;
case 'z':
zclient_serv_path_set (optarg);
break;
case 'A':
babel_vty_addr = optarg;
break;
case 'P':
babel_vty_port = atoi (optarg);
if (babel_vty_port <= 0 || babel_vty_port > 0xffff)
babel_vty_port = BABEL_VTY_PORT;
break;
case 'u':
babeld_privs.user = optarg;
break;
case 'g':
babeld_privs.group = optarg;
break;
case 'v':
print_version (progname);
exit (0);
break;
case 'h':
babel_usage (progname, 0);
break;
default:
babel_usage (progname, 1);
break;
}
}
/* create the threads handler */
master = thread_master_create ();
/* Library inits. */
zprivs_init (&babeld_privs);
babel_init_signals();
cmd_init (1);
vty_init (master);
memory_init ();
resend_delay = BABEL_DEFAULT_RESEND_DELAY;
babel_replace_by_null(STDIN_FILENO);
if (do_daemonise && daemonise() < 0) {
zlog_err("daemonise: %s", safe_strerror(errno));
exit (1);
}
/* write pid file */
if (pid_output(pidfile) < 0) {
zlog_err("error while writing pidfile");
exit (1);
};
/* init some quagga's dependencies, and babeld's commands */
babeld_quagga_init();
/* init zebra client's structure and it's commands */
/* this replace kernel_setup && kernel_setup_socket */
babelz_zebra_init ();
/* Sort all installed commands. */
sort_node ();
/* Get zebra configuration file. */
zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
vty_read_config (babel_config_file, babel_config_default);
/* Create VTY socket */
vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH);
/* init buffer */
rc = resize_receive_buffer(1500);
if(rc < 0)
babel_fail();
schedule_neighbours_check(5000, 1);
zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
}
/* return the progname (without path, example: "./x/progname" --> "progname") */
static char *
babel_get_progname(char *argv_0) {
char *p = strrchr (argv_0, '/');
return (p ? ++p : argv_0);
}
static void
babel_fail(void)
{
exit(1);
}
/* initialize random value, and set 'babel_now' by the way. */
static void
babel_init_random(void)
{
gettime(&babel_now);
int rc;
unsigned int seed;
rc = read_random_bytes(&seed, sizeof(seed));
if(rc < 0) {
zlog_err("read(random): %s", safe_strerror(errno));
seed = 42;
}
seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
srandom(seed);
}
/*
close fd, and replace it by "/dev/null"
exit if error
*/
static void
babel_replace_by_null(int fd)
{
int fd_null;
int rc;
fd_null = open("/dev/null", O_RDONLY);
if(fd_null < 0) {
zlog_err("open(null): %s", safe_strerror(errno));
exit(1);
}
rc = dup2(fd_null, fd);
if(rc < 0) {
zlog_err("dup2(null, 0): %s", safe_strerror(errno));
exit(1);
}
close(fd_null);
}
/*
Load the state file: check last babeld's running state, usefull in case of
"/etc/init.d/babeld restart"
*/
void
babel_load_state_file(void)
{
int fd;
int rc;
fd = open(state_file, O_RDONLY);
if(fd < 0 && errno != ENOENT)
zlog_err("open(babel-state: %s)", safe_strerror(errno));
rc = unlink(state_file);
if(fd >= 0 && rc < 0) {
zlog_err("unlink(babel-state): %s", safe_strerror(errno));
/* If we couldn't unlink it, it's probably stale. */
close(fd);
fd = -1;
}
if(fd >= 0) {
char buf[100];
char buf2[100];
int s;
long t;
rc = read(fd, buf, 99);
if(rc < 0) {
zlog_err("read(babel-state): %s", safe_strerror(errno));
} else {
buf[rc] = '\0';
rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
if(rc == 3 && s >= 0 && s <= 0xFFFF) {
unsigned char sid[8];
rc = parse_eui64(buf2, sid);
if(rc < 0) {
zlog_err("Couldn't parse babel-state.");
} else {
struct timeval realnow;
debugf(BABEL_DEBUG_COMMON,
"Got %s %d %ld from babel-state.",
format_eui64(sid), s, t);
gettimeofday(&realnow, NULL);
if(memcmp(sid, myid, 8) == 0)
myseqno = seqno_plus(s, 1);
else
zlog_err("ID mismatch in babel-state. id=%s; old=%s",
format_eui64(myid),
format_eui64(sid));
}
} else {
zlog_err("Couldn't parse babel-state.");
}
}
close(fd);
fd = -1;
}
}
static void
babel_sigexit(void)
{
zlog_notice("Terminating on signal");
babel_exit_properly();
}
static void
babel_sigusr1 (void)
{
zlog_rotate (NULL);
}
static void
babel_init_signals(void)
{
static struct quagga_signal_t babel_signals[] =
{
{
.signal = SIGUSR1,
.handler = &babel_sigusr1,
},
{
.signal = SIGINT,
.handler = &babel_sigexit,
},
{
.signal = SIGTERM,
.handler = &babel_sigexit,
},
};
signal_init (master, Q_SIGC(babel_signals), babel_signals);
}
static void
babel_exit_properly(void)
{
debugf(BABEL_DEBUG_COMMON, "Exiting...");
usleep(roughly(10000));
gettime(&babel_now);
/* Uninstall and flush all routes. */
debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
flush_all_routes();
babel_interface_close_all();
babel_zebra_close_connexion();
babel_save_state_file();
debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
if(pidfile)
unlink(pidfile);
debugf(BABEL_DEBUG_COMMON, "Done.");
exit(0);
}
static void
babel_save_state_file(void)
{
int fd;
int rc;
debugf(BABEL_DEBUG_COMMON, "Save state file.");
fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
if(fd < 0) {
zlog_err("creat(babel-state): %s", safe_strerror(errno));
unlink(state_file);
} else {
struct timeval realnow;
char buf[100];
gettimeofday(&realnow, NULL);
rc = snprintf(buf, 100, "%s %d %ld\n",
format_eui64(myid), (int)myseqno,
(long)realnow.tv_sec);
if(rc < 0 || rc >= 100) {
zlog_err("write(babel-state): overflow.");
unlink(state_file);
} else {
rc = write(fd, buf, rc);
if(rc < 0) {
zlog_err("write(babel-state): %s", safe_strerror(errno));
unlink(state_file);
}
fsync(fd);
}
close(fd);
}
}
void
show_babel_main_configuration (struct vty *vty)
{
vty_out(vty,
"pid file = %s%s"
"state file = %s%s"
"configuration file = %s%s"
"protocol informations:%s"
" multicast address = %s%s"
" port = %d%s"
"vty address = %s%s"
"vty port = %d%s"
"id = %s%s"
"allow_duplicates = %s%s"
"kernel_metric = %d%s",
pidfile, VTY_NEWLINE,
state_file, VTY_NEWLINE,
babel_config_file ? babel_config_file : babel_config_default,
VTY_NEWLINE,
VTY_NEWLINE,
format_address(protocol_group), VTY_NEWLINE,
protocol_port, VTY_NEWLINE,
babel_vty_addr ? babel_vty_addr : "None",
VTY_NEWLINE,
babel_vty_port, VTY_NEWLINE,
format_eui64(myid), VTY_NEWLINE,
format_bool(allow_duplicates), VTY_NEWLINE,
kernel_metric, VTY_NEWLINE);
}

57
babeld/babel_main.h Normal file
View File

@ -0,0 +1,57 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "vty.h"
extern struct timeval babel_now; /* current time */
extern struct thread_master *master; /* quagga's threads handler */
extern int debug;
extern int resend_delay;
extern unsigned char myid[8];
extern const unsigned char zeroes[16], ones[16];
extern int protocol_port;
extern unsigned char protocol_group[16];
extern int protocol_socket;
extern int kernel_socket;
extern int max_request_hopcount;
void babel_load_state_file(void);
void show_babel_main_configuration (struct vty *vty);

378
babeld/babel_zebra.c Normal file
View File

@ -0,0 +1,378 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* quagga's includes */
#include <zebra.h>
#include "command.h"
#include "zclient.h"
#include "stream.h"
/* babel's includes*/
#include "babel_zebra.h"
#include "babel_interface.h"
#include "xroute.h"
#include "util.h"
void babelz_zebra_init(void);
/* we must use a pointer because of zclient.c's functions (new, free). */
struct zclient *zclient;
static int zebra_config_write (struct vty *vty);
/* Debug types */
static struct {
int type;
int str_min_len;
const char *str;
} debug_type[] = {
{BABEL_DEBUG_COMMON, 1, "common"},
{BABEL_DEBUG_KERNEL, 1, "kernel"},
{BABEL_DEBUG_FILTER, 1, "filter"},
{BABEL_DEBUG_TIMEOUT, 1, "timeout"},
{BABEL_DEBUG_IF, 1, "interface"},
{BABEL_DEBUG_ROUTE, 1, "route"},
{BABEL_DEBUG_ALL, 1, "all"},
{0, 0, NULL}
};
/* Zebra node structure. */
struct cmd_node zebra_node =
{
ZEBRA_NODE,
"%s(config-router)# ",
1 /* vtysh? yes */
};
/* Zebra route add and delete treatment (ipv6). */
static int
babel_zebra_read_ipv6 (int command, struct zclient *zclient,
zebra_size_t length)
{
struct stream *s;
struct zapi_ipv6 api;
unsigned long ifindex = -1;
struct in6_addr nexthop;
struct prefix_ipv6 prefix;
s = zclient->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in6_addr));
memset (&api, 0, sizeof(struct zapi_ipv6));
memset (&prefix, 0, sizeof (struct prefix_ipv6));
/* Type, flags, message. */
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
/* IPv6 prefix. */
prefix.family = AF_INET6;
prefix.prefixlen = stream_getc (s);
stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc (s);
stream_get (&nexthop, s, sizeof(nexthop));
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
if (command == ZEBRA_IPV6_ROUTE_ADD)
babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop);
else
babel_ipv6_route_delete(&api, &prefix, ifindex);
return 0;
}
static int
babel_zebra_read_ipv4 (int command, struct zclient *zclient,
zebra_size_t length)
{
struct stream *s;
struct zapi_ipv4 api;
unsigned long ifindex = -1;
struct in_addr nexthop;
struct prefix_ipv4 prefix;
s = zclient->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in_addr));
memset (&api, 0, sizeof(struct zapi_ipv4));
memset (&prefix, 0, sizeof (struct prefix_ipv4));
/* Type, flags, message. */
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
/* IPv6 prefix. */
prefix.family = AF_INET;
prefix.prefixlen = stream_getc (s);
stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc (s);
stream_get (&nexthop, s, sizeof(nexthop));
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
if (command == ZEBRA_IPV6_ROUTE_ADD) {
babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop);
} else {
babel_ipv4_route_delete(&api, &prefix, ifindex);
}
return 0;
}
/* [Babel Command] */
DEFUN (babel_redistribute_type,
babel_redistribute_type_cmd,
"redistribute " QUAGGA_REDIST_STR_BABELD,
"Redistribute\n"
QUAGGA_REDIST_HELP_STR_BABELD)
{
int type;
type = proto_redistnum(AFI_IP6, argv[0]);
if (type < 0)
type = proto_redistnum(AFI_IP, argv[0]);
if (type < 0) {
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
return CMD_SUCCESS;
}
/* [Babel Command] */
DEFUN (no_babel_redistribute_type,
no_babel_redistribute_type_cmd,
"no redistribute " QUAGGA_REDIST_STR_BABELD,
NO_STR
"Redistribute\n"
QUAGGA_REDIST_HELP_STR_BABELD)
{
int type;
type = proto_redistnum(AFI_IP6, argv[0]);
if (type < 0)
type = proto_redistnum(AFI_IP, argv[0]);
if (type < 0) {
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
/* perhaps should we remove xroutes having the same type... */
return CMD_SUCCESS;
}
#ifndef NO_DEBUG
/* [Babel Command] */
DEFUN (debug_babel,
debug_babel_cmd,
"debug babel (common|kernel|filter|timeout|interface|route|all)",
"Enable debug messages for specific or all part.\n"
"Babel information\n"
"Common messages (default)\n"
"Kernel messages\n"
"Filter messages\n"
"Timeout messages\n"
"Interface messages\n"
"Route messages\n"
"All messages\n")
{
int i;
for(i = 0; debug_type[i].str != NULL; i++) {
if (strncmp (debug_type[i].str, argv[0],
debug_type[i].str_min_len) == 0) {
debug |= debug_type[i].type;
return CMD_SUCCESS;
}
}
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
/* [Babel Command] */
DEFUN (no_debug_babel,
no_debug_babel_cmd,
"no debug babel (common|kernel|filter|timeout|interface|route|all)",
NO_STR
"Disable debug messages for specific or all part.\n"
"Babel information\n"
"Common messages (default)\n"
"Kernel messages\n"
"Filter messages\n"
"Timeout messages\n"
"Interface messages\n"
"Route messages\n"
"All messages\n")
{
int i;
for (i = 0; debug_type[i].str; i++) {
if (strncmp(debug_type[i].str, argv[0],
debug_type[i].str_min_len) == 0) {
debug &= ~debug_type[i].type;
return CMD_SUCCESS;
}
}
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
#endif /* NO_DEBUG */
/* Output "debug" statement lines, if necessary. */
int
debug_babel_config_write (struct vty * vty)
{
#ifdef NO_DEBUG
return 0;
#else
int i, lines = 0;
if (debug == BABEL_DEBUG_ALL)
{
vty_out (vty, "debug babel all%s", VTY_NEWLINE);
lines++;
}
else
for (i = 0; debug_type[i].str != NULL; i++)
if
(
debug_type[i].type != BABEL_DEBUG_ALL
&& CHECK_FLAG (debug, debug_type[i].type)
)
{
vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE);
lines++;
}
if (lines)
{
vty_out (vty, "!%s", VTY_NEWLINE);
lines++;
}
return lines;
#endif /* NO_DEBUG */
}
void babelz_zebra_init(void)
{
zclient = zclient_new();
zclient_init(zclient, ZEBRA_ROUTE_BABEL);
zclient->interface_add = babel_interface_add;
zclient->interface_delete = babel_interface_delete;
zclient->interface_up = babel_interface_up;
zclient->interface_down = babel_interface_down;
zclient->interface_address_add = babel_interface_address_add;
zclient->interface_address_delete = babel_interface_address_delete;
zclient->ipv4_route_add = babel_zebra_read_ipv4;
zclient->ipv4_route_delete = babel_zebra_read_ipv4;
zclient->ipv6_route_add = babel_zebra_read_ipv6;
zclient->ipv6_route_delete = babel_zebra_read_ipv6;
install_node (&zebra_node, zebra_config_write);
install_element(BABEL_NODE, &babel_redistribute_type_cmd);
install_element(BABEL_NODE, &no_babel_redistribute_type_cmd);
install_element(ENABLE_NODE, &debug_babel_cmd);
install_element(ENABLE_NODE, &no_debug_babel_cmd);
install_element(CONFIG_NODE, &debug_babel_cmd);
install_element(CONFIG_NODE, &no_debug_babel_cmd);
}
static int
zebra_config_write (struct vty *vty)
{
if (! zclient->enable)
{
vty_out (vty, "no router zebra%s", VTY_NEWLINE);
return 1;
}
else if (! zclient->redist[ZEBRA_ROUTE_BABEL])
{
vty_out (vty, "router zebra%s", VTY_NEWLINE);
vty_out (vty, " no redistribute babel%s", VTY_NEWLINE);
return 1;
}
return 0;
}
void
babel_zebra_close_connexion(void)
{
zclient_stop(zclient);
}

50
babeld/babel_zebra.h Normal file
View File

@ -0,0 +1,50 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_ZEBRA_H
#define BABEL_ZEBRA_H
#include "vty.h"
extern struct zclient *zclient;
void babelz_zebra_init(void);
void babel_zebra_close_connexion(void);
extern int debug_babel_config_write (struct vty *);
#endif

728
babeld/babeld.c Normal file
View File

@ -0,0 +1,728 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <zebra.h>
#include "command.h"
#include "prefix.h"
#include "memory.h"
#include "memtypes.h"
#include "table.h"
#include "distribute.h"
#include "prefix.h"
#include "filter.h"
#include "plist.h"
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "net.h"
#include "kernel.h"
#include "babel_interface.h"
#include "neighbour.h"
#include "route.h"
#include "message.h"
#include "resend.h"
#include "babel_filter.h"
#include "babel_zebra.h"
static int babel_init_routing_process(struct thread *thread);
static void babel_get_myid(void);
static void babel_initial_noise(void);
static int babel_read_protocol (struct thread *thread);
static int babel_main_loop(struct thread *thread);
static void babel_set_timer(struct timeval *timeout);
static void babel_fill_with_next_timeout(struct timeval *tv);
/* Informations relative to the babel running daemon. */
static struct babel *babel_routing_process = NULL;
static unsigned char *receive_buffer = NULL;
static int receive_buffer_size = 0;
/* timeouts */
struct timeval check_neighbours_timeout;
static time_t expiry_time;
static time_t source_expiry_time;
/* Babel node structure. */
static struct cmd_node cmd_babel_node =
{
.node = BABEL_NODE,
.prompt = "%s(config-router)# ",
.vtysh = 1,
};
/* print current babel configuration on vty */
static int
babel_config_write (struct vty *vty)
{
int lines = 0;
int i;
/* list enabled debug modes */
lines += debug_babel_config_write (vty);
if (!babel_routing_process)
return lines;
vty_out (vty, "router babel%s", VTY_NEWLINE);
if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
{
vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE);
lines++;
}
/* list enabled interfaces */
lines = 1 + babel_enable_if_config_write (vty);
/* list redistributed protocols */
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != zclient->redist_default && zclient->redist[i])
{
vty_out (vty, " redistribute %s%s", zebra_route_string (i), VTY_NEWLINE);
lines++;
}
return lines;
}
static int
babel_create_routing_process (void)
{
assert (babel_routing_process == NULL);
/* Allocaste Babel instance. */
babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel));
/* Initialize timeouts */
gettime(&babel_now);
expiry_time = babel_now.tv_sec + roughly(30);
source_expiry_time = babel_now.tv_sec + roughly(300);
/* Make socket for Babel protocol. */
protocol_socket = babel_socket(protocol_port);
if (protocol_socket < 0) {
zlog_err("Couldn't create link local socket: %s", safe_strerror(errno));
goto fail;
}
/* Threads. */
babel_routing_process->t_read =
thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
/* wait a little: zebra will announce interfaces, addresses, routes... */
babel_routing_process->t_update =
thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L);
return 0;
fail:
XFREE(MTYPE_BABEL, babel_routing_process);
babel_routing_process = NULL;
return -1;
}
/* thread reading entries form others babel daemons */
static int
babel_read_protocol (struct thread *thread)
{
int rc;
struct interface *ifp = NULL;
struct sockaddr_in6 sin6;
struct listnode *linklist_node = NULL;
assert(babel_routing_process != NULL);
assert(protocol_socket >= 0);
rc = babel_recv(protocol_socket,
receive_buffer, receive_buffer_size,
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0) {
if(errno != EAGAIN && errno != EINTR) {
zlog_err("recv: %s", safe_strerror(errno));
}
} else {
FOR_ALL_INTERFACES(ifp, linklist_node) {
if(!if_up(ifp))
continue;
if(ifp->ifindex == sin6.sin6_scope_id) {
parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
receive_buffer, rc);
break;
}
}
}
/* re-add thread */
babel_routing_process->t_read =
thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
return 0;
}
/* Zebra will give some information, especially about interfaces. This function
must be call with a litte timeout wich may give zebra the time to do his job,
making these inits have sense. */
static int
babel_init_routing_process(struct thread *thread)
{
myseqno = (random() & 0xFFFF);
babel_get_myid();
babel_load_state_file();
debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
babel_initial_noise();
babel_main_loop(thread);/* this function self-add to the t_update thread */
return 0;
}
/* fill "myid" with an unique id (only if myid != {0}). */
static void
babel_get_myid(void)
{
struct interface *ifp = NULL;
struct listnode *linklist_node = NULL;
int rc;
int i;
/* if we already have an id (from state file), we return. */
if (memcmp(myid, zeroes, 8) != 0) {
return;
}
FOR_ALL_INTERFACES(ifp, linklist_node) {
/* ifp->ifindex is not necessarily valid at this point */
int ifindex = if_nametoindex(ifp->name);
if(ifindex > 0) {
unsigned char eui[8];
rc = if_eui64(ifp->name, ifindex, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);
return;
}
}
/* We failed to get a global EUI64 from the interfaces we were given.
Let's try to find an interface with a MAC address. */
for(i = 1; i < 256; i++) {
char buf[IF_NAMESIZE], *ifname;
unsigned char eui[8];
ifname = if_indextoname(i, buf);
if(ifname == NULL)
continue;
rc = if_eui64(ifname, i, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);
return;
}
zlog_err("Warning: couldn't find router id -- using random value.");
rc = read_random_bytes(myid, 8);
if(rc < 0) {
zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
exit(1);
}
/* Clear group and global bits */
myid[0] &= ~3;
}
/* Make some noise so that others notice us, and send retractions in
case we were restarted recently */
static void
babel_initial_noise(void)
{
struct interface *ifp = NULL;
struct listnode *linklist_node = NULL;
FOR_ALL_INTERFACES(ifp, linklist_node) {
if(!if_up(ifp))
continue;
/* Apply jitter before we send the first message. */
usleep(roughly(10000));
gettime(&babel_now);
send_hello(ifp);
send_wildcard_retraction(ifp);
}
FOR_ALL_INTERFACES(ifp, linklist_node) {
if(!if_up(ifp))
continue;
usleep(roughly(10000));
gettime(&babel_now);
send_hello(ifp);
send_wildcard_retraction(ifp);
send_self_update(ifp);
send_request(ifp, NULL, 0);
flushupdates(ifp);
flushbuf(ifp);
}
}
/* Delete all the added babel routes, make babeld only speak to zebra. */
static void
babel_clean_routing_process()
{
flush_all_routes();
babel_interface_close_all();
/* cancel threads */
if (babel_routing_process->t_read != NULL) {
thread_cancel(babel_routing_process->t_read);
}
if (babel_routing_process->t_update != NULL) {
thread_cancel(babel_routing_process->t_update);
}
XFREE(MTYPE_BABEL, babel_routing_process);
babel_routing_process = NULL;
}
/* Function used with timeout. */
static int
babel_main_loop(struct thread *thread)
{
struct timeval tv;
struct interface *ifp = NULL;
struct listnode *linklist_node = NULL;
while(1) {
gettime(&babel_now);
/* timeouts --------------------------------------------------------- */
/* get the next timeout */
babel_fill_with_next_timeout(&tv);
/* if there is no timeout, we must wait. */
if(timeval_compare(&tv, &babel_now) > 0) {
timeval_minus(&tv, &tv, &babel_now);
debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
tv.tv_sec * 1000 + tv.tv_usec / 1000);
/* it happens often to have less than 1 ms, it's bad. */
timeval_add_msec(&tv, &tv, 300);
babel_set_timer(&tv);
return 0;
}
gettime(&babel_now);
/* update database -------------------------------------------------- */
if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
int msecs;
msecs = check_neighbours();
msecs = MAX(msecs, 10);
schedule_neighbours_check(msecs, 1);
}
if(babel_now.tv_sec >= expiry_time) {
expire_routes();
expire_resend();
expiry_time = babel_now.tv_sec + roughly(30);
}
if(babel_now.tv_sec >= source_expiry_time) {
expire_sources();
source_expiry_time = babel_now.tv_sec + roughly(300);
}
FOR_ALL_INTERFACES(ifp, linklist_node) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
babel_ifp = babel_get_if_nfo(ifp);
if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
send_hello(ifp);
if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
send_update(ifp, 0, NULL, 0);
if(timeval_compare(&babel_now,
&babel_ifp->update_flush_timeout) >= 0)
flushupdates(ifp);
}
if(resend_time.tv_sec != 0) {
if(timeval_compare(&babel_now, &resend_time) >= 0)
do_resend();
}
if(unicast_flush_timeout.tv_sec != 0) {
if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
flush_unicast(1);
}
FOR_ALL_INTERFACES(ifp, linklist_node) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
babel_ifp = babel_get_if_nfo(ifp);
if(babel_ifp->flush_timeout.tv_sec != 0) {
if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
flushbuf(ifp);
}
}
}
assert(0); /* this line should never be reach */
}
static void
printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
{
static struct timeval curr_tv;
static char buffer[200];
static const char *curr_tag = NULL;
switch (cmd) {
case 0: /* reset timeval */
curr_tv = *tv;
if(ifname != NULL) {
snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
curr_tag = buffer;
} else {
curr_tag = tag;
}
break;
case 1: /* take the min */
if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
break;
}
if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
tv->tv_usec < curr_tv.tv_usec)) {
curr_tv = *tv;
if(ifname != NULL) {
snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
curr_tag = buffer;
} else {
curr_tag = tag;
}
}
break;
case 2: /* print message */
debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
break;
default:
break;
}
}
static void
babel_fill_with_next_timeout(struct timeval *tv)
{
#if (defined NO_DEBUG)
#define printIfMin(a,b,c,d)
#else
#define printIfMin(a,b,c,d) \
if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
struct interface *ifp = NULL;
struct listnode *linklist_node = NULL;
*tv = check_neighbours_timeout;
printIfMin(tv, 0, "check_neighbours_timeout", NULL);
timeval_min_sec(tv, expiry_time);
printIfMin(tv, 1, "expiry_time", NULL);
timeval_min_sec(tv, source_expiry_time);
printIfMin(tv, 1, "source_expiry_time", NULL);
timeval_min(tv, &resend_time);
printIfMin(tv, 1, "resend_time", NULL);
FOR_ALL_INTERFACES(ifp, linklist_node) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
babel_ifp = babel_get_if_nfo(ifp);
timeval_min(tv, &babel_ifp->flush_timeout);
printIfMin(tv, 1, "flush_timeout", ifp->name);
timeval_min(tv, &babel_ifp->hello_timeout);
printIfMin(tv, 1, "hello_timeout", ifp->name);
timeval_min(tv, &babel_ifp->update_timeout);
printIfMin(tv, 1, "update_timeout", ifp->name);
timeval_min(tv, &babel_ifp->update_flush_timeout);
printIfMin(tv, 1, "update_flush_timeout",ifp->name);
}
timeval_min(tv, &unicast_flush_timeout);
printIfMin(tv, 1, "unicast_flush_timeout", NULL);
printIfMin(tv, 2, NULL, NULL);
#undef printIfMin
#endif
}
/* set the t_update thread of the babel routing process to be launch in
'timeout' (approximate at the milisecond) */
static void
babel_set_timer(struct timeval *timeout)
{
long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
if (babel_routing_process->t_update != NULL) {
thread_cancel(babel_routing_process->t_update);
}
babel_routing_process->t_update =
thread_add_timer_msec(master, &babel_main_loop, NULL, msecs);
}
/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */
void
schedule_neighbours_check(int msecs, int override)
{
struct timeval timeout;
timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2));
if(override)
check_neighbours_timeout = timeout;
else
timeval_min(&check_neighbours_timeout, &timeout);
}
int
resize_receive_buffer(int size)
{
if(size <= receive_buffer_size)
return 0;
if(receive_buffer == NULL) {
receive_buffer = malloc(size);
if(receive_buffer == NULL) {
zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
return -1;
}
receive_buffer_size = size;
} else {
unsigned char *new;
new = realloc(receive_buffer, size);
if(new == NULL) {
zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
return -1;
}
receive_buffer = new;
receive_buffer_size = size;
}
return 1;
}
static void
babel_distribute_update (struct distribute *dist)
{
struct interface *ifp;
babel_interface_nfo *babel_ifp;
struct access_list *alist;
struct prefix_list *plist;
if (! dist->ifname)
return;
ifp = if_lookup_by_name (dist->ifname);
if (ifp == NULL)
return;
babel_ifp = babel_get_if_nfo(ifp);
if (dist->list[DISTRIBUTE_IN]) {
alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
if (alist)
babel_ifp->list[BABEL_FILTER_IN] = alist;
else
babel_ifp->list[BABEL_FILTER_IN] = NULL;
} else {
babel_ifp->list[BABEL_FILTER_IN] = NULL;
}
if (dist->list[DISTRIBUTE_OUT]) {
alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
if (alist)
babel_ifp->list[BABEL_FILTER_OUT] = alist;
else
babel_ifp->list[BABEL_FILTER_OUT] = NULL;
} else {
babel_ifp->list[BABEL_FILTER_OUT] = NULL;
}
if (dist->prefix[DISTRIBUTE_IN]) {
plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
if (plist)
babel_ifp->prefix[BABEL_FILTER_IN] = plist;
else
babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
} else {
babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
}
if (dist->prefix[DISTRIBUTE_OUT]) {
plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
if (plist)
babel_ifp->prefix[BABEL_FILTER_OUT] = plist;
else
babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
} else {
babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
}
}
static void
babel_distribute_update_interface (struct interface *ifp)
{
struct distribute *dist;
dist = distribute_lookup (ifp->name);
if (dist)
babel_distribute_update (dist);
}
/* Update all interface's distribute list. */
static void
babel_distribute_update_all (struct prefix_list *notused)
{
struct interface *ifp;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
babel_distribute_update_interface (ifp);
}
static void
babel_distribute_update_all_wrapper (struct access_list *notused)
{
babel_distribute_update_all(NULL);
}
/* [Command] */
DEFUN (router_babel,
router_babel_cmd,
"router babel",
"Enable a routing process\n"
"Make Babel instance command\n"
"No attributes\n")
{
int ret;
vty->node = BABEL_NODE;
if (!babel_routing_process) {
ret = babel_create_routing_process ();
/* Notice to user we couldn't create Babel. */
if (ret < 0) {
zlog_warn ("can't create Babel");
return CMD_WARNING;
}
}
return CMD_SUCCESS;
}
/* [Command] */
DEFUN (no_router_babel,
no_router_babel_cmd,
"no router babel",
NO_STR
"Disable a routing process\n"
"Remove Babel instance command\n"
"No attributes\n")
{
if(babel_routing_process)
babel_clean_routing_process();
return CMD_SUCCESS;
}
/* [Babel Command] */
DEFUN (babel_set_resend_delay,
babel_set_resend_delay_cmd,
"babel resend-delay <20-655340>",
"Babel commands\n"
"Time before resending a message\n"
"Milliseconds\n")
{
int interval;
VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
resend_delay = interval;
return CMD_SUCCESS;
}
void
babeld_quagga_init(void)
{
install_node(&cmd_babel_node, &babel_config_write);
install_element(CONFIG_NODE, &router_babel_cmd);
install_element(CONFIG_NODE, &no_router_babel_cmd);
install_default(BABEL_NODE);
install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
babel_if_init();
/* Access list install. */
access_list_init ();
access_list_add_hook (babel_distribute_update_all_wrapper);
access_list_delete_hook (babel_distribute_update_all_wrapper);
/* Prefix list initialize.*/
prefix_list_init ();
prefix_list_add_hook (babel_distribute_update_all);
prefix_list_delete_hook (babel_distribute_update_all);
/* Distribute list install. */
distribute_list_init (BABEL_NODE);
distribute_list_add_hook (babel_distribute_update);
distribute_list_delete_hook (babel_distribute_update);
}
/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
int
input_filter(const unsigned char *id,
const unsigned char *prefix, unsigned short plen,
const unsigned char *neigh, unsigned int ifindex)
{
return babel_filter(0, prefix, plen, ifindex);
}
int
output_filter(const unsigned char *id, const unsigned char *prefix,
unsigned short plen, unsigned int ifindex)
{
return babel_filter(1, prefix, plen, ifindex);
}
/* There's no redistribute filter in Quagga -- the zebra daemon does its
own filtering. */
int
redistribute_filter(const unsigned char *prefix, unsigned short plen,
unsigned int ifindex, int proto)
{
return 0;
}

30
babeld/babeld.conf.sample Normal file
View File

@ -0,0 +1,30 @@
debug babel common
!debug babel kernel
!debug babel filter
!debug babel timeout
!debug babel interface
!debug babel route
!debug babel all
router babel
! network wlan0
! network eth0
! redistribute kernel
! no redistribute static
! The defaults are fine for a wireless interface
!interface wlan0
! A few optimisation tweaks are optional but recommended on a wired interface
! Disable link quality estimation, enable split horizon processing, and
! increase the hello and update intervals.
!interface eth0
! babel wired
! babel split-horizon
! babel hello-interval 12000
! babel update-interval 36000
! log file /var/log/quagga/babeld.log
log stdout

141
babeld/babeld.h Normal file
View File

@ -0,0 +1,141 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_BABELD_H
#define BABEL_BABELD_H
#include <zebra.h>
#include "vty.h"
#define INFINITY ((unsigned short)(~0))
#ifndef RTPROT_BABEL
#define RTPROT_BABEL 42
#endif
#define RTPROT_BABEL_LOCAL -2
#undef MAX
#undef MIN
#define MAX(x,y) ((x)<=(y)?(y):(x))
#define MIN(x,y) ((x)<=(y)?(x):(y))
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* nothing */
#elif defined(__GNUC__)
#define inline __inline
#if (__GNUC__ >= 3)
#define restrict __restrict
#else
#define restrict /**/
#endif
#else
#define inline /**/
#define restrict /**/
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
#define ATTRIBUTE(x) __attribute__ (x)
#define LIKELY(_x) __builtin_expect(!!(_x), 1)
#define UNLIKELY(_x) __builtin_expect(!!(_x), 0)
#else
#define ATTRIBUTE(x) /**/
#define LIKELY(_x) !!(_x)
#define UNLIKELY(_x) !!(_x)
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
#define COLD __attribute__ ((cold))
#else
#define COLD /**/
#endif
#ifndef IF_NAMESIZE
#include <sys/socket.h>
#include <net/if.h>
#endif
#ifdef HAVE_VALGRIND
#include <valgrind/memcheck.h>
#else
#ifndef VALGRIND_MAKE_MEM_UNDEFINED
#define VALGRIND_MAKE_MEM_UNDEFINED(a, b) do {} while(0)
#endif
#ifndef VALGRIND_CHECK_MEM_IS_DEFINED
#define VALGRIND_CHECK_MEM_IS_DEFINED(a, b) do {} while(0)
#endif
#endif
#define BABEL_VTY_PORT 2609
#define BABEL_DEFAULT_CONFIG "babeld.conf"
#define BABEL_VERSION "0.1 for quagga"
/* Values in milliseconds */
#define BABEL_DEFAULT_HELLO_INTERVAL 4000
#define BABEL_DEFAULT_UPDATE_INTERVAL 16000
#define BABEL_DEFAULT_RESEND_DELAY 2000
/* Babel socket. */
extern int protocol_socket;
/* Babel structure. */
struct babel
{
/* Babel threads. */
struct thread *t_read; /* on Babel protocol's socket */
struct thread *t_update; /* timers */
};
extern void babeld_quagga_init(void);
extern int input_filter(const unsigned char *id,
const unsigned char *prefix, unsigned short plen,
const unsigned char *neigh, unsigned int ifindex);
extern int output_filter(const unsigned char *id, const unsigned char *prefix,
unsigned short plen, unsigned int ifindex);
extern int redistribute_filter(const unsigned char *prefix, unsigned short plen,
unsigned int ifindex, int proto);
extern int resize_receive_buffer(int size);
extern void schedule_neighbours_check(int msecs, int override);
#endif /* BABEL_BABELD_H */

76
babeld/kernel.c Normal file
View File

@ -0,0 +1,76 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <sys/time.h>
#include <sys/param.h>
#include <time.h>
#include "babeld.h"
#include "kernel_zebra.c"
/* Like gettimeofday, but returns monotonic time. If POSIX clocks are not
available, falls back to gettimeofday but enforces monotonicity. */
int
gettime(struct timeval *tv)
{
return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv);
}
/* If /dev/urandom doesn't exist, this will fail with ENOENT, which the
caller will deal with gracefully. */
int
read_random_bytes(void *buf, size_t len)
{
int fd;
int rc;
fd = open("/dev/urandom", O_RDONLY);
if(fd < 0) {
rc = -1;
} else {
rc = read(fd, buf, len);
if(rc < 0 || (unsigned) rc < len)
rc = -1;
close(fd);
}
return rc;
}

69
babeld/kernel.h Normal file
View File

@ -0,0 +1,69 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <netinet/in.h>
#include "babel_main.h"
#include "if.h"
#define KERNEL_INFINITY 0xFFFF
struct kernel_route {
unsigned char prefix[16];
int plen;
int metric;
unsigned int ifindex;
int proto;
unsigned char gw[16];
};
#define ROUTE_FLUSH 0
#define ROUTE_ADD 1
#define ROUTE_MODIFY 2
extern int export_table, import_table;
int kernel_interface_operational(struct interface *interface);
int kernel_interface_mtu(struct interface *interface);
int kernel_interface_wireless(struct interface *interface);
int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex,
unsigned int newmetric);
int if_eui64(char *ifname, int ifindex, unsigned char *eui);
int gettime(struct timeval *tv);
int read_random_bytes(void *buf, size_t len);

275
babeld/kernel_zebra.c Normal file
View File

@ -0,0 +1,275 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <zebra.h>
#include "prefix.h"
#include "zclient.h"
#include "kernel.h"
#include "privs.h"
#include "command.h"
#include "vty.h"
#include "memory.h"
#include "thread.h"
#include "util.h"
#include "babel_interface.h"
#include "babel_zebra.h"
static int
kernel_route_v4(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex,
unsigned int metric);
static int
kernel_route_v6(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex,
unsigned int metric);
int
kernel_interface_operational(struct interface *interface)
{
return if_is_operative(interface);
}
int
kernel_interface_mtu(struct interface *interface)
{
return MIN(interface->mtu, interface->mtu6);
}
int
kernel_interface_wireless(struct interface *interface)
{
return 0;
}
int
kernel_route(int operation, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex,
unsigned int newmetric)
{
int rc;
int ipv4;
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(pref)) {
if(!v4mapped(gate)) {
errno = EINVAL;
return -1;
}
ipv4 = 1;
} else {
if(v4mapped(gate)) {
errno = EINVAL;
return -1;
}
ipv4 = 0;
}
switch (operation) {
case ROUTE_ADD:
return ipv4 ?
kernel_route_v4(1, pref, plen, gate, ifindex, metric):
kernel_route_v6(1, pref, plen, gate, ifindex, metric);
break;
case ROUTE_FLUSH:
return ipv4 ?
kernel_route_v4(0, pref, plen, gate, ifindex, metric):
kernel_route_v6(0, pref, plen, gate, ifindex, metric);
break;
case ROUTE_MODIFY:
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
newifindex == ifindex)
return 0;
debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
rc = ipv4 ?
kernel_route_v4(0, pref, plen, gate, ifindex, metric):
kernel_route_v6(0, pref, plen, gate, ifindex, metric);
if (rc < 0)
return -1;
rc = ipv4 ?
kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric):
kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric);
return rc;
break;
default:
zlog_err("this should never appens (false value - kernel_route)");
assert(0);
exit(1);
break;
}
}
static int
kernel_route_v4(int add,
const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric)
{
struct zapi_ipv4 api; /* quagga's communication system */
struct prefix_ipv4 quagga_prefix; /* quagga's prefix */
struct in_addr babel_prefix_addr; /* babeld's prefix addr */
struct in_addr nexthop; /* next router to go */
struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */
/* convert to be understandable by quagga */
/* convert given addresses */
uchar_to_inaddr(&babel_prefix_addr, pref);
uchar_to_inaddr(&nexthop, gate);
/* make prefix structure */
memset (&quagga_prefix, 0, sizeof(quagga_prefix));
quagga_prefix.family = AF_INET;
IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr);
quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */
apply_mask_ipv4(&quagga_prefix);
api.type = ZEBRA_ROUTE_BABEL;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
/* Unlike the native Linux and BSD interfaces, Quagga doesn't like
there to be both and IPv4 nexthop and an ifindex. Omit the
ifindex, and assume that the connected prefixes be set up
correctly. */
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.ifindex_num = 0;
if(metric >= KERNEL_INFINITY) {
api.flags = ZEBRA_FLAG_BLACKHOLE;
api.nexthop_num = 0;
} else {
api.nexthop_num = 1;
api.nexthop = &nexthop_pointer;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
}
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra",
add ? "adding" : "removing" );
return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD :
ZEBRA_IPV4_ROUTE_DELETE,
zclient, &quagga_prefix, &api);
}
static int
kernel_route_v6(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric)
{
unsigned int tmp_ifindex = ifindex; /* (for typing) */
struct zapi_ipv6 api; /* quagga's communication system */
struct prefix_ipv6 quagga_prefix; /* quagga's prefix */
struct in6_addr babel_prefix_addr; /* babeld's prefix addr */
struct in6_addr nexthop; /* next router to go */
struct in6_addr *nexthop_pointer = &nexthop;
/* convert to be understandable by quagga */
/* convert given addresses */
uchar_to_in6addr(&babel_prefix_addr, pref);
uchar_to_in6addr(&nexthop, gate);
/* make prefix structure */
memset (&quagga_prefix, 0, sizeof(quagga_prefix));
quagga_prefix.family = AF_INET6;
IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr);
quagga_prefix.prefixlen = plen;
apply_mask_ipv6(&quagga_prefix);
api.type = ZEBRA_ROUTE_BABEL;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if(metric >= KERNEL_INFINITY) {
api.flags = ZEBRA_FLAG_BLACKHOLE;
api.nexthop_num = 0;
api.ifindex_num = 0;
} else {
api.nexthop_num = 1;
api.nexthop = &nexthop_pointer;
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = 1;
api.ifindex = &tmp_ifindex;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
}
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra",
add ? "adding" : "removing" );
return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD :
ZEBRA_IPV6_ROUTE_DELETE,
zclient, &quagga_prefix, &api);
}
int
if_eui64(char *ifname, int ifindex, unsigned char *eui)
{
struct interface *ifp = if_lookup_by_index(ifindex);
if (ifp == NULL) {
return -1;
}
#ifdef HAVE_STRUCT_SOCKADDR_DL
u_char len = ifp->sdl.sdl_alen;
char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen;
#else
u_char len = (u_char) ifp->hw_addr_len;
char *tmp = (void*) ifp->hw_addr;
#endif
if (len == 8) {
memcpy(eui, tmp, 8);
eui[0] ^= 2;
} else if (len == 6) {
memcpy(eui, tmp, 3);
eui[3] = 0xFF;
eui[4] = 0xFE;
memcpy(eui+5, tmp+3, 3);
} else {
return -1;
}
return 0;
}

1561
babeld/message.c Normal file

File diff suppressed because it is too large Load Diff

111
babeld/message.h Normal file
View File

@ -0,0 +1,111 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_MESSAGE_H
#define BABEL_MESSAGE_H
#include "babel_interface.h"
#define MAX_BUFFERED_UPDATES 200
#define BUCKET_TOKENS_MAX 200
#define BUCKET_TOKENS_PER_SEC 40
#define MESSAGE_PAD1 0
#define MESSAGE_PADN 1
#define MESSAGE_ACK_REQ 2
#define MESSAGE_ACK 3
#define MESSAGE_HELLO 4
#define MESSAGE_IHU 5
#define MESSAGE_ROUTER_ID 6
#define MESSAGE_NH 7
#define MESSAGE_UPDATE 8
#define MESSAGE_REQUEST 9
#define MESSAGE_MH_REQUEST 10
extern unsigned short myseqno;
extern struct timeval seqno_time;
extern int broadcast_ihu;
extern int split_horizon;
extern unsigned char packet_header[4];
extern struct neighbour *unicast_neighbour;
extern struct timeval unicast_flush_timeout;
void parse_packet(const unsigned char *from, struct interface *ifp,
const unsigned char *packet, int packetlen);
void flushbuf(struct interface *ifp);
void flushupdates(struct interface *ifp);
void send_ack(struct neighbour *neigh, unsigned short nonce,
unsigned short interval);
void send_hello_noupdate(struct interface *ifp, unsigned interval);
void send_hello(struct interface *ifp);
void flush_unicast(int dofree);
void send_update(struct interface *ifp, int urgent,
const unsigned char *prefix, unsigned char plen);
void send_update_resend(struct interface *ifp,
const unsigned char *prefix, unsigned char plen);
void send_wildcard_retraction(struct interface *ifp);
void update_myseqno(void);
void send_self_update(struct interface *ifp);
void send_ihu(struct neighbour *neigh, struct interface *ifp);
void send_marginal_ihu(struct interface *ifp);
void send_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen);
void send_unicast_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen);
void send_multihop_request(struct interface *ifp,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
unsigned short hop_count);
void
send_unicast_multihop_request(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
unsigned short hop_count);
void send_request_resend(struct neighbour *neigh,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, unsigned char *id);
void handle_request(struct neighbour *neigh, const unsigned char *prefix,
unsigned char plen, unsigned char hop_count,
unsigned short seqno, const unsigned char *id);
#endif

343
babeld/neighbour.c Normal file
View File

@ -0,0 +1,343 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <zebra.h>
#include "if.h"
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "babel_interface.h"
#include "neighbour.h"
#include "source.h"
#include "route.h"
#include "message.h"
#include "resend.h"
struct neighbour *neighs = NULL;
static struct neighbour *
find_neighbour_nocreate(const unsigned char *address, struct interface *ifp)
{
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(memcmp(address, neigh->address, 16) == 0 &&
neigh->ifp == ifp)
return neigh;
}
return NULL;
}
void
flush_neighbour(struct neighbour *neigh)
{
flush_neighbour_routes(neigh);
if(unicast_neighbour == neigh)
flush_unicast(1);
flush_resends(neigh);
if(neighs == neigh) {
neighs = neigh->next;
} else {
struct neighbour *previous = neighs;
while(previous->next != neigh)
previous = previous->next;
previous->next = neigh->next;
}
free(neigh);
}
struct neighbour *
find_neighbour(const unsigned char *address, struct interface *ifp)
{
struct neighbour *neigh;
const struct timeval zero = {0, 0};
neigh = find_neighbour_nocreate(address, ifp);
if(neigh)
return neigh;
debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.",
format_address(address), ifp->name);
neigh = malloc(sizeof(struct neighbour));
if(neigh == NULL) {
zlog_err("malloc(neighbour): %s", safe_strerror(errno));
return NULL;
}
neigh->hello_seqno = -1;
memcpy(neigh->address, address, 16);
neigh->reach = 0;
neigh->txcost = INFINITY;
neigh->ihu_time = babel_now;
neigh->hello_time = zero;
neigh->hello_interval = 0;
neigh->ihu_interval = 0;
neigh->ifp = ifp;
neigh->next = neighs;
neighs = neigh;
send_hello(ifp);
return neigh;
}
/* Recompute a neighbour's rxcost. Return true if anything changed.
This does not call local_notify_neighbour, see update_neighbour_metric. */
int
update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
{
int missed_hellos;
int rc = 0;
if(hello < 0) {
if(neigh->hello_interval <= 0)
return rc;
missed_hellos =
((int)timeval_minus_msec(&babel_now, &neigh->hello_time) -
neigh->hello_interval * 7) /
(neigh->hello_interval * 10);
if(missed_hellos <= 0)
return rc;
timeval_add_msec(&neigh->hello_time, &neigh->hello_time,
missed_hellos * neigh->hello_interval * 10);
} else {
if(neigh->hello_seqno >= 0 && neigh->reach > 0) {
missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1;
if(missed_hellos < -8) {
/* Probably a neighbour that rebooted and lost its seqno.
Reboot the universe. */
neigh->reach = 0;
missed_hellos = 0;
rc = 1;
} else if(missed_hellos < 0) {
if(hello_interval > neigh->hello_interval) {
/* This neighbour has increased its hello interval,
and we didn't notice. */
neigh->reach <<= -missed_hellos;
missed_hellos = 0;
} else {
/* Late hello. Probably due to the link layer buffering
packets during a link outage. Ignore it, but reset
the expected seqno. */
neigh->hello_seqno = hello;
hello = -1;
missed_hellos = 0;
}
rc = 1;
}
} else {
missed_hellos = 0;
}
neigh->hello_time = babel_now;
neigh->hello_interval = hello_interval;
}
if(missed_hellos > 0) {
neigh->reach >>= missed_hellos;
neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos);
missed_hellos = 0;
rc = 1;
}
if(hello >= 0) {
neigh->hello_seqno = hello;
neigh->reach >>= 1;
neigh->reach |= 0x8000;
if((neigh->reach & 0xFC00) != 0xFC00)
rc = 1;
}
/* Make sure to give neighbours some feedback early after association */
if((neigh->reach & 0xBF00) == 0x8000) {
/* A new neighbour */
send_hello(neigh->ifp);
} else {
/* Don't send hellos, in order to avoid a positive feedback loop. */
int a = (neigh->reach & 0xC000);
int b = (neigh->reach & 0x3000);
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
/* Reachability is either 1100 or 0011 */
send_self_update(neigh->ifp);
}
}
if((neigh->reach & 0xFC00) == 0xC000) {
/* This is a newish neighbour, let's request a full route dump.
We ought to avoid this when the network is dense */
send_unicast_request(neigh, NULL, 0);
send_ihu(neigh, NULL);
}
return rc;
}
static int
reset_txcost(struct neighbour *neigh)
{
unsigned delay;
delay = timeval_minus_msec(&babel_now, &neigh->ihu_time);
if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U)
return 0;
/* If we're losing a lot of packets, we probably lost an IHU too */
if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 ||
(neigh->ihu_interval > 0 &&
delay >= neigh->ihu_interval * 10U * 10U)) {
neigh->txcost = INFINITY;
neigh->ihu_time = babel_now;
return 1;
}
return 0;
}
unsigned
neighbour_txcost(struct neighbour *neigh)
{
return neigh->txcost;
}
unsigned
check_neighbours()
{
struct neighbour *neigh;
int changed, rc;
unsigned msecs = 50000;
debugf(BABEL_DEBUG_COMMON,"Checking neighbours.");
neigh = neighs;
while(neigh) {
changed = update_neighbour(neigh, -1, 0);
if(neigh->reach == 0 ||
neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */
timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) {
struct neighbour *old = neigh;
neigh = neigh->next;
flush_neighbour(old);
continue;
}
rc = reset_txcost(neigh);
changed = changed || rc;
update_neighbour_metric(neigh, changed);
if(neigh->hello_interval > 0)
msecs = MIN(msecs, neigh->hello_interval * 10U);
if(neigh->ihu_interval > 0)
msecs = MIN(msecs, neigh->ihu_interval * 10U);
neigh = neigh->next;
}
return msecs;
}
unsigned
neighbour_rxcost(struct neighbour *neigh)
{
unsigned delay;
unsigned short reach = neigh->reach;
delay = timeval_minus_msec(&babel_now, &neigh->hello_time);
if((reach & 0xFFF0) == 0 || delay >= 180000) {
return INFINITY;
} else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) {
int sreach =
((reach & 0x8000) >> 2) +
((reach & 0x4000) >> 1) +
(reach & 0x3FFF);
/* 0 <= sreach <= 0x7FFF */
int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1);
/* cost >= interface->cost */
if(delay >= 40000)
cost = (cost * (delay - 20000) + 10000) / 20000;
return MIN(cost, INFINITY);
} else {
/* To lose one hello is a misfortune, to lose two is carelessness. */
if((reach & 0xC000) == 0xC000)
return babel_get_if_nfo(neigh->ifp)->cost;
else if((reach & 0xC000) == 0)
return INFINITY;
else if((reach & 0x2000))
return babel_get_if_nfo(neigh->ifp)->cost;
else
return INFINITY;
}
}
unsigned
neighbour_cost(struct neighbour *neigh)
{
unsigned a, b;
if(!if_up(neigh->ifp))
return INFINITY;
a = neighbour_txcost(neigh);
if(a >= INFINITY)
return INFINITY;
b = neighbour_rxcost(neigh);
if(b >= INFINITY)
return INFINITY;
if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ)
|| (a < 256 && b < 256)) {
return a;
} else {
/* a = 256/alpha, b = 256/beta, where alpha and beta are the expected
probabilities of a packet getting through in the direct and reverse
directions. */
a = MAX(a, 256);
b = MAX(b, 256);
/* 1/(alpha * beta), which is just plain ETX. */
/* Since a and b are capped to 16 bits, overflow is impossible. */
return (a * b + 128) >> 8;
}
}

66
babeld/neighbour.h Normal file
View File

@ -0,0 +1,66 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
struct neighbour {
struct neighbour *next;
/* This is -1 when unknown, so don't make it unsigned */
int hello_seqno;
unsigned char address[16];
unsigned short reach;
unsigned short txcost;
struct timeval hello_time;
struct timeval ihu_time;
unsigned short hello_interval; /* in centiseconds */
unsigned short ihu_interval; /* in centiseconds */
struct interface *ifp;
};
extern struct neighbour *neighs;
#define FOR_ALL_NEIGHBOURS(_neigh) \
for(_neigh = neighs; _neigh; _neigh = _neigh->next)
int neighbour_valid(struct neighbour *neigh);
void flush_neighbour(struct neighbour *neigh);
struct neighbour *find_neighbour(const unsigned char *address,
struct interface *ifp);
int update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
unsigned check_neighbours(void);
unsigned neighbour_txcost(struct neighbour *neigh);
unsigned neighbour_rxcost(struct neighbour *neigh);
unsigned neighbour_cost(struct neighbour *neigh);

239
babeld/net.c Normal file
View File

@ -0,0 +1,239 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include "babeld.h"
#include "util.h"
#include "net.h"
int
babel_socket(int port)
{
struct sockaddr_in6 sin6;
int s, rc;
int saved_errno;
int one = 1, zero = 0;
const int ds = 0xc0; /* CS6 - Network Control */
s = socket(PF_INET6, SOCK_DGRAM, 0);
if(s < 0)
return -1;
rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
if(rc < 0)
goto fail;
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if(rc < 0)
goto fail;
rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
&zero, sizeof(zero));
if(rc < 0)
goto fail;
rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&one, sizeof(one));
if(rc < 0)
goto fail;
rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&one, sizeof(one));
if(rc < 0)
goto fail;
#ifdef IPV6_TCLASS
rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds));
#else
rc = -1;
errno = ENOSYS;
#endif
if(rc < 0)
perror("Couldn't set traffic class");
rc = fcntl(s, F_GETFL, 0);
if(rc < 0)
goto fail;
rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
if(rc < 0)
goto fail;
rc = fcntl(s, F_GETFD, 0);
if(rc < 0)
goto fail;
rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
if(rc < 0)
goto fail;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
goto fail;
return s;
fail:
saved_errno = errno;
close(s);
errno = saved_errno;
return -1;
}
int
babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen)
{
struct iovec iovec;
struct msghdr msg;
int rc;
memset(&msg, 0, sizeof(msg));
iovec.iov_base = buf;
iovec.iov_len = buflen;
msg.msg_name = sin;
msg.msg_namelen = slen;
msg.msg_iov = &iovec;
msg.msg_iovlen = 1;
rc = recvmsg(s, &msg, 0);
return rc;
}
int
babel_send(int s,
void *buf1, int buflen1, void *buf2, int buflen2,
struct sockaddr *sin, int slen)
{
struct iovec iovec[2];
struct msghdr msg;
int rc;
iovec[0].iov_base = buf1;
iovec[0].iov_len = buflen1;
iovec[1].iov_base = buf2;
iovec[1].iov_len = buflen2;
memset(&msg, 0, sizeof(msg));
msg.msg_name = (struct sockaddr*)sin;
msg.msg_namelen = slen;
msg.msg_iov = iovec;
msg.msg_iovlen = 2;
again:
rc = sendmsg(s, &msg, 0);
if(rc < 0) {
if(errno == EINTR)
goto again;
else if(errno == EAGAIN) {
int rc2;
rc2 = wait_for_fd(1, s, 5);
if(rc2 > 0)
goto again;
errno = EAGAIN;
}
}
return rc;
}
int
tcp_server_socket(int port, int local)
{
struct sockaddr_in6 sin6;
int s, rc, saved_errno;
int one = 1;
s = socket(PF_INET6, SOCK_STREAM, 0);
if(s < 0)
return -1;
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if(rc < 0)
goto fail;
rc = fcntl(s, F_GETFL, 0);
if(rc < 0)
goto fail;
rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
if(rc < 0)
goto fail;
rc = fcntl(s, F_GETFD, 0);
if(rc < 0)
goto fail;
rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
if(rc < 0)
goto fail;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
if(local) {
rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr);
if(rc < 0)
goto fail;
}
rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
goto fail;
rc = listen(s, 2);
if(rc < 0)
goto fail;
return s;
fail:
saved_errno = errno;
close(s);
errno = saved_errno;
return -1;
}

44
babeld/net.h Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
int babel_socket(int port);
int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen);
int babel_send(int s,
void *buf1, int buflen1, void *buf2, int buflen2,
struct sockaddr *sin, int slen);
int tcp_server_socket(int port, int local);

330
babeld/resend.c Normal file
View File

@ -0,0 +1,330 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <zebra.h>
#include "if.h"
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "neighbour.h"
#include "resend.h"
#include "message.h"
#include "babel_interface.h"
struct timeval resend_time = {0, 0};
struct resend *to_resend = NULL;
static int
resend_match(struct resend *resend,
int kind, const unsigned char *prefix, unsigned char plen)
{
return (resend->kind == kind &&
resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0);
}
/* This is called by neigh.c when a neighbour is flushed */
void
flush_resends(struct neighbour *neigh)
{
/* Nothing for now */
}
static struct resend *
find_resend(int kind, const unsigned char *prefix, unsigned char plen,
struct resend **previous_return)
{
struct resend *current, *previous;
previous = NULL;
current = to_resend;
while(current) {
if(resend_match(current, kind, prefix, plen)) {
if(previous_return)
*previous_return = previous;
return current;
}
previous = current;
current = current->next;
}
return NULL;
}
struct resend *
find_request(const unsigned char *prefix, unsigned char plen,
struct resend **previous_return)
{
return find_resend(RESEND_REQUEST, prefix, plen, previous_return);
}
int
record_resend(int kind, const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
struct interface *ifp, int delay)
{
struct resend *resend;
unsigned int ifindex = ifp ? ifp->ifindex : 0;
if((kind == RESEND_REQUEST &&
input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) ||
(kind == RESEND_UPDATE &&
output_filter(NULL, prefix, plen, ifindex) >= INFINITY))
return 0;
if(delay >= 0xFFFF)
delay = 0xFFFF;
resend = find_resend(kind, prefix, plen, NULL);
if(resend) {
if(resend->delay && delay)
resend->delay = MIN(resend->delay, delay);
else if(delay)
resend->delay = delay;
resend->time = babel_now;
resend->max = RESEND_MAX;
if(id && memcmp(resend->id, id, 8) == 0 &&
seqno_compare(resend->seqno, seqno) > 0) {
return 0;
}
if(id)
memcpy(resend->id, id, 8);
else
memset(resend->id, 0, 8);
resend->seqno = seqno;
if(resend->ifp != ifp)
resend->ifp = NULL;
} else {
resend = malloc(sizeof(struct resend));
if(resend == NULL)
return -1;
resend->kind = kind;
resend->max = RESEND_MAX;
resend->delay = delay;
memcpy(resend->prefix, prefix, 16);
resend->plen = plen;
resend->seqno = seqno;
if(id)
memcpy(resend->id, id, 8);
else
memset(resend->id, 0, 8);
resend->ifp = ifp;
resend->time = babel_now;
resend->next = to_resend;
to_resend = resend;
}
if(resend->delay) {
struct timeval timeout;
timeval_add_msec(&timeout, &resend->time, resend->delay);
timeval_min(&resend_time, &timeout);
}
return 1;
}
static int
resend_expired(struct resend *resend)
{
switch(resend->kind) {
case RESEND_REQUEST:
return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT;
default:
return resend->max <= 0;
}
}
int
unsatisfied_request(const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id)
{
struct resend *request;
request = find_request(prefix, plen, NULL);
if(request == NULL || resend_expired(request))
return 0;
if(memcmp(request->id, id, 8) != 0 ||
seqno_compare(request->seqno, seqno) <= 0)
return 1;
return 0;
}
/* Determine whether a given request should be forwarded. */
int
request_redundant(struct interface *ifp,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id)
{
struct resend *request;
request = find_request(prefix, plen, NULL);
if(request == NULL || resend_expired(request))
return 0;
if(memcmp(request->id, id, 8) == 0 &&
seqno_compare(request->seqno, seqno) > 0)
return 0;
if(request->ifp != NULL && request->ifp != ifp)
return 0;
if(request->max > 0)
/* Will be resent. */
return 1;
if(timeval_minus_msec(&babel_now, &request->time) <
(ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000))
/* Fairly recent. */
return 1;
return 0;
}
int
satisfy_request(const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
struct interface *ifp)
{
struct resend *request, *previous;
request = find_request(prefix, plen, &previous);
if(request == NULL)
return 0;
if(ifp != NULL && request->ifp != ifp)
return 0;
if(memcmp(request->id, id, 8) != 0 ||
seqno_compare(request->seqno, seqno) <= 0) {
/* We cannot remove the request, as we may be walking the list right
now. Mark it as expired, so that expire_resend will remove it. */
request->max = 0;
request->time.tv_sec = 0;
recompute_resend_time();
return 1;
}
return 0;
}
void
expire_resend()
{
struct resend *current, *previous;
int recompute = 0;
previous = NULL;
current = to_resend;
while(current) {
if(resend_expired(current)) {
if(previous == NULL) {
to_resend = current->next;
free(current);
current = to_resend;
} else {
previous->next = current->next;
free(current);
current = previous->next;
}
recompute = 1;
} else {
previous = current;
current = current->next;
}
}
if(recompute)
recompute_resend_time();
}
void
recompute_resend_time()
{
struct resend *request;
struct timeval resend = {0, 0};
request = to_resend;
while(request) {
if(!resend_expired(request) && request->delay > 0 && request->max > 0) {
struct timeval timeout;
timeval_add_msec(&timeout, &request->time, request->delay);
timeval_min(&resend, &timeout);
}
request = request->next;
}
resend_time = resend;
}
void
do_resend()
{
struct resend *resend;
resend = to_resend;
while(resend) {
if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) {
struct timeval timeout;
timeval_add_msec(&timeout, &resend->time, resend->delay);
if(timeval_compare(&babel_now, &timeout) >= 0) {
switch(resend->kind) {
case RESEND_REQUEST:
send_multihop_request(resend->ifp,
resend->prefix, resend->plen,
resend->seqno, resend->id, 127);
break;
case RESEND_UPDATE:
send_update(resend->ifp, 1,
resend->prefix, resend->plen);
break;
default: abort();
}
resend->delay = MIN(0xFFFF, resend->delay * 2);
resend->max--;
}
}
resend = resend->next;
}
recompute_resend_time();
}

77
babeld/resend.h Normal file
View File

@ -0,0 +1,77 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#define REQUEST_TIMEOUT 65000
#define RESEND_MAX 3
#define RESEND_REQUEST 1
#define RESEND_UPDATE 2
struct resend {
unsigned char kind;
unsigned char max;
unsigned short delay;
struct timeval time;
unsigned char prefix[16];
unsigned char plen;
unsigned short seqno;
unsigned char id[8];
struct interface *ifp;
struct resend *next;
};
extern struct timeval resend_time;
struct resend *find_request(const unsigned char *prefix, unsigned char plen,
struct resend **previous_return);
void flush_resends(struct neighbour *neigh);
int record_resend(int kind, const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
struct interface *ifp, int delay);
int unsatisfied_request(const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id);
int request_redundant(struct interface *ifp,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id);
int satisfy_request(const unsigned char *prefix, unsigned char plen,
unsigned short seqno, const unsigned char *id,
struct interface *ifp);
void expire_resend(void);
void recompute_resend_time(void);
void do_resend(void);

1019
babeld/route.c Normal file

File diff suppressed because it is too large Load Diff

135
babeld/route.h Normal file
View File

@ -0,0 +1,135 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_ROUTE_H
#define BABEL_ROUTE_H
#include "babel_interface.h"
#include "source.h"
#define DIVERSITY_NONE 0
#define DIVERSITY_INTERFACE_1 1
#define DIVERSITY_CHANNEL_1 2
#define DIVERSITY_CHANNEL 3
#define DIVERSITY_HOPS 8
struct babel_route {
struct source *src;
unsigned short refmetric;
unsigned short cost;
unsigned short add_metric;
unsigned short seqno;
struct neighbour *neigh;
unsigned char nexthop[16];
time_t time;
unsigned short hold_time; /* in seconds */
short installed;
unsigned char channels[DIVERSITY_HOPS];
struct babel_route *next;
};
extern struct babel_route **routes;
extern int kernel_metric, allow_duplicates;
extern int diversity_kind, diversity_factor;
extern int keep_unfeasible;
static inline int
route_metric(const struct babel_route *route)
{
int m = (int)route->refmetric + route->cost + route->add_metric;
return MIN(m, INFINITY);
}
static inline int
route_metric_noninterfering(const struct babel_route *route)
{
int m =
(int)route->refmetric +
(diversity_factor * route->cost + 128) / 256 +
route->add_metric;
m = MAX(m, route->refmetric + 1);
return MIN(m, INFINITY);
}
struct babel_route *find_route(const unsigned char *prefix, unsigned char plen,
struct neighbour *neigh, const unsigned char *nexthop);
struct babel_route *find_installed_route(const unsigned char *prefix,
unsigned char plen);
int installed_routes_estimate(void);
void flush_route(struct babel_route *route);
void flush_all_routes(void);
void flush_neighbour_routes(struct neighbour *neigh);
void flush_interface_routes(struct interface *ifp, int v4only);
void for_all_routes(void (*f)(struct babel_route*, void*), void *closure);
void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure);
void install_route(struct babel_route *route);
void uninstall_route(struct babel_route *route);
void switch_route(struct babel_route *old, struct babel_route *new);
int route_feasible(struct babel_route *route);
int route_old(struct babel_route *route);
int route_expired(struct babel_route *route);
int route_interferes(struct babel_route *route, struct interface *ifp);
int update_feasible(struct source *src,
unsigned short seqno, unsigned short refmetric);
struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen,
int feasible, struct neighbour *exclude);
struct babel_route *install_best_route(const unsigned char prefix[16],
unsigned char plen);
void update_neighbour_metric(struct neighbour *neigh, int change);
void update_interface_metric(struct interface *ifp);
void update_route_metric(struct babel_route *route);
struct babel_route *update_route(const unsigned char *id,
const unsigned char *prefix, unsigned char plen,
unsigned short seqno, unsigned short refmetric,
unsigned short interval, struct neighbour *neigh,
const unsigned char *nexthop,
const unsigned char *channels, int channels_len);
void retract_neighbour_routes(struct neighbour *neigh);
void send_unfeasible_request(struct neighbour *neigh, int force,
unsigned short seqno, unsigned short metric,
struct source *src);
void send_triggered_update(struct babel_route *route,
struct source *oldsrc, unsigned oldmetric);
void route_changed(struct babel_route *route,
struct source *oldsrc, unsigned short oldmetric);
void route_lost(struct source *src, unsigned oldmetric);
void expire_routes(void);
#endif

180
babeld/source.c Normal file
View File

@ -0,0 +1,180 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "source.h"
#include "babel_interface.h"
#include "route.h"
struct source *srcs = NULL;
struct source*
find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
int create, unsigned short seqno)
{
struct source *src;
for(src = srcs; src; src = src->next) {
/* This should really be a hash table. For now, check the
last byte first. */
if(src->id[7] != id[7])
continue;
if(memcmp(src->id, id, 8) != 0)
continue;
if(src->plen != plen)
continue;
if(memcmp(src->prefix, p, 16) == 0)
return src;
}
if(!create)
return NULL;
src = malloc(sizeof(struct source));
if(src == NULL) {
zlog_err("malloc(source): %s", safe_strerror(errno));
return NULL;
}
memcpy(src->id, id, 8);
memcpy(src->prefix, p, 16);
src->plen = plen;
src->seqno = seqno;
src->metric = INFINITY;
src->time = babel_now.tv_sec;
src->route_count = 0;
src->next = srcs;
srcs = src;
return src;
}
struct source *
retain_source(struct source *src)
{
assert(src->route_count < 0xffff);
src->route_count++;
return src;
}
void
release_source(struct source *src)
{
assert(src->route_count > 0);
src->route_count--;
}
int
flush_source(struct source *src)
{
if(src->route_count > 0)
/* The source is in use by a route. */
return 0;
if(srcs == src) {
srcs = src->next;
} else {
struct source *previous = srcs;
while(previous->next != src)
previous = previous->next;
previous->next = src->next;
}
free(src);
return 1;
}
void
update_source(struct source *src,
unsigned short seqno, unsigned short metric)
{
if(metric >= INFINITY)
return;
/* If a source is expired, pretend that it doesn't exist and update
it unconditionally. This makes ensures that old data will
eventually be overridden, and prevents us from getting stuck if
a router loses its sequence number. */
if(src->time < babel_now.tv_sec - SOURCE_GC_TIME ||
seqno_compare(src->seqno, seqno) < 0 ||
(src->seqno == seqno && src->metric > metric)) {
src->seqno = seqno;
src->metric = metric;
}
src->time = babel_now.tv_sec;
}
void
expire_sources()
{
struct source *src;
src = srcs;
while(src) {
if(src->time > babel_now.tv_sec)
/* clock stepped */
src->time = babel_now.tv_sec;
if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) {
struct source *old = src;
src = src->next;
flush_source(old);
continue;
}
src = src->next;
}
}
void
check_sources_released(void)
{
struct source *src;
for(src = srcs; src; src = src->next) {
if(src->route_count != 0)
fprintf(stderr, "Warning: source %s %s has refcount %d.\n",
format_eui64(src->id),
format_prefix(src->prefix, src->plen),
(int)src->route_count);
}
}

67
babeld/source.h Normal file
View File

@ -0,0 +1,67 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef BABEL_SOURCE_H
#define BABEL_SOURCE_H
#define SOURCE_GC_TIME 200
struct source {
struct source *next;
unsigned char id[8];
unsigned char prefix[16];
unsigned char plen;
unsigned short seqno;
unsigned short metric;
unsigned short route_count;
time_t time;
};
struct source *find_source(const unsigned char *id,
const unsigned char *p,
unsigned char plen,
int create, unsigned short seqno);
struct source *retain_source(struct source *src);
void release_source(struct source *src);
int flush_source(struct source *src);
void update_source(struct source *src,
unsigned short seqno, unsigned short metric);
void expire_sources(void);
void check_sources_released(void);
#endif

445
babeld/util.c Normal file
View File

@ -0,0 +1,445 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
unsigned
roughly(unsigned value)
{
return value * 3 / 4 + random() % (value / 2);
}
/* d = s1 - s2 */
void
timeval_minus(struct timeval *d,
const struct timeval *s1, const struct timeval *s2)
{
if(s1->tv_usec >= s2->tv_usec) {
d->tv_usec = s1->tv_usec - s2->tv_usec;
d->tv_sec = s1->tv_sec - s2->tv_sec;
} else {
d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec;
d->tv_sec = s1->tv_sec - s2->tv_sec - 1;
}
}
unsigned
timeval_minus_msec(const struct timeval *s1, const struct timeval *s2)
{
if(s1->tv_sec < s2->tv_sec)
return 0;
/* Avoid overflow. */
if(s1->tv_sec - s2->tv_sec > 2000000)
return 2000000000;
if(s1->tv_sec > s2->tv_sec)
return
(unsigned)((unsigned)(s1->tv_sec - s2->tv_sec) * 1000 +
((int)s1->tv_usec - s2->tv_usec) / 1000);
if(s1->tv_usec <= s2->tv_usec)
return 0;
return (unsigned)(s1->tv_usec - s2->tv_usec) / 1000u;
}
/* d = s + msecs */
void
timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs)
{
int usecs;
d->tv_sec = s->tv_sec + msecs / 1000;
usecs = s->tv_usec + (msecs % 1000) * 1000;
if(usecs < 1000000) {
d->tv_usec = usecs;
} else {
d->tv_usec = usecs - 1000000;
d->tv_sec++;
}
}
void
set_timeout(struct timeval *timeout, int msecs)
{
timeval_add_msec(timeout, &babel_now, roughly(msecs));
}
/* returns <0 if "s1" < "s2", etc. */
int
timeval_compare(const struct timeval *s1, const struct timeval *s2)
{
if(s1->tv_sec < s2->tv_sec)
return -1;
else if(s1->tv_sec > s2->tv_sec)
return 1;
else if(s1->tv_usec < s2->tv_usec)
return -1;
else if(s1->tv_usec > s2->tv_usec)
return 1;
else
return 0;
}
/* set d at min(d, s) */
/* {0, 0} represents infinity */
void
timeval_min(struct timeval *d, const struct timeval *s)
{
if(s->tv_sec == 0)
return;
if(d->tv_sec == 0 || timeval_compare(d, s) > 0) {
*d = *s;
}
}
/* set d to min(d, x) with x in [secs, secs+1] */
void
timeval_min_sec(struct timeval *d, time_t secs)
{
if(d->tv_sec == 0 || d->tv_sec > secs) {
d->tv_sec = secs;
d->tv_usec = random() % 1000000;
}
}
/* parse a float value in second and return the corresponding mili-seconds.
For example:
parse_msec("12.342345") returns 12342 */
int
parse_msec(const char *string)
{
unsigned int in, fl;
int i, j;
in = fl = 0;
i = 0;
while(string[i] == ' ' || string[i] == '\t')
i++;
while(string[i] >= '0' && string[i] <= '9') {
in = in * 10 + string[i] - '0';
i++;
}
if(string[i] == '.') {
i++;
j = 0;
while(string[i] >= '0' && string[i] <= '9') {
fl = fl * 10 + string[i] - '0';
i++;
j++;
}
while(j > 3) {
fl /= 10;
j--;
}
while(j < 3) {
fl *= 10;
j++;
}
}
while(string[i] == ' ' || string[i] == '\t')
i++;
if(string[i] == '\0')
return in * 1000 + fl;
return -1;
}
int
in_prefix(const unsigned char *restrict address,
const unsigned char *restrict prefix, unsigned char plen)
{
unsigned char m;
if(plen > 128)
plen = 128;
if(memcmp(address, prefix, plen / 8) != 0)
return 0;
if(plen % 8 == 0)
return 1;
m = 0xFF << (8 - (plen % 8));
return ((address[plen / 8] & m) == (prefix[plen / 8] & m));
}
unsigned char *
mask_prefix(unsigned char *restrict ret,
const unsigned char *restrict prefix, unsigned char plen)
{
if(plen >= 128) {
memcpy(ret, prefix, 16);
return ret;
}
memset(ret, 0, 16);
memcpy(ret, prefix, plen / 8);
if(plen % 8 != 0)
ret[plen / 8] =
(prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF));
return ret;
}
static const unsigned char v4prefix[16] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
static const unsigned char llprefix[16] =
{0xFE, 0x80};
const char *
format_address(const unsigned char *address)
{
static char buf[4][INET6_ADDRSTRLEN];
static int i = 0;
i = (i + 1) % 4;
if(v4mapped(address))
inet_ntop(AF_INET, address + 12, buf[i], INET6_ADDRSTRLEN);
else
inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN);
return buf[i];
}
const char *
format_prefix(const unsigned char *prefix, unsigned char plen)
{
static char buf[4][INET6_ADDRSTRLEN + 4];
static int i = 0;
int n;
i = (i + 1) % 4;
if(plen >= 96 && v4mapped(prefix)) {
inet_ntop(AF_INET, prefix + 12, buf[i], INET6_ADDRSTRLEN);
n = strlen(buf[i]);
snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen - 96);
} else {
inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN);
n = strlen(buf[i]);
snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen);
}
return buf[i];
}
const char *
format_eui64(const unsigned char *eui)
{
static char buf[4][28];
static int i = 0;
i = (i + 1) % 4;
snprintf(buf[i], 28, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
eui[0], eui[1], eui[2], eui[3],
eui[4], eui[5], eui[6], eui[7]);
return buf[i];
}
const char *format_bool(const int b) {
return b ? "true" : "false";
}
int
parse_address(const char *address, unsigned char *addr_r, int *af_r)
{
struct in_addr ina;
struct in6_addr ina6;
int rc;
rc = inet_pton(AF_INET, address, &ina);
if(rc > 0) {
memcpy(addr_r, v4prefix, 12);
memcpy(addr_r + 12, &ina, 4);
if(af_r) *af_r = AF_INET;
return 0;
}
rc = inet_pton(AF_INET6, address, &ina6);
if(rc > 0) {
memcpy(addr_r, &ina6, 16);
if(af_r) *af_r = AF_INET6;
return 0;
}
return -1;
}
int
parse_eui64(const char *eui, unsigned char *eui_r)
{
int n;
n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3],
&eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]);
if(n == 8)
return 0;
n = sscanf(eui, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx",
&eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3],
&eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]);
if(n == 8)
return 0;
n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&eui_r[0], &eui_r[1], &eui_r[2],
&eui_r[5], &eui_r[6], &eui_r[7]);
if(n == 6) {
eui_r[3] = 0xFF;
eui_r[4] = 0xFE;
return 0;
}
return -1;
}
int
wait_for_fd(int direction, int fd, int msecs)
{
fd_set fds;
int rc;
struct timeval tv;
tv.tv_sec = msecs / 1000;
tv.tv_usec = (msecs % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if(direction)
rc = select(fd + 1, NULL, &fds, NULL, &tv);
else
rc = select(fd + 1, &fds, NULL, NULL, &tv);
return rc;
}
int
martian_prefix(const unsigned char *prefix, int plen)
{
return
(plen >= 8 && prefix[0] == 0xFF) ||
(plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) ||
(plen >= 128 && memcmp(prefix, zeroes, 15) == 0 &&
(prefix[15] == 0 || prefix[15] == 1)) ||
(plen >= 96 && v4mapped(prefix) &&
((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) ||
(plen >= 100 && (prefix[12] & 0xE0) == 0xE0)));
}
int
linklocal(const unsigned char *address)
{
return memcmp(address, llprefix, 8) == 0;
}
int
v4mapped(const unsigned char *address)
{
return memcmp(address, v4prefix, 12) == 0;
}
void
v4tov6(unsigned char *dst, const unsigned char *src)
{
memcpy(dst, v4prefix, 12);
memcpy(dst + 12, src, 4);
}
void
inaddr_to_uchar(unsigned char *dest, const struct in_addr *src)
{
memcpy(dest, v4prefix, 12);
memcpy(dest + 12, src, 4);
assert(v4mapped(dest));
}
void
uchar_to_inaddr(struct in_addr *dest, const unsigned char *src)
{
assert(v4mapped(src));
memcpy(dest, src + 12, 4);
}
void
in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src)
{
memcpy(dest, src, 16);
}
void
uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src)
{
memcpy(dest, src, 16);
}
int
daemonise()
{
int rc;
fflush(stdout);
fflush(stderr);
rc = fork();
if(rc < 0)
return -1;
if(rc > 0)
exit(0);
rc = setsid();
if(rc < 0)
return -1;
return 1;
}

165
babeld/util.h Normal file
View File

@ -0,0 +1,165 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "babeld.h"
#include "babel_main.h"
#include "log.h"
#if defined(i386) || defined(__mc68020__) || defined(__x86_64__)
#define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0)
#define DO_NTOHL(_d, _s) do{ _d = ntohl(*(const unsigned*)(_s)); } while(0)
#define DO_HTONS(_d, _s) do{ *(unsigned short*)(_d) = htons(_s); } while(0)
#define DO_HTONL(_d, _s) do{ *(unsigned*)(_d) = htonl(_s); } while(0)
/* Some versions of gcc seem to be buggy, and ignore the packed attribute.
Disable this code until the issue is clarified. */
/* #elif defined __GNUC__*/
#elif 0
struct __us { unsigned short x __attribute__((packed)); };
#define DO_NTOHS(_d, _s) \
do { _d = ntohs(((const struct __us*)(_s))->x); } while(0)
#define DO_HTONS(_d, _s) \
do { ((struct __us*)(_d))->x = htons(_s); } while(0)
#else
#define DO_NTOHS(_d, _s) \
do { short _dd; \
memcpy(&(_dd), (_s), 2); \
_d = ntohs(_dd); } while(0)
#define DO_HTONS(_d, _s) \
do { unsigned short _dd; \
_dd = htons(_s); \
memcpy((_d), &(_dd), 2); } while(0)
#endif
static inline int
seqno_compare(unsigned short s1, unsigned short s2)
{
if(s1 == s2)
return 0;
else
return ((s2 - s1) & 0x8000) ? 1 : -1;
}
static inline short
seqno_minus(unsigned short s1, unsigned short s2)
{
return (short)((s1 - s2) & 0xFFFF);
}
static inline unsigned short
seqno_plus(unsigned short s, int plus)
{
return ((s + plus) & 0xFFFF);
}
unsigned roughly(unsigned value);
void timeval_minus(struct timeval *d,
const struct timeval *s1, const struct timeval *s2);
unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2)
ATTRIBUTE ((pure));
void timeval_add_msec(struct timeval *d,
const struct timeval *s, const int msecs);
void set_timeout (struct timeval *timeout, int msecs);
int timeval_compare(const struct timeval *s1, const struct timeval *s2)
ATTRIBUTE ((pure));
void timeval_min(struct timeval *d, const struct timeval *s);
void timeval_min_sec(struct timeval *d, time_t secs);
int parse_msec(const char *string) ATTRIBUTE ((pure));
int in_prefix(const unsigned char *restrict address,
const unsigned char *restrict prefix, unsigned char plen)
ATTRIBUTE ((pure));
unsigned char *mask_prefix(unsigned char *restrict ret,
const unsigned char *restrict prefix,
unsigned char plen);
const char *format_address(const unsigned char *address);
const char *format_prefix(const unsigned char *address, unsigned char prefix);
const char *format_eui64(const unsigned char *eui);
const char *format_bool(const int b);
int parse_address(const char *address, unsigned char *addr_r, int *af_r);
int parse_eui64(const char *eui, unsigned char *eui_r);
int wait_for_fd(int direction, int fd, int msecs);
int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure));
int linklocal(const unsigned char *address) ATTRIBUTE ((pure));
int v4mapped(const unsigned char *address) ATTRIBUTE ((pure));
void v4tov6(unsigned char *dst, const unsigned char *src);
void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src);
void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src);
void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src);
void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src);
int daemonise(void);
/* If debugging is disabled, we want to avoid calling format_address
for every omitted debugging message. So debug is a macro. But
vararg macros are not portable. */
#if defined NO_DEBUG
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define debugf(...) do {} while(0)
#elif defined __GNUC__
#define debugf(_args...) do {} while(0)
#else
static inline void debugf(int level, const char *format, ...) { return; }
#endif
#else /* NO_DEBUG */
/* some levels */
#define BABEL_DEBUG_COMMON (1 << 0)
#define BABEL_DEBUG_KERNEL (1 << 1)
#define BABEL_DEBUG_FILTER (1 << 2)
#define BABEL_DEBUG_TIMEOUT (1 << 3)
#define BABEL_DEBUG_IF (1 << 4)
#define BABEL_DEBUG_ROUTE (1 << 5)
#define BABEL_DEBUG_ALL (0xFFFF)
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define debugf(level, ...) \
do { \
if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \
} while(0)
#elif defined __GNUC__
#define debugf(level, _args...) \
do { \
if(UNLIKELY(debug & level)) zlog_debug(_args); \
} while(0)
#else
static inline void debugf(int level, const char *format, ...) { return; }
#endif
#endif /* NO_DEBUG */

237
babeld/xroute.c Normal file
View File

@ -0,0 +1,237 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <zebra.h>
#include "if.h"
#include "log.h"
#include "babeld.h"
#include "kernel.h"
#include "neighbour.h"
#include "message.h"
#include "route.h"
#include "xroute.h"
#include "util.h"
#include "babel_interface.h"
static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
unsigned short metric, unsigned int ifindex,
int proto, int send_updates);
static struct xroute *xroutes;
static int numxroutes = 0, maxxroutes = 0;
/* Add redistributed route to Babel table. */
int
babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex, struct in_addr *nexthop)
{
unsigned char uchar_prefix[16];
inaddr_to_uchar(uchar_prefix, &prefix->prefix);
debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra.");
xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96,
api->metric, ifindex, 0, 1);
return 0;
}
/* Remove redistributed route from Babel table. */
int
babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex)
{
unsigned char uchar_prefix[16];
struct xroute *xroute = NULL;
inaddr_to_uchar(uchar_prefix, &prefix->prefix);
xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
flush_xroute(xroute);
}
return 0;
}
/* Add redistributed route to Babel table. */
int
babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex, struct in6_addr *nexthop)
{
unsigned char uchar_prefix[16];
in6addr_to_uchar(uchar_prefix, &prefix->prefix);
debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra.");
xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex,
0, 1);
return 0;
}
/* Remove redistributed route from Babel table. */
int
babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex)
{
unsigned char uchar_prefix[16];
struct xroute *xroute = NULL;
in6addr_to_uchar(uchar_prefix, &prefix->prefix);
xroute = find_xroute(uchar_prefix, prefix->prefixlen);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra).");
flush_xroute(xroute);
}
return 0;
}
struct xroute *
find_xroute(const unsigned char *prefix, unsigned char plen)
{
int i;
for(i = 0; i < numxroutes; i++) {
if(xroutes[i].plen == plen &&
memcmp(xroutes[i].prefix, prefix, 16) == 0)
return &xroutes[i];
}
return NULL;
}
void
flush_xroute(struct xroute *xroute)
{
int i;
i = xroute - xroutes;
assert(i >= 0 && i < numxroutes);
if(i != numxroutes - 1)
memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute));
numxroutes--;
VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
if(numxroutes == 0) {
free(xroutes);
xroutes = NULL;
maxxroutes = 0;
} else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) {
struct xroute *new_xroutes;
int n = maxxroutes / 2;
new_xroutes = realloc(xroutes, n * sizeof(struct xroute));
if(new_xroutes == NULL)
return;
xroutes = new_xroutes;
maxxroutes = n;
}
}
static int
add_xroute(unsigned char prefix[16], unsigned char plen,
unsigned short metric, unsigned int ifindex, int proto)
{
struct xroute *xroute = find_xroute(prefix, plen);
if(xroute) {
if(xroute->metric <= metric)
return 0;
xroute->metric = metric;
return 1;
}
if(numxroutes >= maxxroutes) {
struct xroute *new_xroutes;
int n = maxxroutes < 1 ? 8 : 2 * maxxroutes;
new_xroutes = xroutes == NULL ?
malloc(n * sizeof(struct xroute)) :
realloc(xroutes, n * sizeof(struct xroute));
if(new_xroutes == NULL)
return -1;
maxxroutes = n;
xroutes = new_xroutes;
}
memcpy(xroutes[numxroutes].prefix, prefix, 16);
xroutes[numxroutes].plen = plen;
xroutes[numxroutes].metric = metric;
xroutes[numxroutes].ifindex = ifindex;
xroutes[numxroutes].proto = proto;
numxroutes++;
return 1;
}
/* Returns an overestimate of the number of xroutes. */
int
xroutes_estimate()
{
return numxroutes;
}
void
for_all_xroutes(void (*f)(struct xroute*, void*), void *closure)
{
int i;
for(i = 0; i < numxroutes; i++)
(*f)(&xroutes[i], closure);
}
/* add an xroute, verifying some conditions; return 0 if there is no changes */
static int
xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
unsigned short metric, unsigned int ifindex,
int proto, int send_updates)
{
int rc;
if(martian_prefix(prefix, plen))
return 0;
metric = redistribute_filter(prefix, plen, ifindex, proto);
if(metric < INFINITY) {
rc = add_xroute(prefix, plen, metric, ifindex, proto);
if(rc > 0) {
struct babel_route *route;
route = find_installed_route(prefix, plen);
if(route) {
if(allow_duplicates < 0 ||
metric < allow_duplicates)
uninstall_route(route);
}
if(send_updates)
send_update(NULL, 0, prefix, plen);
return 1;
}
}
return 0;
}

59
babeld/xroute.h Normal file
View File

@ -0,0 +1,59 @@
/*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
struct xroute {
unsigned char prefix[16];
unsigned char plen;
unsigned short metric;
unsigned int ifindex;
int proto;
};
struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen);
void flush_xroute(struct xroute *xroute);
int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex, struct in_addr *nexthop);
int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex);
int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex, struct in6_addr *nexthop);
int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex);
int xroutes_estimate(void);
void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure);

View File

@ -1,15 +0,0 @@
Makefile
Makefile.in
*.o
bgpd
bgp_btoa
bgpd.conf
tags
TAGS
.deps
.nfs*
*.lo
*.la
*.libs
.arch-inventory
.arch-ids

View File

@ -140,13 +140,13 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
baa->refcnt--;
if (baa->refcnt && baa->attr)
bgp_attr_unintern (baa->attr);
bgp_attr_unintern (&baa->attr);
else
{
if (baa->attr)
{
hash_release (hash, baa);
bgp_attr_unintern (baa->attr);
bgp_attr_unintern (&baa->attr);
}
baa_free (baa);
}
@ -319,7 +319,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
struct peer *peer, afi_t afi, safi_t safi)
{
if (adj->attr)
bgp_attr_unintern (adj->attr);
bgp_attr_unintern (&adj->attr);
if (adj->adv)
bgp_advertise_clean (peer, adj, afi, safi);
@ -339,7 +339,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
{
if (adj->attr != attr)
{
bgp_attr_unintern (adj->attr);
bgp_attr_unintern (&adj->attr);
adj->attr = bgp_attr_intern (attr);
}
return;
@ -355,7 +355,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
void
bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
{
bgp_attr_unintern (bai->attr);
bgp_attr_unintern (&bai->attr);
BGP_ADJ_IN_DEL (rn, bai);
peer_unlock (bai->peer); /* adj_in peer reference */
XFREE (MTYPE_BGP_ADJ_IN, bai);

View File

@ -91,13 +91,13 @@ static struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
static inline as_t *
static as_t *
assegment_data_new (int num)
{
return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
}
static inline void
static void
assegment_data_free (as_t *asdata)
{
XFREE (MTYPE_AS_SEG_DATA,asdata);
@ -340,19 +340,21 @@ aspath_free (struct aspath *aspath)
/* Unintern aspath from AS path bucket. */
void
aspath_unintern (struct aspath *aspath)
aspath_unintern (struct aspath **aspath)
{
struct aspath *ret;
struct aspath *asp = *aspath;
if (aspath->refcnt)
aspath->refcnt--;
if (asp->refcnt)
asp->refcnt--;
if (aspath->refcnt == 0)
if (asp->refcnt == 0)
{
/* This aspath must exist in aspath hash table. */
ret = hash_release (ashash, aspath);
ret = hash_release (ashash, asp);
assert (ret != NULL);
aspath_free (aspath);
aspath_free (asp);
*aspath = NULL;
}
}
@ -671,80 +673,79 @@ aspath_hash_alloc (void *arg)
return aspath;
}
/* parse as-segment byte stream in struct assegment
*
* Returns NULL if the AS_PATH or AS4_PATH is not valid.
*/
static struct assegment *
assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)
/* parse as-segment byte stream in struct assegment */
static int
assegments_parse (struct stream *s, size_t length,
struct assegment **result, int use32bit)
{
struct assegment_header segh;
struct assegment *seg, *prev = NULL, *head = NULL;
size_t bytes = 0;
assert (length > 0); /* does not expect empty AS_PATH or AS4_PATH */
/* empty aspath (ie iBGP or somesuch) */
if (length == 0)
return 0;
if (BGP_DEBUG (as4, AS4_SEGMENT))
zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
(unsigned long) length);
/* basic checks */
if ((STREAM_READABLE(s) < length)
|| (STREAM_READABLE(s) < AS_HEADER_SIZE)
|| (length % AS16_VALUE_SIZE ))
return -1;
/* double check that length does not exceed stream */
if (STREAM_READABLE(s) < length)
return NULL;
/* deal with each segment in turn */
while (length > 0)
while (bytes < length)
{
int i;
size_t seg_size;
/* softly softly, get the header first on its own */
if (length < AS_HEADER_SIZE)
if ((length - bytes) <= AS_HEADER_SIZE)
{
if (head)
assegment_free_all (head);
return NULL;
return -1;
}
/* softly softly, get the header first on its own */
segh.type = stream_getc (s);
segh.length = stream_getc (s);
seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
/* includes the header bytes */
if (BGP_DEBUG (as4, AS4_SEGMENT))
zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
segh.type, segh.length);
/* check it.. */
if ( ((bytes + seg_size) > length)
/* 1771bis 4.3b: seg length contains one or more */
|| (segh.length == 0)
/* Paranoia in case someone changes type of segment length.
* Shift both values by 0x10 to make the comparison operate
* on more, than 8 bits (otherwise it's a warning, bug #564).
*/
|| ((sizeof segh.length > 1)
&& (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
{
if (head)
assegment_free_all (head);
return -1;
}
switch (segh.type)
{
case AS_SEQUENCE:
case AS_SET:
break ;
case AS_CONFED_SEQUENCE:
case AS_CONFED_SET:
if (!as4_path)
break;
/* RFC4893 3: "invalid for the AS4_PATH attribute" */
/* fall through */
default: /* reject unknown or invalid AS_PATH segment types */
seg_size = 0 ;
}
/* Stop now if segment is not valid (discarding anything collected to date)
*
* RFC4271 4.3, Path Attributes, b) AS_PATH:
*
* "path segment value field contains one or more AS numbers"
*/
if ((seg_size == 0) || (seg_size > length) || (segh.length == 0))
{
default:
if (head)
assegment_free_all (head);
return NULL;
return -1;
}
length -= seg_size ;
/* now its safe to trust lengths */
seg = assegment_new (segh.type, segh.length);
@ -756,52 +757,47 @@ assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)
for (i = 0; i < segh.length; i++)
seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
bytes += seg_size;
if (BGP_DEBUG (as4, AS4_SEGMENT))
zlog_debug ("[AS4SEG] Parse aspath segment: length left: %lu",
(unsigned long) length);
zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
(unsigned long) bytes);
prev = seg;
}
return assegment_normalise (head);
*result = assegment_normalise (head);
return 0;
}
/* AS path parse function -- parses AS_PATH and AS4_PATH attributes
*
* Requires: s -- stream, currently positioned before first segment
* of AS_PATH or AS4_PATH (ie after attribute header)
* length -- length of the value of the AS_PATH or AS4_PATH
* use32bit -- true <=> 4Byte ASN, otherwise 2Byte ASN
* as4_path -- true <=> AS4_PATH, otherwise AS_PATH
*
* Returns: if valid: address of struct aspath in the hash of known aspaths,
* with reference count incremented.
* else: NULL
*
* NB: empty AS path (length == 0) is valid. The returned struct aspath will
* have segments == NULL and str == zero length string (unique).
/* AS path parse function. pnt is a pointer to byte stream and length
is length of byte stream. If there is same AS path in the the AS
path hash then return it else make new AS path structure.
On error NULL is returned.
*/
struct aspath *
aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path)
aspath_parse (struct stream *s, size_t length, int use32bit)
{
struct aspath as;
struct aspath *find;
/* Parse each segment and construct normalised list of struct assegment */
memset (&as, 0, sizeof (struct aspath));
if (length != 0)
{
as.segments = assegments_parse (s, length, use32bit, as4_path);
/* If length is odd it's malformed AS path. */
/* Nit-picking: if (use32bit == 0) it is malformed if odd,
* otherwise its malformed when length is larger than 2 and (length-2)
* is not dividable by 4.
* But... this time we're lazy
*/
if (length % AS16_VALUE_SIZE )
return NULL;
if (as.segments == NULL)
return NULL ; /* Invalid AS_PATH or AS4_PATH */
} ;
memset (&as, 0, sizeof (struct aspath));
if (assegments_parse (s, length, &as.segments, use32bit) < 0)
return NULL;
/* If already same aspath exist then return it. */
find = hash_get (ashash, &as, aspath_hash_alloc);
assert(find) ; /* valid aspath, so must find or create */
/* aspath_hash_alloc dupes segments too. that probably could be
* optimised out.
*/
@ -809,12 +805,14 @@ aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path)
if (as.str)
XFREE (MTYPE_AS_STR, as.str);
if (! find)
return NULL;
find->refcnt++;
return find;
}
static inline void
static void
assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
{
int i;
@ -832,7 +830,7 @@ assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
}
}
static inline size_t
static size_t
assegment_header_put (struct stream *s, u_char type, int length)
{
size_t lenp;
@ -1632,7 +1630,7 @@ aspath_segment_add (struct aspath *as, int type)
struct aspath *
aspath_empty (void)
{
return aspath_parse (NULL, 0, 1, 0); /* 32Bit ;-) not AS4_PATH */
return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
}
struct aspath *

View File

@ -65,7 +65,7 @@ struct aspath
/* Prototypes. */
extern void aspath_init (void);
extern void aspath_finish (void);
extern struct aspath *aspath_parse (struct stream *, size_t, int, int);
extern struct aspath *aspath_parse (struct stream *, size_t, int);
extern struct aspath *aspath_dup (struct aspath *);
extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *);
extern struct aspath *aspath_prepend (struct aspath *, struct aspath *);
@ -80,7 +80,7 @@ extern struct aspath *aspath_empty_get (void);
extern struct aspath *aspath_str2aspath (const char *);
extern void aspath_free (struct aspath *);
extern struct aspath *aspath_intern (struct aspath *);
extern void aspath_unintern (struct aspath *);
extern void aspath_unintern (struct aspath **);
extern const char *aspath_print (struct aspath *);
extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *);
extern void aspath_print_all_vty (struct vty *);

File diff suppressed because it is too large Load Diff

View File

@ -132,17 +132,25 @@ struct transit
#define ATTR_FLAG_BIT(X) (1 << ((X) - 1))
typedef enum {
BGP_ATTR_PARSE_PROCEED = 0,
BGP_ATTR_PARSE_ERROR = -1,
BGP_ATTR_PARSE_WITHDRAW = -2,
} bgp_attr_parse_ret_t;
/* Prototypes. */
extern void bgp_attr_init (void);
extern void bgp_attr_finish (void);
extern int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t,
struct bgp_nlri *, struct bgp_nlri *);
extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *,
bgp_size_t, struct bgp_nlri *,
struct bgp_nlri *);
extern int bgp_attr_check (struct peer *, struct attr *);
extern struct attr_extra *bgp_attr_extra_get (struct attr *);
extern void bgp_attr_extra_free (struct attr *);
extern void bgp_attr_dup (struct attr *, struct attr *);
extern struct attr *bgp_attr_intern (struct attr *attr);
extern void bgp_attr_unintern (struct attr *);
extern void bgp_attr_unintern_sub (struct attr *);
extern void bgp_attr_unintern (struct attr **);
extern void bgp_attr_flush (struct attr *);
extern struct attr *bgp_attr_default_set (struct attr *attr, u_char);
extern struct attr *bgp_attr_default_intern (u_char);
@ -171,9 +179,19 @@ extern void cluster_unintern (struct cluster_list *);
/* Transit attribute prototypes. */
void transit_unintern (struct transit *);
/* Exported for unit-test purposes only */
extern int bgp_mp_reach_parse (struct peer *, bgp_size_t, struct attr *,
/* Below exported for unit-test purposes only */
struct bgp_attr_parser_args {
struct peer *peer;
bgp_size_t length; /* attribute data length; */
bgp_size_t total; /* total length, inc header */
struct attr *attr;
u_int8_t type;
u_int8_t flags;
u_char *startp;
};
extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *);
extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *);
extern int bgp_mp_unreach_parse (struct peer *, bgp_size_t, struct bgp_nlri *);
#endif /* _QUAGGA_BGP_ATTR_H */

View File

@ -70,7 +70,7 @@ community_entry_free (struct community_entry *entry)
if (entry->config)
XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
if (entry->u.ecom)
ecommunity_free (entry->u.ecom);
ecommunity_free (&entry->u.ecom);
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
@ -806,7 +806,7 @@ extcommunity_list_unset (struct community_list_handler *ch,
entry = community_list_entry_lookup (list, str, direct);
if (ecom)
ecommunity_free (ecom);
ecommunity_free (&ecom);
if (regex)
bgp_regex_free (regex);

View File

@ -321,21 +321,22 @@ community_intern (struct community *com)
/* Free community attribute. */
void
community_unintern (struct community *com)
community_unintern (struct community **com)
{
struct community *ret;
if (com->refcnt)
com->refcnt--;
if ((*com)->refcnt)
(*com)->refcnt--;
/* Pull off from hash. */
if (com->refcnt == 0)
if ((*com)->refcnt == 0)
{
/* Community value com must exist in hash. */
ret = (struct community *) hash_release (comhash, com);
ret = (struct community *) hash_release (comhash, *com);
assert (ret != NULL);
community_free (com);
community_free (*com);
*com = NULL;
}
}

View File

@ -57,7 +57,7 @@ extern void community_free (struct community *);
extern struct community *community_uniq_sort (struct community *);
extern struct community *community_parse (u_int32_t *, u_short);
extern struct community *community_intern (struct community *);
extern void community_unintern (struct community *);
extern void community_unintern (struct community **);
extern char *community_str (struct community *);
extern unsigned int community_hash_make (struct community *);
extern struct community *community_str2com (const char *);

View File

@ -105,6 +105,7 @@ static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX;
static const struct message bgp_notify_open_msg[] =
{
{ BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" },
{ BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"},
{ BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"},
@ -117,6 +118,7 @@ static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX;
static const struct message bgp_notify_update_msg[] =
{
{ BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"},
{ BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"},
{ BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"},
@ -133,6 +135,7 @@ static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX;
static const struct message bgp_notify_cease_msg[] =
{
{ BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"},
{ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"},
{ BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"},
@ -146,6 +149,7 @@ static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX;
static const struct message bgp_notify_capability_msg[] =
{
{ BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" },
{ BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"},
{ BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"},

View File

@ -42,13 +42,14 @@ ecommunity_new (void)
/* Allocate ecommunities. */
void
ecommunity_free (struct ecommunity *ecom)
ecommunity_free (struct ecommunity **ecom)
{
if (ecom->val)
XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val);
if (ecom->str)
XFREE (MTYPE_ECOMMUNITY_STR, ecom->str);
XFREE (MTYPE_ECOMMUNITY, ecom);
if ((*ecom)->val)
XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
if ((*ecom)->str)
XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str);
XFREE (MTYPE_ECOMMUNITY, *ecom);
ecom = NULL;
}
/* Add a new Extended Communities value to Extended Communities
@ -197,7 +198,7 @@ ecommunity_intern (struct ecommunity *ecom)
find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
if (find != ecom)
ecommunity_free (ecom);
ecommunity_free (&ecom);
find->refcnt++;
@ -209,18 +210,18 @@ ecommunity_intern (struct ecommunity *ecom)
/* Unintern Extended Communities Attribute. */
void
ecommunity_unintern (struct ecommunity *ecom)
ecommunity_unintern (struct ecommunity **ecom)
{
struct ecommunity *ret;
if (ecom->refcnt)
ecom->refcnt--;
if ((*ecom)->refcnt)
(*ecom)->refcnt--;
/* Pull off from hash. */
if (ecom->refcnt == 0)
if ((*ecom)->refcnt == 0)
{
/* Extended community must be in the hash. */
ret = (struct ecommunity *) hash_release (ecomhash, ecom);
ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
assert (ret != NULL);
ecommunity_free (ecom);
@ -516,7 +517,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
if (! keyword_included || keyword)
{
if (ecom)
ecommunity_free (ecom);
ecommunity_free (&ecom);
return NULL;
}
keyword = 1;
@ -536,7 +537,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
if (! keyword)
{
if (ecom)
ecommunity_free (ecom);
ecommunity_free (&ecom);
return NULL;
}
keyword = 0;
@ -549,7 +550,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
case ecommunity_token_unknown:
default:
if (ecom)
ecommunity_free (ecom);
ecommunity_free (&ecom);
return NULL;
}
}
@ -619,6 +620,13 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
for (i = 0; i < ecom->size; i++)
{
/* Make it sure size is enough. */
while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
{
str_size *= 2;
str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
}
/* Space between each value. */
if (! first)
str_buf[str_pnt++] = ' ';
@ -662,13 +670,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
break;
}
/* Make it sure size is enough. */
while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
{
str_size *= 2;
str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
}
/* Put string into buffer. */
if (encode == ECOMMUNITY_ENCODE_AS4)
{

View File

@ -67,13 +67,13 @@ struct ecommunity_val
extern void ecommunity_init (void);
extern void ecommunity_finish (void);
extern void ecommunity_free (struct ecommunity *);
extern void ecommunity_free (struct ecommunity **);
extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short);
extern struct ecommunity *ecommunity_dup (struct ecommunity *);
extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);
extern struct ecommunity *ecommunity_intern (struct ecommunity *);
extern int ecommunity_cmp (const void *, const void *);
extern void ecommunity_unintern (struct ecommunity *);
extern void ecommunity_unintern (struct ecommunity **);
extern unsigned int ecommunity_hash_make (void *);
extern struct ecommunity *ecommunity_str2com (const char *, int, int);
extern char *ecommunity_ecom2str (struct ecommunity *, int);

View File

@ -355,7 +355,7 @@ bgp_graceful_restart_timer_expire (struct thread *thread)
/* NSF delete stale route */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
@ -388,7 +388,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
/* NSF delete stale route */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
@ -481,7 +481,7 @@ bgp_stop (struct peer *peer)
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
peer->nsf[afi][safi] = 0;
}
@ -799,7 +799,7 @@ bgp_establish (struct peer *peer)
/* graceful restart */
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
{
if (peer->afc_nego[afi][safi]
&& CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)

View File

@ -54,6 +54,7 @@ static const struct option longopts[] =
{ "daemon", no_argument, NULL, 'd'},
{ "config_file", required_argument, NULL, 'f'},
{ "pid_file", required_argument, NULL, 'i'},
{ "socket", required_argument, NULL, 'z'},
{ "bgp_port", required_argument, NULL, 'p'},
{ "listenon", required_argument, NULL, 'l'},
{ "vty_addr", required_argument, NULL, 'A'},
@ -119,6 +120,7 @@ static zebra_capabilities_t _caps_p [] =
{
ZCAP_BIND,
ZCAP_NET_RAW,
ZCAP_NET_ADMIN,
};
struct zebra_privs_t bgpd_privs =
@ -149,6 +151,7 @@ redistribution between different routing protocols.\n\n\
-d, --daemon Runs in daemon mode\n\
-f, --config_file Set configuration file name\n\
-i, --pid_file Set process identifier file name\n\
-z, --socket Set path of zebra socket\n\
-p, --bgp_port Set bgp protocol's port number\n\
-l, --listenon Listen on specified address (implies -n)\n\
-A, --vty_addr Set vty's bind address\n\
@ -196,6 +199,7 @@ sigint (void)
if (! retain_mode)
bgp_terminate ();
zprivs_terminate (&bgpd_privs);
bgp_exit (0);
}
@ -335,7 +339,7 @@ main (int argc, char **argv)
/* Command line argument treatment. */
while (1)
{
opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vC", longopts, 0);
opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0);
if (opt == EOF)
break;
@ -353,6 +357,9 @@ main (int argc, char **argv)
case 'i':
pid_file = optarg;
break;
case 'z':
zclient_serv_path_set (optarg);
break;
case 'p':
tmp_port = atoi (optarg);
if (tmp_port <= 0 || tmp_port > 0xffff)

View File

@ -233,9 +233,13 @@ str2tag (const char *str, u_char *tag)
char *endptr;
u_int32_t t;
if (*str == '-')
return 0;
errno = 0;
l = strtoul (str, &endptr, 10);
if (*endptr == '\0' || l == ULONG_MAX || l > UINT32_MAX)
if (*endptr != '\0' || errno || l > UINT32_MAX)
return 0;
t = (u_int32_t) l;

View File

@ -238,46 +238,36 @@ bgp_bind (struct peer *peer)
}
static int
bgp_bind_address (int sock, struct in_addr *addr)
bgp_update_address (struct interface *ifp, const union sockunion *dst,
union sockunion *addr)
{
int ret;
struct sockaddr_in local;
memset (&local, 0, sizeof (struct sockaddr_in));
local.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
local.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
if ( bgpd_privs.change (ZPRIVS_RAISE) )
zlog_err ("bgp_bind_address: could not raise privs");
ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
if (ret < 0)
;
if (bgpd_privs.change (ZPRIVS_LOWER) )
zlog_err ("bgp_bind_address: could not lower privs");
return 0;
}
static struct in_addr *
bgp_update_address (struct interface *ifp)
{
struct prefix_ipv4 *p;
struct prefix *p, *sel, *d;
struct connected *connected;
struct listnode *node;
int common;
d = sockunion2hostprefix (dst);
sel = NULL;
common = -1;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
{
p = (struct prefix_ipv4 *) connected->address;
if (p->family == AF_INET)
return &p->prefix;
p = connected->address;
if (p->family != d->family)
continue;
if (prefix_common_bits (p, d) > common)
{
sel = p;
common = prefix_common_bits (sel, d);
}
return NULL;
}
prefix_free (d);
if (!sel)
return 1;
prefix2sockunion (sel, addr);
return 0;
}
/* Update source selection. */
@ -285,7 +275,7 @@ static void
bgp_update_source (struct peer *peer)
{
struct interface *ifp;
struct in_addr *addr;
union sockunion addr;
/* Source is specified with interface name. */
if (peer->update_if)
@ -294,11 +284,10 @@ bgp_update_source (struct peer *peer)
if (! ifp)
return;
addr = bgp_update_address (ifp);
if (! addr)
if (bgp_update_address (ifp, &peer->su, &addr))
return;
bgp_bind_address (peer->fd, addr);
sockunion_bind (peer->fd, &addr, 0, &addr);
}
/* Source is specified with IP address. */
@ -328,8 +317,16 @@ bgp_connect (struct peer *peer)
sockopt_reuseport (peer->fd);
#ifdef IPTOS_PREC_INTERNETCONTROL
if (bgpd_privs.change (ZPRIVS_RAISE))
zlog_err ("%s: could not raise privs", __func__);
if (sockunion_family (&peer->su) == AF_INET)
setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
# ifdef HAVE_IPV6
else if (sockunion_family (&peer->su) == AF_INET6)
setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL);
# endif
if (bgpd_privs.change (ZPRIVS_LOWER))
zlog_err ("%s: could not lower privs", __func__);
#endif
if (peer->password)
@ -386,27 +383,24 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
sockopt_reuseaddr (sock);
sockopt_reuseport (sock);
if (bgpd_privs.change (ZPRIVS_RAISE))
zlog_err ("%s: could not raise privs", __func__);
#ifdef IPTOS_PREC_INTERNETCONTROL
if (sa->sa_family == AF_INET)
setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
# ifdef HAVE_IPV6
else if (sa->sa_family == AF_INET6)
setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
# endif
#endif
#ifdef IPV6_V6ONLY
/* Want only IPV6 on ipv6 socket (not mapped addresses) */
if (sa->sa_family == AF_INET6) {
int on = 1;
setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *) &on, sizeof (on));
}
#endif
if (bgpd_privs.change (ZPRIVS_RAISE) )
zlog_err ("bgp_socket: could not raise privs");
sockopt_v6only (sa->sa_family, sock);
ret = bind (sock, sa, salen);
en = errno;
if (bgpd_privs.change (ZPRIVS_LOWER))
zlog_err ("bgp_bind_address: could not lower privs");
zlog_err ("%s: could not lower privs", __func__);
if (ret < 0)
{

View File

@ -146,7 +146,7 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)
}
static int
bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,
bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
struct bgp_nexthop_cache *bnc2)
{
int i;
@ -171,7 +171,7 @@ bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,
/* If nexthop exists on connected network return 1. */
int
bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr)
bgp_nexthop_onlink (afi_t afi, struct attr *attr)
{
struct bgp_node *rn;
@ -253,15 +253,15 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
}
else
{
bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global);
if (bnc)
if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global)))
bnc = bnc_new ();
else
{
if (changed)
{
struct bgp_table *old;
struct bgp_node *oldrn;
struct bgp_nexthop_cache *oldbnc;
if (changed)
{
if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6])
old = cache2_table[AFI_IP6];
else
@ -270,9 +270,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
oldbnc = oldrn->info;
struct bgp_nexthop_cache *oldbnc = oldrn->info;
bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
@ -281,11 +281,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
}
}
}
else
{
bnc = bnc_new ();
bnc->valid = 0;
}
rn->info = bnc;
}
@ -344,15 +339,15 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
}
else
{
bnc = zlookup_query (addr);
if (bnc)
if (NULL == (bnc = zlookup_query (addr)))
bnc = bnc_new ();
else
{
if (changed)
{
struct bgp_table *old;
struct bgp_node *oldrn;
struct bgp_nexthop_cache *oldbnc;
if (changed)
{
if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP])
old = cache2_table[AFI_IP];
else
@ -361,9 +356,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
oldbnc = oldrn->info;
struct bgp_nexthop_cache *oldbnc = oldrn->info;
bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
@ -372,11 +367,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
}
}
}
else
{
bnc = bnc_new ();
bnc->valid = 0;
}
rn->info = bnc;
}
@ -462,7 +452,7 @@ bgp_scan (afi_t afi, safi_t safi)
metricchanged = 0;
if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1)
valid = bgp_nexthop_check_ebgp (afi, bi->attr);
valid = bgp_nexthop_onlink (afi, bi->attr);
else
valid = bgp_nexthop_lookup (afi, bi->peer, bi,
&changed, &metricchanged);
@ -1098,12 +1088,7 @@ zlookup_connect (struct thread *t)
if (zlookup->sock != -1)
return 0;
#ifdef HAVE_TCP_ZEBRA
zlookup->sock = zclient_socket ();
#else
zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
#endif /* HAVE_TCP_ZEBRA */
if (zlookup->sock < 0)
if (zclient_socket_connect (zlookup) < 0)
return -1;
return 0;
@ -1201,16 +1186,13 @@ ALIAS (no_bgp_scan_time,
"Configure background scanner interval\n"
"Scanner interval (seconds)\n")
DEFUN (show_ip_bgp_scan,
show_ip_bgp_scan_cmd,
"show ip bgp scan",
SHOW_STR
IP_STR
BGP_STR
"BGP scan status\n")
static int
show_ip_bgp_scan_tables (struct vty *vty, const char detail)
{
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
char buf[INET6_ADDRSTRLEN];
u_char i;
if (bgp_scan_thread)
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
@ -1223,28 +1205,57 @@ DEFUN (show_ip_bgp_scan,
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
{
vty_out (vty, " %s valid [IGP metric %d]%s",
inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE);
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV4:
vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
}
}
else
vty_out (vty, " %s invalid%s",
inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE);
inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
}
#ifdef HAVE_IPV6
{
char buf[BUFSIZ];
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
{
vty_out (vty, " %s valid [IGP metric %d]%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
bnc->metric, VTY_NEWLINE);
if (detail)
for (i = 0; i < bnc->nexthop_num; i++)
switch (bnc->nexthop[i].type)
{
case NEXTHOP_TYPE_IPV6:
vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
break;
default:
vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
}
}
else
vty_out (vty, " %s invalid%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
VTY_NEWLINE);
}
}
@ -1260,14 +1271,12 @@ DEFUN (show_ip_bgp_scan,
#ifdef HAVE_IPV6
{
char buf[BUFSIZ];
for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
if (rn->info != NULL)
vty_out (vty, " %s/%d%s",
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
rn->p.prefixlen,
VTY_NEWLINE);
}
@ -1276,6 +1285,29 @@ DEFUN (show_ip_bgp_scan,
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_scan,
show_ip_bgp_scan_cmd,
"show ip bgp scan",
SHOW_STR
IP_STR
BGP_STR
"BGP scan status\n")
{
return show_ip_bgp_scan_tables (vty, 0);
}
DEFUN (show_ip_bgp_scan_detail,
show_ip_bgp_scan_detail_cmd,
"show ip bgp scan detail",
SHOW_STR
IP_STR
BGP_STR
"BGP scan status\n"
"More detailed output\n")
{
return show_ip_bgp_scan_tables (vty, 1);
}
int
bgp_config_write_scan_time (struct vty *vty)
{
@ -1317,8 +1349,10 @@ bgp_scan_init (void)
install_element (BGP_NODE, &no_bgp_scan_time_cmd);
install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);
install_element (VIEW_NODE, &show_ip_bgp_scan_cmd);
install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);
}
void

View File

@ -54,7 +54,7 @@ extern void bgp_connected_add (struct connected *c);
extern void bgp_connected_delete (struct connected *c);
extern int bgp_multiaccess_check_v4 (struct in_addr, char *);
extern int bgp_config_write_scan_time (struct vty *);
extern int bgp_nexthop_check_ebgp (afi_t, struct attr *);
extern int bgp_nexthop_onlink (afi_t, struct attr *);
extern int bgp_nexthop_self (afi_t, struct attr *);
#endif /* _QUAGGA_BGP_NEXTHOP_H */

View File

@ -93,11 +93,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
case SAFI_MULTICAST:
vty_out (vty, "SAFI Multicast");
break;
case SAFI_UNICAST_MULTICAST:
vty_out (vty, "SAFI Unicast Multicast");
break;
case BGP_SAFI_VPNV4:
vty_out (vty, "SAFI MPLS-VPN");
case SAFI_MPLS_LABELED_VPN:
vty_out (vty, "SAFI MPLS-labeled VPN");
break;
default:
vty_out (vty, "SAFI Unknown %d ", mpc.safi);
@ -127,14 +124,6 @@ bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
int
bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
{
/* VPNvX are AFI specific */
if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
|| (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
{
zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
return 0;
}
switch (afi)
{
case AFI_IP:
@ -143,9 +132,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
#endif
switch (*safi)
{
/* BGP VPNvX SAFI isn't contigious with others, remap */
case BGP_SAFI_VPNV4:
case BGP_SAFI_VPNV6:
/* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
case SAFI_MPLS_LABELED_VPN:
*safi = SAFI_MPLS_VPN;
case SAFI_UNICAST:
case SAFI_MULTICAST:
@ -392,7 +380,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
peer->v_gr_restart);
}
while (stream_get_getp (s) + 4 < end)
while (stream_get_getp (s) + 4 <= end)
{
afi_t afi = stream_getw (s);
safi_t safi = stream_getc (s);
@ -433,13 +421,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
static as_t
bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
{
SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
if (hdr->length != CAPABILITY_CODE_AS4_LEN)
{
zlog_err ("%s AS4 capability has incorrect data length %d",
peer->host, hdr->length);
return 0;
}
as_t as4 = stream_getl (BGP_INPUT(peer));
if (BGP_DEBUG (as4, AS4))
zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
peer->host, as4);
SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
return as4;
}
@ -701,9 +696,6 @@ peek_for_as4_capability (struct peer *peer, u_char length)
if (hdr.code == CAPABILITY_CODE_AS4)
{
if (hdr.length != CAPABILITY_CODE_AS4_LEN)
goto end;
if (BGP_DEBUG (as4, AS4))
zlog_info ("[AS4] found AS4 capability, about to parse");
as4 = bgp_capability_as4 (peer, &hdr);
@ -859,7 +851,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,
int number_of_orfs = 0;
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
safi = SAFI_MPLS_LABELED_VPN;
stream_putc (s, BGP_OPEN_OPT_CAP);
capp = stream_get_endp (s); /* Set Capability Len Pointer */
@ -967,7 +959,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, CAPABILITY_CODE_MP_LEN);
stream_putw (s, AFI_IP);
stream_putc (s, 0);
stream_putc (s, BGP_SAFI_VPNV4);
stream_putc (s, SAFI_MPLS_LABELED_VPN);
}
#ifdef HAVE_IPV6
/* IPv6 unicast. */

View File

@ -206,7 +206,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
/* Synchnorize attribute. */
if (adj->attr)
bgp_attr_unintern (adj->attr);
bgp_attr_unintern (&adj->attr);
else
peer->scount[afi][safi]++;
@ -895,14 +895,27 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
{
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
{
peer->last_reset = PEER_DOWN_USER_RESET;
else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
zlog_info ("Notification sent to neighbor %s: User reset", peer->host);
}
else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
{
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
zlog_info ("Notification sent to neighbor %s: shutdown", peer->host);
}
else
{
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
zlog_info ("Notification sent to neighbor %s: type %u/%u",
peer->host, code, sub_code);
}
}
else
zlog_info ("Notification sent to neighbor %s: configuration change",
peer->host);
/* Call imidiately. */
/* Call immediately. */
BGP_WRITE_OFF (peer->t_write);
bgp_write_notify (peer);
@ -933,7 +946,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
safi = SAFI_MPLS_LABELED_VPN;
s = stream_new (BGP_MAX_PACKET_SIZE);
@ -1023,7 +1036,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
safi = SAFI_MPLS_LABELED_VPN;
s = stream_new (BGP_MAX_PACKET_SIZE);
@ -1368,7 +1381,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* remote router-id check. */
if (remote_id.s_addr == 0
|| ntohl (remote_id.s_addr) >= 0xe0000000
|| IPV4_CLASS_DE (ntohl (remote_id.s_addr))
|| ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
{
if (BGP_DEBUG (normal, NORMAL))
@ -1446,10 +1459,14 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* Open option part parse. */
if (optlen != 0)
{
ret = bgp_open_option_parse (peer, optlen, &capability);
if (ret < 0)
if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0)
{
bgp_notify_send (peer,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
return ret;
}
}
else
{
if (BGP_DEBUG (normal, NORMAL))
@ -1584,22 +1601,43 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
return -1;
}
/* Certain attribute parsing errors should not be considered bad enough
* to reset the session for, most particularly any partial/optional
* attributes that have 'tunneled' over speakers that don't understand
* them. Instead we withdraw only the prefix concerned.
*
* Complicates the flow a little though..
*/
bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED;
/* This define morphs the update case into a withdraw when lower levels
* have signalled an error condition where this is best.
*/
#define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL)
/* Parse attribute when it exists. */
if (attribute_len)
{
ret = bgp_attr_parse (peer, &attr, attribute_len,
attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len,
&mp_update, &mp_withdraw);
if (ret < 0)
if (attr_parse_ret == BGP_ATTR_PARSE_ERROR)
return -1;
}
/* Logging the attribute. */
if (BGP_DEBUG (update, UPDATE_IN))
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW
|| BGP_DEBUG (update, UPDATE_IN))
{
ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ);
int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
? LOG_ERR : LOG_DEBUG;
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
zlog (peer->log, LOG_ERR,
"%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
peer->host);
if (ret)
zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE w/ attr: %s",
zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s",
peer->host, attrstr);
}
@ -1611,7 +1649,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Check NLRI packet format and prefix length. */
ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len);
if (ret < 0)
{
bgp_attr_unintern_sub (&attr);
if (attr.extra)
bgp_attr_extra_free (&attr);
return -1;
}
/* Set NLRI portion to structure. */
update.afi = AFI_IP;
@ -1634,15 +1677,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
update. */
ret = bgp_attr_check (peer, &attr);
if (ret < 0)
{
bgp_attr_unintern_sub (&attr);
if (attr.extra)
bgp_attr_extra_free (&attr);
return -1;
}
bgp_nlri_parse (peer, &attr, &update);
bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update);
}
if (mp_update.length
&& mp_update.afi == AFI_IP
&& mp_update.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP
@ -1669,7 +1717,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (mp_update.length
&& mp_update.afi == AFI_IP
&& mp_update.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP
@ -1699,7 +1747,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (mp_update.length
&& mp_update.afi == AFI_IP6
&& mp_update.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP6
@ -1728,7 +1776,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (mp_update.length
&& mp_update.afi == AFI_IP6
&& mp_update.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, &attr, &mp_update);
bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP6
@ -1755,17 +1803,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
{
if (mp_update.length
&& mp_update.afi == AFI_IP
&& mp_update.safi == BGP_SAFI_VPNV4)
bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
&& mp_update.safi == SAFI_MPLS_LABELED_VPN)
bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == BGP_SAFI_VPNV4)
&& mp_withdraw.safi == SAFI_MPLS_LABELED_VPN)
bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
if (! withdraw_len
&& mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == BGP_SAFI_VPNV4
&& mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
&& mp_withdraw.length == 0)
{
/* End-of-RIB received */
@ -1778,20 +1826,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Everything is done. We unintern temporary structures which
interned in bgp_attr_parse(). */
if (attr.aspath)
aspath_unintern (attr.aspath);
if (attr.community)
community_unintern (attr.community);
bgp_attr_unintern_sub (&attr);
if (attr.extra)
{
if (attr.extra->ecommunity)
ecommunity_unintern (attr.extra->ecommunity);
if (attr.extra->cluster)
cluster_unintern (attr.extra->cluster);
if (attr.extra->transit)
transit_unintern (attr.extra->transit);
bgp_attr_extra_free (&attr);
}
/* If peering is stopped due to some reason, do not generate BGP
event. */
@ -1936,7 +1973,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
/* Check AFI and SAFI. */
if ((afi != AFI_IP && afi != AFI_IP6)
|| (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
&& safi != BGP_SAFI_VPNV4))
&& safi != SAFI_MPLS_LABELED_VPN))
{
if (BGP_DEBUG (normal, NORMAL))
{
@ -1947,7 +1984,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
}
/* Adjust safi code. */
if (safi == BGP_SAFI_VPNV4)
if (safi == SAFI_MPLS_LABELED_VPN)
safi = SAFI_MPLS_VPN;
if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
@ -2021,7 +2058,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
break;
}
ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ;
if (!ok)
if (ok)
{
memcpy (&seq, p_pnt, sizeof (u_int32_t));
p_pnt += sizeof (u_int32_t);

View File

@ -137,7 +137,7 @@ static void
bgp_info_free (struct bgp_info *binfo)
{
if (binfo->attr)
bgp_attr_unintern (binfo->attr);
bgp_attr_unintern (&binfo->attr);
bgp_info_extra_free (&binfo->extra);
@ -1069,11 +1069,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
struct bgp_filter *filter;
struct bgp_info info;
struct peer *from;
struct bgp *bgp;
from = ri->peer;
filter = &rsclient->filter[afi][safi];
bgp = rsclient->bgp;
if (DISABLE_BGP_ANNOUNCE)
return 0;
@ -1493,7 +1491,7 @@ bgp_process_main (struct work_queue *wq, void *data)
if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
{
if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED))
bgp_zebra_announce (p, old_select, bgp);
bgp_zebra_announce (p, old_select, bgp, safi);
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
@ -1516,20 +1514,20 @@ bgp_process_main (struct work_queue *wq, void *data)
}
/* FIB update. */
if (safi == SAFI_UNICAST && ! bgp->name &&
! bgp_option_check (BGP_OPT_NO_FIB))
if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name &&
! bgp_option_check (BGP_OPT_NO_FIB)))
{
if (new_select
&& new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_announce (p, new_select, bgp);
bgp_zebra_announce (p, new_select, bgp, safi);
else
{
/* Withdraw the route from the kernel. */
if (old_select
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (p, old_select);
bgp_zebra_withdraw (p, old_select, safi);
}
}
@ -1659,7 +1657,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
u_int8_t ndata[7];
if (safi == SAFI_MPLS_VPN)
safi = BGP_SAFI_VPNV4;
safi = SAFI_MPLS_LABELED_VPN;
ndata[0] = (afi >> 8);
ndata[1] = afi;
@ -1802,23 +1800,23 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Apply import policy. */
if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY)
{
bgp_attr_unintern (attr_new2);
bgp_attr_unintern (&attr_new2);
reason = "import-policy;";
goto filtered;
}
attr_new = bgp_attr_intern (&new_attr);
bgp_attr_unintern (attr_new2);
bgp_attr_unintern (&attr_new2);
/* IPv4 unicast next hop check. */
if (afi == AFI_IP && safi == SAFI_UNICAST)
if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST))
{
/* Next hop must not be 0.0.0.0 nor Class E address. */
/* Next hop must not be 0.0.0.0 nor Class D/E address. */
if (new_attr.nexthop.s_addr == 0
|| ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
|| IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
{
bgp_attr_unintern (attr_new);
bgp_attr_unintern (&attr_new);
reason = "martian next-hop;";
goto filtered;
@ -1848,7 +1846,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
p->prefixlen, rsclient->host);
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
bgp_attr_unintern (&attr_new);
return;
}
@ -1868,7 +1866,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* Update to new attribute. */
bgp_attr_unintern (ri->attr);
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;
/* Update MPLS tag. */
@ -2063,18 +2061,18 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* If the peer is EBGP and nexthop is not on connected route,
discard it. */
if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1
&& ! bgp_nexthop_check_ebgp (afi, &new_attr)
&& ! bgp_nexthop_onlink (afi, &new_attr)
&& ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
{
reason = "non-connected next-hop;";
goto filtered;
}
/* Next hop must not be 0.0.0.0 nor Class E address. Next hop
/* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop
must not be my own address. */
if (bgp_nexthop_self (afi, &new_attr)
|| new_attr.nexthop.s_addr == 0
|| ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
|| IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
{
reason = "martian next-hop;";
goto filtered;
@ -2128,7 +2126,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
bgp_attr_unintern (&attr_new);
bgp_attr_extra_free (&new_attr);
return 0;
@ -2175,7 +2173,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Update to new attribute. */
bgp_attr_unintern (ri->attr);
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;
/* Update MPLS tag. */
@ -2467,7 +2465,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
}
bgp_attr_extra_free (&attr);
aspath_unintern (aspath);
aspath_unintern (&aspath);
}
static void
@ -2936,7 +2934,7 @@ bgp_cleanup_routes (void)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (&rn->p, ri);
bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
table = bgp->rib[AFI_IP6][SAFI_UNICAST];
@ -2945,7 +2943,7 @@ bgp_cleanup_routes (void)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_withdraw (&rn->p, ri);
bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
}
}
@ -3215,7 +3213,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_attr_flush (&attr_tmp);
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
bgp_attr_extra_free (&attr);
@ -3242,8 +3240,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp->peer_self->rmap_type = 0;
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
bgp_attr_unintern (&attr_new);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
@ -3253,7 +3251,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp->peer_self->rmap_type = 0;
bgp_attr_unintern (attr_new);
bgp_attr_unintern (&attr_new);
attr_new = bgp_attr_intern (&new_attr);
bgp_attr_extra_free (&new_attr);
@ -3268,8 +3266,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
bgp_attr_unintern (&attr_new);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@ -3281,14 +3279,14 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
/* Rewrite BGP route information. */
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
bgp_info_restore(rn, ri);
bgp_attr_unintern (ri->attr);
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;
ri->uptime = bgp_clock ();
/* Process change. */
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@ -3313,7 +3311,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_process (bgp, rn, afi, safi);
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
@ -3363,7 +3361,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_attr_flush (&attr_tmp);
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_static_withdraw (bgp, p, afi, safi);
return;
@ -3384,8 +3382,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
bgp_unlock_node (rn);
bgp_attr_unintern (attr_new);
aspath_unintern (attr.aspath);
bgp_attr_unintern (&attr_new);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@ -3399,7 +3397,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_info_restore(rn, ri);
else
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
bgp_attr_unintern (ri->attr);
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;
ri->uptime = bgp_clock ();
@ -3407,7 +3405,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_aggregate_increment (bgp, p, ri, afi, safi);
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@ -3435,7 +3433,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_process (bgp, rn, afi, safi);
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
@ -4169,7 +4167,7 @@ DEFUN (ipv6_bgp_network,
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n")
{
return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST,
return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty),
NULL, 0);
}
@ -4192,7 +4190,7 @@ DEFUN (no_ipv6_bgp_network,
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n")
{
return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty));
}
ALIAS (no_ipv6_bgp_network,
@ -5244,7 +5242,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
/* Redistribute route treatment. */
void
bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
const struct in6_addr *nexthop6,
u_int32_t metric, u_char type)
{
struct bgp *bgp;
@ -5264,6 +5263,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (nexthop)
attr.nexthop = *nexthop;
#ifdef HAVE_IPV6
if (nexthop6)
{
struct attr_extra *extra = bgp_attr_extra_get(&attr);
extra->mp_nexthop_global = *nexthop6;
extra->mp_nexthop_len = 16;
}
#endif
attr.med = metric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
@ -5299,7 +5307,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_attr_extra_free (&attr_new);
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_redistribute_delete (p, type);
return;
@ -5322,8 +5330,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (attrhash_cmp (bi->attr, new_attr) &&
!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
{
bgp_attr_unintern (new_attr);
aspath_unintern (attr.aspath);
bgp_attr_unintern (&new_attr);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_unlock_node (bn);
return;
@ -5338,7 +5346,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_info_restore(bn, bi);
else
bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
bgp_attr_unintern (bi->attr);
bgp_attr_unintern (&bi->attr);
bi->attr = new_attr;
bi->uptime = bgp_clock ();
@ -5346,7 +5354,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);
bgp_process (bgp, bn, afi, SAFI_UNICAST);
bgp_unlock_node (bn);
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@ -5368,7 +5376,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
}
/* Unintern original. */
aspath_unintern (attr.aspath);
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
@ -9379,10 +9387,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
safi = SAFI_MULTICAST;
else if (strncmp (safi_str, "u", 1) == 0)
safi = SAFI_UNICAST;
else if (strncmp (safi_str, "vpnv4", 5) == 0)
safi = BGP_SAFI_VPNV4;
else if (strncmp (safi_str, "vpnv6", 6) == 0)
safi = BGP_SAFI_VPNV6;
else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0)
safi = SAFI_MPLS_LABELED_VPN;
else
{
vty_out (vty, "%% Invalid subsequent address family %s%s",
@ -9397,13 +9403,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
return CMD_WARNING;
}
if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6)
|| (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4))
{
vty_out (vty, "%% Invalid subsequent address family %s for %s%s",
afi_str, safi_str, VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_table_stats (vty, bgp, afi, safi);
}
@ -12581,6 +12580,9 @@ bgp_route_init (void)
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd);
install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
/* Old config IPv6 BGP commands. */
install_element (BGP_NODE, &old_ipv6_bgp_network_cmd);
install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd);

View File

@ -192,7 +192,9 @@ extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int);
extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char);
extern void bgp_redistribute_add (struct prefix *, const struct in_addr *,
const struct in6_addr *,
u_int32_t, u_char);
extern void bgp_redistribute_delete (struct prefix *, u_char);
extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int);

View File

@ -525,8 +525,13 @@ route_match_metric_compile (const char *arg)
char *endptr = NULL;
unsigned long tmpval;
/* Metric value shoud be integer. */
if (! all_digit (arg))
return NULL;
errno = 0;
tmpval = strtoul (arg, &endptr, 10);
if (*endptr != '\0' || tmpval == ULONG_MAX || tmpval > UINT32_MAX)
if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
return NULL;
med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@ -790,6 +795,75 @@ struct route_map_rule_cmd route_match_origin_cmd =
route_match_origin_compile,
route_match_origin_free
};
/* match probability { */
static route_map_result_t
route_match_probability (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
long r;
#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500
r = random();
#else
r = (long) rand();
#endif
switch (*(unsigned *) rule)
{
case 0: break;
case RAND_MAX: return RMAP_MATCH;
default:
if (r < *(unsigned *) rule)
{
return RMAP_MATCH;
}
}
return RMAP_NOMATCH;
}
static void *
route_match_probability_compile (const char *arg)
{
unsigned *lobule;
unsigned perc;
#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500
srandom (time (NULL));
#else
srand (time (NULL));
#endif
perc = atoi (arg);
lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned));
switch (perc)
{
case 0: *lobule = 0; break;
case 100: *lobule = RAND_MAX; break;
default: *lobule = RAND_MAX / 100 * perc;
}
return lobule;
}
static void
route_match_probability_free (void *rule)
{
XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
}
struct route_map_rule_cmd route_match_probability_cmd =
{
"probability",
route_match_probability,
route_match_probability_compile,
route_match_probability_free
};
/* } */
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
@ -933,8 +1007,9 @@ route_set_local_pref_compile (const char *arg)
if (! all_digit (arg))
return NULL;
errno = 0;
tmp = strtoul (arg, &endptr, 10);
if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX)
if (*endptr != '\0' || errno || tmp > UINT32_MAX)
return NULL;
local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@ -1001,9 +1076,9 @@ route_set_weight_compile (const char *arg)
if (! all_digit (arg))
return NULL;
errno = 0;
tmp = strtoul (arg, &endptr, 10);
if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX)
if (*endptr != '\0' || errno || tmp > UINT32_MAX)
return NULL;
weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@ -1092,8 +1167,9 @@ route_set_metric_compile (const char *arg)
if (all_digit (arg))
{
/* set metric value check*/
errno = 0;
larg = strtoul (arg, &endptr, 10);
if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX)
if (*endptr != '\0' || errno || larg > UINT32_MAX)
return NULL;
metric = larg;
}
@ -1105,8 +1181,9 @@ route_set_metric_compile (const char *arg)
|| (! all_digit (arg+1)))
return NULL;
errno = 0;
larg = strtoul (arg+1, &endptr, 10);
if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX)
if (*endptr != '\0' || errno || larg > UINT32_MAX)
return NULL;
metric = larg;
}
@ -1482,10 +1559,10 @@ route_set_ecommunity_rt (void *rule, struct prefix *prefix,
else
new_ecom = ecommunity_dup (ecom);
bgp_info->attr->extra->ecommunity = new_ecom;
bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom);
if (old_ecom)
ecommunity_free (old_ecom);
ecommunity_unintern (&old_ecom);
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
}
@ -1501,7 +1578,7 @@ route_set_ecommunity_rt_compile (const char *arg)
ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0);
if (! ecom)
return NULL;
return ecom;
return ecommunity_intern (ecom);
}
/* Free function for set community. */
@ -1509,7 +1586,7 @@ static void
route_set_ecommunity_rt_free (void *rule)
{
struct ecommunity *ecom = rule;
ecommunity_free (ecom);
ecommunity_unintern (&ecom);
}
/* Set community rule structure. */
@ -1528,7 +1605,7 @@ static route_map_result_t
route_set_ecommunity_soo (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct ecommunity *ecom;
struct ecommunity *ecom, *old_ecom, *new_ecom;
struct bgp_info *bgp_info;
if (type == RMAP_BGP)
@ -1539,8 +1616,19 @@ route_set_ecommunity_soo (void *rule, struct prefix *prefix,
if (! ecom)
return RMAP_OKAY;
old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity;
if (old_ecom)
new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom);
else
new_ecom = ecommunity_dup (ecom);
bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom);
if (old_ecom)
ecommunity_unintern (&old_ecom);
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
(bgp_attr_extra_get (bgp_info->attr))->ecommunity = ecommunity_dup (ecom);
}
return RMAP_OKAY;
}
@ -1555,7 +1643,7 @@ route_set_ecommunity_soo_compile (const char *arg)
if (! ecom)
return NULL;
return ecom;
return ecommunity_intern (ecom);
}
/* Free function for set community. */
@ -1563,7 +1651,7 @@ static void
route_set_ecommunity_soo_free (void *rule)
{
struct ecommunity *ecom = rule;
ecommunity_free (ecom);
ecommunity_unintern (&ecom);
}
/* Set community rule structure. */
@ -2451,6 +2539,38 @@ ALIAS (no_match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
/* match probability { */
DEFUN (match_probability,
match_probability_cmd,
"match probability <0-100>",
MATCH_STR
"Match portion of routes defined by percentage value\n"
"Percentage of routes\n")
{
return bgp_route_match_add (vty, vty->index, "probability", argv[0]);
}
DEFUN (no_match_probability,
no_match_probability_cmd,
"no match probability",
NO_STR
MATCH_STR
"Match portion of routes defined by percentage value\n")
{
return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL);
}
ALIAS (no_match_probability,
no_match_probability_val_cmd,
"no match probability <1-99>",
NO_STR
MATCH_STR
"Match portion of routes defined by percentage value\n"
"Percentage of routes\n")
/* } */
DEFUN (match_ip_route_source,
match_ip_route_source_cmd,
"match ip route-source (<1-199>|<1300-2699>|WORD)",
@ -3738,6 +3858,7 @@ bgp_route_map_init (void)
route_map_install_match (&route_match_ecommunity_cmd);
route_map_install_match (&route_match_metric_cmd);
route_map_install_match (&route_match_origin_cmd);
route_map_install_match (&route_match_probability_cmd);
route_map_install_set (&route_set_ip_nexthop_cmd);
route_map_install_set (&route_set_local_pref_cmd);
@ -3769,7 +3890,6 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_ip_route_source_cmd);
install_element (RMAP_NODE, &no_match_ip_route_source_cmd);
install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd);
install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
@ -3797,6 +3917,9 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_origin_cmd);
install_element (RMAP_NODE, &no_match_origin_cmd);
install_element (RMAP_NODE, &no_match_origin_val_cmd);
install_element (RMAP_NODE, &match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_val_cmd);
install_element (RMAP_NODE, &set_ip_nexthop_cmd);
install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd);

View File

@ -3707,7 +3707,7 @@ peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
if (! peer)
return CMD_WARNING;
VTY_GET_INTEGER ("maxmum number", max, num_str);
VTY_GET_INTEGER ("maximum number", max, num_str);
if (threshold_str)
threshold = atoi (threshold_str);
else
@ -4215,17 +4215,9 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (sort == clear_as)
{
as_t as;
unsigned long as_ul;
int find = 0;
VTY_GET_LONG ("AS", as_ul, arg);
if (!as_ul)
{
vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
return CMD_WARNING;
}
as = (as_t) as_ul;
VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX);
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
@ -8381,57 +8373,16 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary,
/* Redistribute VTY commands. */
/* Utility function to convert user input route type string to route
type. */
static int
bgp_str2route_type (int afi, const char *str)
{
if (! str)
return 0;
if (afi == AFI_IP)
{
if (strncmp (str, "k", 1) == 0)
return ZEBRA_ROUTE_KERNEL;
else if (strncmp (str, "c", 1) == 0)
return ZEBRA_ROUTE_CONNECT;
else if (strncmp (str, "s", 1) == 0)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (str, "r", 1) == 0)
return ZEBRA_ROUTE_RIP;
else if (strncmp (str, "o", 1) == 0)
return ZEBRA_ROUTE_OSPF;
}
if (afi == AFI_IP6)
{
if (strncmp (str, "k", 1) == 0)
return ZEBRA_ROUTE_KERNEL;
else if (strncmp (str, "c", 1) == 0)
return ZEBRA_ROUTE_CONNECT;
else if (strncmp (str, "s", 1) == 0)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (str, "r", 1) == 0)
return ZEBRA_ROUTE_RIPNG;
else if (strncmp (str, "o", 1) == 0)
return ZEBRA_ROUTE_OSPF6;
}
return 0;
}
DEFUN (bgp_redistribute_ipv4,
bgp_redistribute_ipv4_cmd,
"redistribute (connected|kernel|ospf|rip|static)",
"redistribute " QUAGGA_IP_REDIST_STR_BGPD,
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n")
QUAGGA_IP_REDIST_HELP_STR_BGPD)
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8441,20 +8392,16 @@ DEFUN (bgp_redistribute_ipv4,
DEFUN (bgp_redistribute_ipv4_rmap,
bgp_redistribute_ipv4_rmap_cmd,
"redistribute (connected|kernel|ospf|rip|static) route-map WORD",
"redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8466,21 +8413,17 @@ DEFUN (bgp_redistribute_ipv4_rmap,
DEFUN (bgp_redistribute_ipv4_metric,
bgp_redistribute_ipv4_metric_cmd,
"redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
"redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8493,13 +8436,9 @@ DEFUN (bgp_redistribute_ipv4_metric,
DEFUN (bgp_redistribute_ipv4_rmap_metric,
bgp_redistribute_ipv4_rmap_metric_cmd,
"redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
"redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@ -8508,8 +8447,8 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8523,13 +8462,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,
DEFUN (bgp_redistribute_ipv4_metric_rmap,
bgp_redistribute_ipv4_metric_rmap_cmd,
"redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
"redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@ -8538,8 +8473,8 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8553,19 +8488,15 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,
DEFUN (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_cmd,
"no redistribute (connected|kernel|ospf|rip|static)",
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD,
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n")
QUAGGA_IP_REDIST_HELP_STR_BGPD)
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8576,21 +8507,17 @@ DEFUN (no_bgp_redistribute_ipv4,
DEFUN (no_bgp_redistribute_ipv4_rmap,
no_bgp_redistribute_ipv4_rmap_cmd,
"no redistribute (connected|kernel|ospf|rip|static) route-map WORD",
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8602,21 +8529,17 @@ DEFUN (no_bgp_redistribute_ipv4_rmap,
DEFUN (no_bgp_redistribute_ipv4_metric,
no_bgp_redistribute_ipv4_metric_cmd,
"no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8628,14 +8551,10 @@ DEFUN (no_bgp_redistribute_ipv4_metric,
DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
no_bgp_redistribute_ipv4_rmap_metric_cmd,
"no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@ -8643,8 +8562,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
{
int type;
type = bgp_str2route_type (AFI_IP, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8657,14 +8576,10 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
no_bgp_redistribute_ipv4_metric_rmap_cmd,
"no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPF)\n"
"Routing Information Protocol (RIP)\n"
"Static routes\n"
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@ -8673,18 +8588,14 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
#ifdef HAVE_IPV6
DEFUN (bgp_redistribute_ipv6,
bgp_redistribute_ipv6_cmd,
"redistribute (connected|kernel|ospf6|ripng|static)",
"redistribute " QUAGGA_IP6_REDIST_STR_BGPD,
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n")
QUAGGA_IP6_REDIST_HELP_STR_BGPD)
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8695,20 +8606,16 @@ DEFUN (bgp_redistribute_ipv6,
DEFUN (bgp_redistribute_ipv6_rmap,
bgp_redistribute_ipv6_rmap_cmd,
"redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
"redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8720,21 +8627,17 @@ DEFUN (bgp_redistribute_ipv6_rmap,
DEFUN (bgp_redistribute_ipv6_metric,
bgp_redistribute_ipv6_metric_cmd,
"redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
"redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8747,13 +8650,9 @@ DEFUN (bgp_redistribute_ipv6_metric,
DEFUN (bgp_redistribute_ipv6_rmap_metric,
bgp_redistribute_ipv6_rmap_metric_cmd,
"redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
"redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@ -8762,8 +8661,8 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8777,13 +8676,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,
DEFUN (bgp_redistribute_ipv6_metric_rmap,
bgp_redistribute_ipv6_metric_rmap_cmd,
"redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
"redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@ -8792,8 +8687,8 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,
int type;
u_int32_t metric;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8807,19 +8702,15 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,
DEFUN (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_cmd,
"no redistribute (connected|kernel|ospf6|ripng|static)",
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD,
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n")
QUAGGA_IP6_REDIST_HELP_STR_BGPD)
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8830,21 +8721,17 @@ DEFUN (no_bgp_redistribute_ipv6,
DEFUN (no_bgp_redistribute_ipv6_rmap,
no_bgp_redistribute_ipv6_rmap_cmd,
"no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8856,21 +8743,17 @@ DEFUN (no_bgp_redistribute_ipv6_rmap,
DEFUN (no_bgp_redistribute_ipv6_metric,
no_bgp_redistribute_ipv6_metric_cmd,
"no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8882,14 +8765,10 @@ DEFUN (no_bgp_redistribute_ipv6_metric,
DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
no_bgp_redistribute_ipv6_rmap_metric_cmd,
"no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@ -8897,8 +8776,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
{
int type;
type = bgp_str2route_type (AFI_IP6, argv[0]);
if (! type)
type = proto_redistnum (AFI_IP6, argv[0]);
if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@ -8911,14 +8790,10 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
ALIAS (no_bgp_redistribute_ipv6_rmap_metric,
no_bgp_redistribute_ipv6_metric_rmap_cmd,
"no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
"Connected\n"
"Kernel routes\n"
"Open Shurtest Path First (OSPFv3)\n"
"Routing Information Protocol (RIPng)\n"
"Static routes\n"
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"

View File

@ -232,12 +232,10 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct zapi_ipv4 api;
unsigned long ifindex;
struct in_addr nexthop;
struct prefix_ipv4 p;
s = zclient->ibuf;
ifindex = 0;
nexthop.s_addr = 0;
/* Type, flags, message. */
@ -260,7 +258,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
stream_getl (s); /* ifindex, unused */
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@ -281,7 +279,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type);
bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
api.metric, api.type);
}
else
{
@ -309,12 +308,10 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct zapi_ipv6 api;
unsigned long ifindex;
struct in6_addr nexthop;
struct prefix_ipv6 p;
s = zclient->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in6_addr));
/* Type, flags, message. */
@ -337,7 +334,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
stream_getl (s); /* ifindex, unused */
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@ -356,23 +353,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u",
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)),
p.prefixlen, api.metric);
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type);
bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
api.metric, api.type);
}
else
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u",
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
"nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)),
p.prefixlen, api.metric);
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_delete ((struct prefix *) &p, api.type);
}
@ -640,7 +643,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
}
void
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
{
int flags;
u_char distance;
@ -675,6 +678,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
@ -749,6 +753,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
@ -775,7 +780,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
}
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{
int flags;
struct peer *peer;
@ -809,6 +814,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
@ -864,6 +870,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;

View File

@ -25,8 +25,8 @@ extern void bgp_zebra_init (void);
extern int bgp_if_update_all (void);
extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
int *);
extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *);
extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *);
extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t);
extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
extern int bgp_redistribute_set (struct bgp *, afi_t, int);
extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *);

View File

@ -695,7 +695,7 @@ peer_sort (struct peer *peer)
}
}
static inline void
static void
peer_free (struct peer *peer)
{
assert (peer->status == Deleted);
@ -1147,7 +1147,7 @@ peer_nsf_stop (struct peer *peer)
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
peer->nsf[afi][safi] = 0;
if (peer->t_gr_restart)
@ -2048,6 +2048,10 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
}
}
bgp = bgp_create (as, name);
bgp_router_id_set(bgp, &router_id_zebra);
*bgp_val = bgp;
/* Create BGP server socket, if first instance. */
if (list_isempty(bm->bgp))
{
@ -2055,10 +2059,7 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
return BGP_ERR_INVALID_VALUE;
}
bgp = bgp_create (as, name);
listnode_add (bm->bgp, bgp);
bgp_router_id_set(bgp, &router_id_zebra);
*bgp_val = bgp;
return 0;
}
@ -4720,12 +4721,10 @@ static void
bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
struct peer *peer, afi_t afi, safi_t safi)
{
struct bgp_filter *filter;
struct peer *g_peer = NULL;
char buf[SU_ADDRSTRLEN];
char *addr;
filter = &peer->filter[afi][safi];
addr = peer->host;
if (peer_group_active (peer))
g_peer = peer->group->conf;
@ -5014,6 +5013,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
&& ! peer->af_group[afi][safi])
vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE);
/* Nexthop-local unchanged. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)
&& ! peer->af_group[afi][safi])
vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE);
/* Allow AS in. */
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))
if (! peer_group_active (peer)

View File

@ -632,6 +632,8 @@ struct bgp_nlri
#define BGP_NOTIFY_CAPABILITY_ERR 7
#define BGP_NOTIFY_MAX 8
#define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0
/* BGP_NOTIFY_HEADER_ERR sub codes. */
#define BGP_NOTIFY_HEADER_NOT_SYNC 1
#define BGP_NOTIFY_HEADER_BAD_MESLEN 2
@ -662,7 +664,7 @@ struct bgp_nlri
#define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11
#define BGP_NOTIFY_UPDATE_MAX 12
/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05). */
/* BGP_NOTIFY_CEASE sub codes (RFC 4486). */
#define BGP_NOTIFY_CEASE_MAX_PREFIX 1
#define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2
#define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3
@ -725,9 +727,8 @@ struct bgp_nlri
#define BGP_DEFAULT_RESTART_TIME 120
#define BGP_DEFAULT_STALEPATH_TIME 360
/* SAFI which used in open capability negotiation. */
#define BGP_SAFI_VPNV4 128
#define BGP_SAFI_VPNV6 129
/* RFC4364 */
#define SAFI_MPLS_LABELED_VPN 128
/* Max TTL value. */
#define TTL_MAX 255

View File

@ -5,10 +5,9 @@
## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
##
## $Id$
AC_PREREQ(2.53)
AC_INIT(Quagga, 0.99.18, [https://bugzilla.quagga.net])
AC_INIT(Quagga, 0.99.20, [https://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
@ -73,6 +72,16 @@ dnl autoconf 2.59 appears not to support AC_PROG_SED
dnl AC_PROG_SED
AC_CHECK_PROG([SED],[sed],[sed],[/bin/false])
dnl pdflatex and latexmk are needed to build HACKING.pdf
AC_CHECK_PROG([PDFLATEX],[pdflatex],[pdflatex],[/bin/false])
AC_CHECK_PROG([LATEXMK],[latexmk],[latexmk],[/bin/false])
if test "x$PDFLATEX" = "x/bin/false" -o "x$LATEXMK" = "x/bin/false"; then
AC_MSG_WARN([Will not be able to make PDF versions of TeX documents])
else
HAVE_LATEX=true
fi
AM_CONDITIONAL([HAVE_LATEX], [test "x$HAVE_LATEX" = "xtrue"])
dnl ------------------------------------------------------------------
dnl Intel compiler check. Although Intel tries really hard to make icc
dnl look like gcc, there are some differences. It's very verbose with
@ -198,6 +207,8 @@ AC_ARG_ENABLE(ospfd,
[ --disable-ospfd do not build ospfd])
AC_ARG_ENABLE(ospf6d,
[ --disable-ospf6d do not build ospf6d])
AC_ARG_ENABLE(babeld,
[ --disable-babeld do not build babeld])
AC_ARG_ENABLE(watchquagga,
[ --disable-watchquagga do not build watchquagga])
AC_ARG_ENABLE(isisd,
@ -395,7 +406,7 @@ dnl Check other header files.
dnl -------------------------
AC_CHECK_HEADERS([stropts.h sys/ksym.h sys/times.h sys/select.h \
sys/types.h linux/version.h netdb.h asm/types.h \
sys/param.h limits.h signal.h libutil.h \
sys/param.h limits.h signal.h \
sys/socket.h netinet/in.h time.h sys/time.h])
dnl Utility macro to avoid retyping includes all the time
@ -442,8 +453,35 @@ m4_define([QUAGGA_INCLUDES],
#endif /* TIME_WITH_SYS_TIME */
])dnl
AC_CHECK_HEADERS([sys/un.h net/if.h netinet/in_systm.h netinet/in_var.h \
net/if_dl.h net/if_var.h net/netopt.h net/route.h \
dnl HAVE_NET_IF_H must be discovered by the time the longer AC_CHECK_HEADERS
dnl round below execution begins, otherwise it doesn't properly detect
dnl HAVE_NETINET6_IN6_VAR_H, HAVE_NET_IF_VAR_H and HAVE_STRUCT_IN6_ALIASREQ
dnl on FreeBSD (BZ#408).
AC_CHECK_HEADERS([net/if.h], [], [], QUAGGA_INCLUDES)
m4_define([QUAGGA_INCLUDES],
QUAGGA_INCLUDES
[#if HAVE_NET_IF_H
# include <net/if.h>
#endif
])dnl
dnl Same applies for HAVE_NET_IF_VAR_H, which HAVE_NETINET6_ND6_H and
dnl HAVE_NETINET_IN_VAR_H depend upon. But if_var.h depends on if.h, hence
dnl an additional round for it.
AC_CHECK_HEADERS([net/if_var.h], [], [], QUAGGA_INCLUDES)
m4_define([QUAGGA_INCLUDES],
QUAGGA_INCLUDES
[#if HAVE_NET_IF_VAR_H
# include <net/if_var.h>
#endif
])dnl
AC_CHECK_HEADERS([sys/un.h netinet/in_systm.h netinet/in_var.h \
net/if_dl.h net/netopt.h net/route.h \
inet/nd.h arpa/inet.h netinet/ip_icmp.h \
fcntl.h stddef.h sys/ioctl.h syslog.h wchar.h wctype.h \
sys/sysctl.h sys/sockio.h kvm.h sys/conf.h],
@ -458,10 +496,7 @@ QUAGGA_INCLUDES
m4_define([QUAGGA_INCLUDES],
QUAGGA_INCLUDES
[#if HAVE_NET_IF_H
# include <net/if.h>
#endif
#if HAVE_SYS_UN_H
[#if HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#if HAVE_NETINET_IN_SYSTM_H
@ -473,9 +508,6 @@ QUAGGA_INCLUDES
#if HAVE_NET_IF_DL_H
# include <net/if_dl.h>
#endif
#if HAVE_NET_IF_VAR_H
# include <net/if_var.h>
#endif
#if HAVE_NET_NETOPT_H
# include <net/netopt.h>
#endif
@ -595,6 +627,13 @@ AC_SUBST(LIBREADLINE)
dnl ----------
dnl PAM module
dnl
dnl Quagga detects the PAM library it is built against by checking for a
dnl functional pam_misc.h (Linux-PAM) or openpam.h (OpenPAM) header. pam_misc.h
dnl is known to #include pam_appl.h, the standard header of a PAM library, and
dnl openpam.h doesn't do that, although depends on the header too. Hence a
dnl little assistance to AC_CHECK_HEADER is necessary for the proper detection
dnl of OpenPAM.
dnl ----------
if test "$with_libpam" = "yes"; then
AC_CHECK_HEADER([security/pam_misc.h],
@ -608,7 +647,7 @@ if test "$with_libpam" = "yes"; then
AC_DEFINE(PAM_CONV_FUNC,openpam_ttyconv,Have openpam_ttyconv)
pam_conv_func="openpam_ttyconv"
],
[], QUAGGA_INCLUDES)
[], QUAGGA_INCLUDES[#include <security/pam_appl.h>])
if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then
AC_MSG_WARN([*** pam support will not be built ***])
with_libpam="no"
@ -665,11 +704,9 @@ dnl ----------------------------
AC_FUNC_CHOWN
AC_FUNC_FNMATCH
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_MKTIME
AC_FUNC_STRFTIME
AC_FUNC_REALLOC
AC_FUNC_STAT
AC_FUNC_SELECT_ARGTYPES
AC_FUNC_STRFTIME
@ -916,6 +953,15 @@ AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H
AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])],
AC_MSG_RESULT(no))
AC_MSG_CHECKING([for RFC3678 protocol-independed API])
AC_TRY_COMPILE([
#include <sys/types.h>
#include <netinet/in.h>
], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr));
], [AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_RFC3678,1,[Have RFC3678 protocol-independed API])],
AC_MSG_RESULT(no))
dnl ---------------------------------------------------------------
dnl figure out how to check link-state
dnl ---------------------------------------------------------------
@ -972,10 +1018,18 @@ dnl -----------------------------
dnl check ipforward detect method
dnl -----------------------------
AC_CACHE_CHECK([ipforward method], [quagga_cv_ipforward_method],
[for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null;
[if test x$cross_compiling = xyes; then
if test x"$opsys" = x"gnu-linux"; then
quagga_cv_ipforward_method=/proc/net/snmp
else
quagga_cv_ipforward_method=/dev/ip
fi
else
for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null;
do
test x`ls $quagga_cv_ipforward_method 2>/dev/null` = x"$quagga_cv_ipforward_method" && break
done
fi
case $quagga_cv_ipforward_method in
"/proc/net/snmp") quagga_cv_ipforward_method="proc";;
"/dev/ip")
@ -1193,6 +1247,12 @@ else
OSPFD="ospfd"
fi
if test "${enable_babeld}" = "no";then
BABELD=""
else
BABELD="babeld"
fi
if test "${enable_watchquagga}" = "no";then
WATCHQUAGGA=""
else
@ -1249,6 +1309,7 @@ AC_SUBST(RIPD)
AC_SUBST(RIPNGD)
AC_SUBST(OSPFD)
AC_SUBST(OSPF6D)
AC_SUBST(BABELD)
AC_SUBST(WATCHQUAGGA)
AC_SUBST(ISISD)
AC_SUBST(SOLARIS)
@ -1403,14 +1464,12 @@ AC_SUBST(LIBCAP)
dnl ---------------------------
dnl check for glibc 'backtrace'
dnl ---------------------------
if test "${glibc}" = "yes"; then
AC_CHECK_HEADER([execinfo.h],
[AC_CHECK_FUNC([backtrace],
[AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace])
AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding])
])
])
fi
dnl -----------------------------------------
dnl check for malloc mallinfo struct and call
@ -1494,6 +1553,7 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID)
AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID)
AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID)
AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID)
AC_DEFINE_UNQUOTED(PATH_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID)
AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID)
AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID)
AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$quagga_statedir/zserv.api",zebra api socket)
@ -1503,6 +1563,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc
AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket)
AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket)
AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket)
AC_DEFINE_UNQUOTED(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket)
AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)
AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
@ -1527,8 +1588,9 @@ AC_MSG_RESULT($ac_cv_htonl_works)
AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile
ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile
ospfclient/Makefile tests/Makefile m4/Makefile redhat/Makefile
ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
redhat/Makefile
pkgsrc/Makefile
redhat/quagga.spec
lib/version.h

View File

@ -1,31 +0,0 @@
Makefile
Makefile.in
mdate-sh
draft-zebra-00.txt
zebra.info-*
zebra.html
defines.texi
version.texi
quagga.html
quagga.info
*.pdf
*.eps
quagga.ps
quagga.dvi
stamp-vti
.nfs*
*.aux
*.cp
*.cps
*.fn
*.fns
*.ky
*.kys
*.log
*.op
*.pg
*.toc
*.tp
*.vr
.arch-inventory
.arch-ids

View File

@ -3,24 +3,22 @@
Value Attribute References
=========================================================================
1 ORIGIN [RFC 1771]
2 AS_PATH [RFC 1771]
3 NEXT_HOP [RFC 1771]
4 MULTI_EXIT_DISC [RFC 1771]
5 LOCAL_PREF [RFC 1771]
6 ATOMIC_AGGREGATE [RFC 1771]
7 AGGREGATOR [RFC 1771]
1 ORIGIN [RFC 4271]
2 AS_PATH [RFC 4271]
3 NEXT_HOP [RFC 4271]
4 MULTI_EXIT_DISC [RFC 4271]
5 LOCAL_PREF [RFC 4271]
6 ATOMIC_AGGREGATE [RFC 4271]
7 AGGREGATOR [RFC 4271]
8 COMMUNITIES [RFC 1997]
9 ORIGINATOR_ID [RFC 1966]
10 CLUSTER_LIST [RFC 1966]
9 ORIGINATOR_ID [RFC 4456]
10 CLUSTER_LIST [RFC 4456]
11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)]
12 ADVERTISER [Changed from RFC 1863 bgp@ans.net ML?]
13 RCID_PATH [Changed from RFC 1863 bgp@ans.net ML?]
14 MP_REACH_NLRI [RFC 2283]
15 MP_UNREACH_NLRI [RFC 2283]
16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt]
12 ADVERTISER [RFC 1863]
13 RCID_PATH [RFC 1863]
14 MP_REACH_NLRI [RFC 4760]
15 MP_UNREACH_NLRI [RFC 4760]
16 EXT_COMMUNITIES [RFC 4360]
17 AS4_PATH [RFC 4893]
18 AS4_AGGREGATOR [RFC 4893]
254 RCID_PATH [RFC 1863]
255 ADVERTISER [RFC 1863]
=========================================================================

View File

@ -46,11 +46,11 @@ info_TEXINFOS = quagga.texi
quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS)
$(TEXI2PDF) -o "$@" $<
quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \
ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \
protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi \
vtysh.texi routeserver.texi defines.texi $(figures_png) snmptrap.texi \
$(figures_txt)
quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \
install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \
overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \
snmptrap.texi $(figures_txt)
.png.eps:
$(PNGTOEPS) $< "$@"

118
doc/babeld.texi Normal file
View File

@ -0,0 +1,118 @@
@c -*-texinfo-*-
@c This is part of the Quagga Manual.
@c @value{COPYRIGHT_STR}
@c See file quagga.texi for copying conditions.
@node Babel
@chapter Babel
Babel is an interior gateway protocol that is suitable both for wired
networks and for wireless mesh networks. Babel has been described as
``RIP on speed'' --- it is based on the same principles as RIP, but
includes a number of refinements that make it react much faster to
topology changes without ever counting to infinity, and allow it to
perform reliable link quality estimation on wireless links. Babel is
a double-stack routing protocol, meaning that a single Babel instance
is able to perform routing for both IPv4 and IPv6.
Quagga implements Babel as described in RFC6126.
@menu
* Configuring babeld::
* Babel configuration::
* Babel redistribution::
* Show Babel information::
* Babel debugging commands::
@end menu
@node Configuring babeld, Babel configuration, Babel, Babel
@section Configuring babeld
The @command{babeld} daemon can be invoked with any of the common
options (@pxref{Common Invocation Options}).
The @command{zebra} daemon must be running before @command{babeld} is
invoked. Also, if @command{zebra} is restarted then @command{babeld}
must be too.
Configuration of @command{babeld} is done in its configuration file
@file{babeld.conf}.
@node Babel configuration, Babel redistribution, Configuring babeld, Babel
@section Babel configuration
@deffn Command {router babel} {}
@deffnx Command {no router babel} {}
Enable or disable Babel routing.
@end deffn
@deffn {Babel Command} {network @var{ifname}} {}
@deffnx {Babel Command} {no network @var{ifname}} {}
Enable or disable Babel on the given interface.
@end deffn
@deffn {Interface Command} {babel wired} {}
@deffnx {Interface Command} {babel wireless} {}
Specifies whether this interface is wireless, which disables a number
of optimisations that are only correct on wired interfaces.
Specifying @code{wireless} (the default) is always correct, but may
cause slower convergence and extra routing traffic.
@end deffn
@deffn {Interface Command} {babel split-horizon}
@deffnx {Interface Command} {no babel split-horizon}
Specifies whether to perform split-horizon on the interface.
Specifying @code{no babel split-horizon} (the default) is always
correct, while @code{babel split-horizon} is an optimisation that
should only be used on symmetric and transitive (wired) networks.
@end deffn
@deffn {Interface Command} {babel hello-interval <20-655340>}
Specifies the time in milliseconds between two scheduled hellos. On
wired links, Babel notices a link failure within two hello intervals;
on wireless links, the link quality value is reestimated at every
hello interval. The default is 4000@dmn{ms}.
@end deffn
@deffn {Interface Command} {babel update-interval <20-655340>}
Specifies the time in milliseconds between two scheduled updates.
Since Babel makes extensive use of triggered updates, this can be set
to fairly high values on links with little packet loss. The default
is 20000@dmn{ms}.
@end deffn
@deffn {Babel Command} {babel resend-delay <20-655340>}
Specifies the time in milliseconds after which an ``important''
request or update will be resent. The default is 2000@dmn{ms}. You
probably don't want to tweak this value.
@end deffn
@node Babel redistribution, Show Babel information, Babel configuration, Babel
@section Babel redistribution
@deffn {Babel command} {redistribute @var{kind}}
@deffnx {Babel command} {no redistribute @var{kind}}
Specify which kind of routes should be redistributed into Babel.
@end deffn
@node Show Babel information, Babel debugging commands, Babel redistribution, Babel
@section Show Babel information
@deffn {Command} {show babel database} {}
@deffnx {Command} {show babel interface} {}
@deffnx {Command} {show babel neighbour} {}
@deffnx {Command} {show babel parameters} {}
These commands dump various parts of @command{babeld}'s internal
state. They are mostly useful for troubleshooting.
@end deffn
@node Babel debugging commands, , Show Babel information, Babel
@section Babel debugging commands
@deffn {Babel Command} {debug babel @var{kind}} {}
@deffnx {Babel Command} {no debug babel @var{kind}} {}
Enable or disable debugging messages of a given kind. @var{kind} can
be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout},
@samp{interface}, @samp{route} or @samp{all}. Note that if you have
compiled with the NO_DEBUG flag, then these commands aren't available.
@end deffn

View File

@ -46,14 +46,14 @@ starting.
Config files are generally found in:
@itemize @asis
@itemize @w{}
@item @file{@value{INSTALL_PREFIX_ETC}/*.conf}
@end itemize
Each of the daemons has its own
config file. For example, zebra's default config file name is:
@itemize @asis
@itemize @w{}
@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf}
@end itemize

View File

@ -85,6 +85,7 @@ so @code{router-id} is set to 0.0.0.0. So please set router-id by hand.
@menu
* BGP distance::
* BGP decision process::
* BGP route flap dampening::
@end menu
@node BGP distance
@ -123,6 +124,27 @@ sequences should should be taken into account during the BGP best path
decision process.
@end deffn
@node BGP route flap dampening
@subsection BGP route flap dampening
@deffn {BGP} {bgp dampening @var{<1-45>} @var{<1-20000>} @var{<1-20000>} @var{<1-255>}} {}
This command enables BGP route-flap dampening and specifies dampening parameters.
@table @asis
@item @asis{half-life}
Half-life time for the penalty
@item @asis{reuse-threshold}
Value to start reusing a route
@item @asis{suppress-threshold}
Value to start suppressing a route
@item @asis{max-suppress}
Maximum duration to suppress a stable route
@end table
The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of this command
is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}.
@end deffn
@node BGP network
@section BGP network
@ -930,6 +952,14 @@ Clear peers which have addresses of X.X.X.X
Clear peer using soft reconfiguration.
@end deffn
@deffn {Command} {show ip bgp dampened-paths} {}
Display paths suppressed due to dampening
@end deffn
@deffn {Command} {show ip bgp flap-statistics} {}
Display flap statistics of routes
@end deffn
@deffn {Command} {show debug} {}
@end deffn

View File

@ -2,7 +2,7 @@
@chapter IPv6 Support
Quagga fully supports IPv6 routing. As described so far, Quagga supports
RIPng, OSPFv3 and BGP-4+. You can give IPv6 addresses to an interface
RIPng, OSPFv3, Babel and BGP-4+. You can give IPv6 addresses to an interface
and configure static IPv6 routing information. Quagga IPv6 also provides
automatic address configuration via a feature called @code{address
auto configuration}. To do it, the router must send router advertisement
@ -62,23 +62,24 @@ Default: not set, i.e. hosts do not assume a complete IP address is placed.
@end itemize
@end deffn
@deffn {Interface Command} {ipv6 nd ra-interval SECONDS} {}
@deffnx {Interface Command} {no ipv6 nd ra-interval} {}
@deffn {Interface Command} {ipv6 nd ra-interval <1-1800>} {}
@deffnx {Interface Command} {no ipv6 nd ra-interval [<1-1800>]} {}
The maximum time allowed between sending unsolicited multicast router
advertisements from the interface, in seconds. Must be no less than 3 seconds.
advertisements from the interface, in seconds.
Default: @code{600}
@end deffn
@deffn {Interface Command} {ipv6 nd ra-interval msec MILLISECONDS} {}
@deffnx {Interface Command} {no ipv6 nd ra-interval msec} {}
@deffn {Interface Command} {ipv6 nd ra-interval msec <70-1800000>} {}
@deffnx {Interface Command} {no ipv6 nd ra-interval [msec <70-1800000>]} {}
The maximum time allowed between sending unsolicited multicast router
advertisements from the interface, in milliseconds. Must be no less than 30 milliseconds.
advertisements from the interface, in milliseconds.
Default: @code{600000}
@end deffn
@deffn {Interface Command} {ipv6 nd ra-lifetime SECONDS} {}
@deffnx {Interface Command} {no ipv6 nd ra-lifetime} {}
@deffn {Interface Command} {ipv6 nd ra-lifetime <0-9000>} {}
@deffnx {Interface Command} {no ipv6 nd ra-lifetime [<0-9000>]} {}
The value to be placed in the Router Lifetime field of router advertisements
sent from the interface, in seconds. Indicates the usefulness of the router
as a default router on this interface. Setting the value to zero indicates
@ -89,12 +90,12 @@ Must be either zero or between value specified with @var{ipv6 nd ra-interval}
Default: @code{1800}
@end deffn
@deffn {Interface Command} {ipv6 nd reachable-time MILLISECONDS} {}
@deffnx {Interface Command} {no ipv6 nd reachable-time} {}
@deffn {Interface Command} {ipv6 nd reachable-time <1-3600000>} {}
@deffnx {Interface Command} {no ipv6 nd reachable-time [<1-3600000>]} {}
The value to be placed in the Reachable Time field in the Router Advertisement
messages sent by the router, in milliseconds. The configured time enables the
router to detect unavailable neighbors. The value zero means unspecified (by
this router). Must be no greater than @code{3,600,000} milliseconds (1 hour).
this router).
Default: @code{0}
@end deffn
@ -126,18 +127,20 @@ the router acts as a Home Agent and includes a Home Agent Option.
Default: not set
@end deffn
@deffn {Interface Command} {ipv6 nd home-agent-preference} {}
@deffnx {Interface Command} {no ipv6 nd home-agent-preference} {}
@deffn {Interface Command} {ipv6 nd home-agent-preference <0-65535>} {}
@deffnx {Interface Command} {no ipv6 nd home-agent-preference [<0-65535>]} {}
The value to be placed in Home Agent Option, when Home Agent config flag is set,
which indicates to hosts Home Agent preference.
which indicates to hosts Home Agent preference. The default value of 0 stands
for the lowest preference possible.
Default: 0
@end deffn
@deffn {Interface Command} {ipv6 nd home-agent-lifetime} {}
@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime} {}
+@deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {}
+@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {}
The value to be placed in Home Agent Option, when Home Agent config flag is set,
which indicates to hosts Home Agent Lifetime. A value of 0 means to place Router Lifetime value.
which indicates to hosts Home Agent Lifetime. The default value of 0 means to
place the current Router Lifetime value.
Default: 0
@end deffn
@ -151,12 +154,21 @@ Default: not set
@end deffn
@deffn {Interface Command} {ipv6 nd router-preference (high|medium|low)} {}
@deffnx {Interface Command} {no ipv6 nd router-preference} {}
@deffnx {Interface Command} {no ipv6 nd router-preference [(high|medium|low)]} {}
Set default router preference in IPv6 router advertisements per RFC4191.
Default: medium
@end deffn
@deffn {Interface Command} {ipv6 nd mtu <1-65535>} {}
@deffnx {Interface Command} {no ipv6 nd mtu [<1-65535>]} {}
Include an MTU (type 5) option in each RA packet to assist the attached hosts
in proper interface configuration. The announced value is not verified to be
consistent with router interface MTU.
Default: don't advertise any MTU option
@end deffn
@example
@group
interface eth0
@ -166,6 +178,6 @@ interface eth0
@end example
For more information see @cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)}
, @cite{RFC2461 (Neighbor Discovery for IP Version 6 (IPv6))}
, @cite{RFC3775 (Mobility Support in IPv6 (Mobile IPv6))}
, @cite{RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))}
, @cite{RFC6275 (Mobility Support in IPv6)}
and @cite{RFC4191 (Default Router Preferences and More-Specific Routes)}.

View File

@ -1,2 +0,0 @@
.arch-ids
.arch-inventory

View File

@ -99,7 +99,7 @@ behaviors implemented in Cisco and IBM routers."
to section G.2 (changes) in section 16.4 a change to the path
preference algorithm that prevents possible routing loops that were
possible in the old version of OSPFv2. More specifically it demands
that inter-area paths and intra-area path are now of equal preference
that inter-area paths and intra-area backbone path are now of equal preference
but still both preferred to external paths.
This command should NOT be set normally.
@ -568,10 +568,6 @@ redistributed into OSPF (@pxref{OSPF redistribute}).
@deffnx {OSPF Command} {no distance ospf} {}
@end deffn
@deffn {Command} {router zebra} {}
@deffnx {Command} {no router zebra} {}
@end deffn
@node Showing OSPF information
@section Showing OSPF information

View File

@ -86,6 +86,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of
* RIPng::
* OSPFv2::
* OSPFv3::
* Babel::
* BGP::
* Configuring Quagga as a Route Server::
* VTY shell::
@ -110,6 +111,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of
@include ripngd.texi
@include ospfd.texi
@include ospf6d.texi
@include babeld.texi
@include bgpd.texi
@include routeserver.texi
@include vtysh.texi

View File

@ -424,10 +424,10 @@ must be different. Maybe it'd be better to made new matches - say
Match if route destination is permitted by access-list.
@end deffn
@deffn {Route Map} {match ip next-hop A.B.C.D} {}
Cisco uses here <access-list>, @command{ripd} IPv4 address. Match if
route has this next-hop (meaning next-hop listed in the rip route
table - "show ip rip")
@deffn {Route Map} {match ip next-hop @var{word}} {}
@deffnx {Route Map} {match ip next-hop prefix-list @var{word}} {}
Match if route next-hop (meaning next-hop listed in the rip route-table
as displayed by "show ip rip") is permitted by access-list.
@end deffn
@deffn {Route Map} {match metric <0-4294967295>} {}

View File

@ -1,7 +0,0 @@
Makefile
*.o
zebra-guile
Makefile.in
.nfs*
.arch-inventory
.arch-ids

View File

@ -1,3 +0,0 @@
Makefile
Makefile.in
.nfs*

View File

@ -1,14 +0,0 @@
Makefile
Makefile.in
*.o
*.lo
*.la
version.c
version.h
.deps
.nfs*
.libs
.arch-inventory
.arch-ids
memtypes.h
route_types.h

View File

@ -29,10 +29,10 @@ pkginclude_HEADERS = \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
workqueue.h route_types.h
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt
memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk
($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@)
route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.awk
($(GAWK) -f $(srcdir)/route_types.awk $(srcdir)/route_types.txt > $@)
route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl
@PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@

View File

@ -1,6 +1,4 @@
/*
$Id$
Command interpreter routine for virtual terminal [aka TeletYpe]
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
@ -2402,6 +2400,7 @@ DEFUN (config_exit,
case BGP_NODE:
case RIP_NODE:
case RIPNG_NODE:
case BABEL_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case ISIS_NODE:
@ -2451,6 +2450,7 @@ DEFUN (config_end,
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
case BABEL_NODE:
case BGP_NODE:
case BGP_VPNV4_NODE:
case BGP_IPV4_NODE:

View File

@ -78,6 +78,7 @@ enum node_type
TABLE_NODE, /* rtm_table selection node. */
RIP_NODE, /* RIP protocol mode node. */
RIPNG_NODE, /* RIPng protocol mode node. */
BABEL_NODE, /* Babel protocol mode node. */
BGP_NODE, /* BGP protocol mode which includes BGP4+ */
BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */

View File

@ -299,7 +299,6 @@ DEFUN (distribute_list_all,
"Filter outgoing routing updates\n")
{
enum distribute_type type;
struct distribute *dist;
/* Check of distribute list type. */
if (strncmp (argv[1], "i", 1) == 0)
@ -314,7 +313,7 @@ DEFUN (distribute_list_all,
}
/* Get interface name corresponding distribute list. */
dist = distribute_list_set (NULL, type, argv[0]);
distribute_list_set (NULL, type, argv[0]);
return CMD_SUCCESS;
}
@ -379,7 +378,6 @@ DEFUN (distribute_list,
"Interface name\n")
{
enum distribute_type type;
struct distribute *dist;
/* Check of distribute list type. */
if (strncmp (argv[1], "i", 1) == 0)
@ -393,7 +391,7 @@ DEFUN (distribute_list,
}
/* Get interface name corresponding distribute list. */
dist = distribute_list_set (argv[2], type, argv[0]);
distribute_list_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
}
@ -407,7 +405,7 @@ ALIAS (distribute_list,
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (no_districute_list, no_distribute_list_cmd,
DEFUN (no_distribute_list, no_distribute_list_cmd,
"no distribute-list WORD (in|out) WORD",
NO_STR
"Filter networks in routing updates\n"
@ -439,7 +437,7 @@ DEFUN (no_districute_list, no_distribute_list_cmd,
return CMD_SUCCESS;
}
ALIAS (no_districute_list, no_ipv6_distribute_list_cmd,
ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd,
"no distribute-list WORD (in|out) WORD",
NO_STR
"Filter networks in routing updates\n"
@ -448,7 +446,7 @@ ALIAS (no_districute_list, no_ipv6_distribute_list_cmd,
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (districute_list_prefix_all,
DEFUN (distribute_list_prefix_all,
distribute_list_prefix_all_cmd,
"distribute-list prefix WORD (in|out)",
"Filter networks in routing updates\n"
@ -458,7 +456,6 @@ DEFUN (districute_list_prefix_all,
"Filter outgoing routing updates\n")
{
enum distribute_type type;
struct distribute *dist;
/* Check of distribute list type. */
if (strncmp (argv[1], "i", 1) == 0)
@ -473,12 +470,12 @@ DEFUN (districute_list_prefix_all,
}
/* Get interface name corresponding distribute list. */
dist = distribute_list_prefix_set (NULL, type, argv[0]);
distribute_list_prefix_set (NULL, type, argv[0]);
return CMD_SUCCESS;
}
ALIAS (districute_list_prefix_all,
ALIAS (distribute_list_prefix_all,
ipv6_distribute_list_prefix_all_cmd,
"distribute-list prefix WORD (in|out)",
"Filter networks in routing updates\n"
@ -487,7 +484,7 @@ ALIAS (districute_list_prefix_all,
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n")
DEFUN (no_districute_list_prefix_all,
DEFUN (no_distribute_list_prefix_all,
no_distribute_list_prefix_all_cmd,
"no distribute-list prefix WORD (in|out)",
NO_STR
@ -521,7 +518,7 @@ DEFUN (no_districute_list_prefix_all,
return CMD_SUCCESS;
}
ALIAS (no_districute_list_prefix_all,
ALIAS (no_distribute_list_prefix_all,
no_ipv6_distribute_list_prefix_all_cmd,
"no distribute-list prefix WORD (in|out)",
NO_STR
@ -531,7 +528,7 @@ ALIAS (no_districute_list_prefix_all,
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n")
DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
DEFUN (distribute_list_prefix, distribute_list_prefix_cmd,
"distribute-list prefix WORD (in|out) WORD",
"Filter networks in routing updates\n"
"Filter prefixes in routing updates\n"
@ -541,7 +538,6 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
"Interface name\n")
{
enum distribute_type type;
struct distribute *dist;
/* Check of distribute list type. */
if (strncmp (argv[1], "i", 1) == 0)
@ -556,12 +552,12 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
}
/* Get interface name corresponding distribute list. */
dist = distribute_list_prefix_set (argv[2], type, argv[0]);
distribute_list_prefix_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
}
ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd,
ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd,
"distribute-list prefix WORD (in|out) WORD",
"Filter networks in routing updates\n"
"Filter prefixes in routing updates\n"
@ -570,7 +566,7 @@ ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd,
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd,
"no distribute-list prefix WORD (in|out) WORD",
NO_STR
"Filter networks in routing updates\n"
@ -604,7 +600,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
return CMD_SUCCESS;
}
ALIAS (no_districute_list_prefix, no_ipv6_distribute_list_prefix_cmd,
ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd,
"no distribute-list prefix WORD (in|out) WORD",
NO_STR
"Filter networks in routing updates\n"
@ -762,22 +758,25 @@ distribute_list_init (int node)
(int (*) (const void *, const void *)) distribute_cmp);
if(node==RIP_NODE) {
install_element (RIP_NODE, &distribute_list_all_cmd);
install_element (RIP_NODE, &no_distribute_list_all_cmd);
install_element (RIP_NODE, &distribute_list_cmd);
install_element (RIP_NODE, &no_distribute_list_cmd);
install_element (RIP_NODE, &distribute_list_prefix_all_cmd);
install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd);
install_element (RIP_NODE, &distribute_list_prefix_cmd);
install_element (RIP_NODE, &no_distribute_list_prefix_cmd);
} else {
install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd);
install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd);
install_element (RIPNG_NODE, &ipv6_distribute_list_cmd);
install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd);
install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd);
install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd);
install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd);
install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd);
install_element (node, &distribute_list_all_cmd);
install_element (node, &no_distribute_list_all_cmd);
install_element (node, &distribute_list_cmd);
install_element (node, &no_distribute_list_cmd);
install_element (node, &distribute_list_prefix_all_cmd);
install_element (node, &no_distribute_list_prefix_all_cmd);
install_element (node, &distribute_list_prefix_cmd);
install_element (node, &no_distribute_list_prefix_cmd);
} else if (node == RIPNG_NODE || node == BABEL_NODE) {
/* WARNING: two identical commands installed do a crash, so be worry with
aliases. For this reason, and because all these commands are aliases, Babel
is not set with RIP. */
install_element (node, &ipv6_distribute_list_all_cmd);
install_element (node, &no_ipv6_distribute_list_all_cmd);
install_element (node, &ipv6_distribute_list_cmd);
install_element (node, &no_ipv6_distribute_list_cmd);
install_element (node, &ipv6_distribute_list_prefix_all_cmd);
install_element (node, &no_ipv6_distribute_list_prefix_all_cmd);
install_element (node, &ipv6_distribute_list_prefix_cmd);
install_element (node, &no_ipv6_distribute_list_prefix_cmd);
}
}

View File

@ -22,6 +22,9 @@
#ifndef _ZEBRA_DISTRIBUTE_H
#define _ZEBRA_DISTRIBUTE_H
#include <zebra.h>
#include "if.h"
/* Disctirubte list types. */
enum distribute_type
{

View File

@ -1337,13 +1337,13 @@ DEFUN (no_access_list_all,
master = access->master;
/* Delete all filter from access-list. */
access_list_delete (access);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
/* Delete all filter from access-list. */
access_list_delete (access);
return CMD_SUCCESS;
}
@ -1508,13 +1508,13 @@ DEFUN (no_ipv6_access_list_all,
master = access->master;
/* Delete all filter from access-list. */
access_list_delete (access);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
/* Delete all filter from access-list. */
access_list_delete (access);
return CMD_SUCCESS;
}

View File

@ -431,6 +431,7 @@ if_dump (const struct interface *ifp)
struct listnode *node;
struct connected *c;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c))
zlog_info ("Interface %s index %d metric %d mtu %d "
#ifdef HAVE_IPV6
"mtu6 %d "
@ -441,9 +442,6 @@ if_dump (const struct interface *ifp)
ifp->mtu6,
#endif /* HAVE_IPV6 */
if_flag_dump (ifp->flags));
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c))
;
}
/* Interface printing for all interface. */

View File

@ -207,7 +207,6 @@ DEFUN (if_rmap,
"Route map interface name\n")
{
enum if_rmap_type type;
struct if_rmap *if_rmap;
if (strncmp (argv[1], "i", 1) == 0)
type = IF_RMAP_IN;
@ -219,7 +218,7 @@ DEFUN (if_rmap,
return CMD_WARNING;
}
if_rmap = if_rmap_set (argv[2], type, argv[0]);
if_rmap_set (argv[2], type, argv[0]);
return CMD_SUCCESS;
}

View File

@ -1,6 +1,4 @@
/*
* $Id$
*
* Logging of zebra
* Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
*
@ -22,6 +20,8 @@
* 02111-1307, USA.
*/
#define QUAGGA_DEFINE_DESC_TABLE
#include <zebra.h>
#include "log.h"
@ -48,6 +48,7 @@ const char *zlog_proto_names[] =
"BGP",
"OSPF",
"RIPNG",
"BABEL",
"OSPF6",
"ISIS",
"MASC",
@ -776,7 +777,8 @@ lookup (const struct message *mes, int key)
* provided otherwise.
*/
const char *
mes_lookup (const struct message *meslist, int max, int index, const char *none)
mes_lookup (const struct message *meslist, int max, int index,
const char *none, const char *mesname)
{
int pos = index - meslist[0].key;
@ -799,13 +801,13 @@ mes_lookup (const struct message *meslist, int max, int index, const char *none)
{
const char *str = (meslist->str ? meslist->str : none);
zlog_debug ("message index %d [%s] found in position %d (max is %d)",
index, str, i, max);
zlog_debug ("message index %d [%s] found in %s at position %d (max is %d)",
index, str, mesname, i, max);
return str;
}
}
}
zlog_err("message index %d not found (max is %d)", index, max);
zlog_err("message index %d not found in %s (max is %d)", index, mesname, max);
assert (none);
return none;
}
@ -818,29 +820,6 @@ safe_strerror(int errnum)
return (s != NULL) ? s : "Unknown error";
}
struct zebra_desc_table
{
unsigned int type;
const char *string;
char chr;
};
#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) }
static const struct zebra_desc_table route_types[] = {
DESC_ENTRY (ZEBRA_ROUTE_SYSTEM, "system", 'X' ),
DESC_ENTRY (ZEBRA_ROUTE_KERNEL, "kernel", 'K' ),
DESC_ENTRY (ZEBRA_ROUTE_CONNECT, "connected", 'C' ),
DESC_ENTRY (ZEBRA_ROUTE_STATIC, "static", 'S' ),
DESC_ENTRY (ZEBRA_ROUTE_RIP, "rip", 'R' ),
DESC_ENTRY (ZEBRA_ROUTE_RIPNG, "ripng", 'R' ),
DESC_ENTRY (ZEBRA_ROUTE_OSPF, "ospf", 'O' ),
DESC_ENTRY (ZEBRA_ROUTE_OSPF6, "ospf6", 'O' ),
DESC_ENTRY (ZEBRA_ROUTE_ISIS, "isis", 'I' ),
DESC_ENTRY (ZEBRA_ROUTE_BGP, "bgp", 'B' ),
DESC_ENTRY (ZEBRA_ROUTE_HSLS, "hsls", 'H' ),
};
#undef DESC_ENTRY
#define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_INTERFACE_ADD),
@ -865,6 +844,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_ROUTER_ID_ADD),
DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY (ZEBRA_HELLO),
};
#undef DESC_ENTRY
@ -930,4 +910,52 @@ proto_name2num(const char *s)
return route_types[i].type;
return -1;
}
#undef RTSIZE
int
proto_redistnum(int afi, const char *s)
{
if (! s)
return -1;
if (afi == AFI_IP)
{
if (strncmp (s, "k", 1) == 0)
return ZEBRA_ROUTE_KERNEL;
else if (strncmp (s, "c", 1) == 0)
return ZEBRA_ROUTE_CONNECT;
else if (strncmp (s, "s", 1) == 0)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (s, "r", 1) == 0)
return ZEBRA_ROUTE_RIP;
else if (strncmp (s, "o", 1) == 0)
return ZEBRA_ROUTE_OSPF;
else if (strncmp (s, "i", 1) == 0)
return ZEBRA_ROUTE_ISIS;
else if (strncmp (s, "bg", 2) == 0)
return ZEBRA_ROUTE_BGP;
else if (strncmp (s, "ba", 2) == 0)
return ZEBRA_ROUTE_BABEL;
}
if (afi == AFI_IP6)
{
if (strncmp (s, "k", 1) == 0)
return ZEBRA_ROUTE_KERNEL;
else if (strncmp (s, "c", 1) == 0)
return ZEBRA_ROUTE_CONNECT;
else if (strncmp (s, "s", 1) == 0)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (s, "r", 1) == 0)
return ZEBRA_ROUTE_RIPNG;
else if (strncmp (s, "o", 1) == 0)
return ZEBRA_ROUTE_OSPF6;
else if (strncmp (s, "i", 1) == 0)
return ZEBRA_ROUTE_ISIS;
else if (strncmp (s, "bg", 2) == 0)
return ZEBRA_ROUTE_BGP;
else if (strncmp (s, "ba", 2) == 0)
return ZEBRA_ROUTE_BABEL;
}
return -1;
}

View File

@ -1,6 +1,4 @@
/*
* $Id$
*
* Zebra logging funcions.
* Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
*
@ -52,6 +50,7 @@ typedef enum
ZLOG_BGP,
ZLOG_OSPF,
ZLOG_RIPNG,
ZLOG_BABEL,
ZLOG_OSPF6,
ZLOG_ISIS,
ZLOG_MASC
@ -148,12 +147,12 @@ extern int zlog_reset_file (struct zlog *zl);
extern int zlog_rotate (struct zlog *);
/* For hackey massage lookup and check */
#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)")
#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)", #x)
extern const char *lookup (const struct message *, int);
extern const char *mes_lookup (const struct message *meslist,
int max, int index,
const char *no_item);
const char *no_item, const char *mesname);
extern const char *zlog_priority[];
extern const char *zlog_proto_names[];

View File

@ -466,6 +466,17 @@ DEFUN (show_memory_ripng,
return CMD_SUCCESS;
}
DEFUN (show_memory_babel,
show_memory_babel_cmd,
"show memory babel",
SHOW_STR
"Memory statistics\n"
"Babel memory\n")
{
show_memory_vty (vty, memory_list_babel);
return CMD_SUCCESS;
}
DEFUN (show_memory_bgp,
show_memory_bgp_cmd,
"show memory bgp",
@ -518,6 +529,7 @@ memory_init (void)
install_element (RESTRICTED_NODE, &show_memory_lib_cmd);
install_element (RESTRICTED_NODE, &show_memory_rip_cmd);
install_element (RESTRICTED_NODE, &show_memory_ripng_cmd);
install_element (RESTRICTED_NODE, &show_memory_babel_cmd);
install_element (RESTRICTED_NODE, &show_memory_bgp_cmd);
install_element (RESTRICTED_NODE, &show_memory_ospf_cmd);
install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd);
@ -528,6 +540,7 @@ memory_init (void)
install_element (VIEW_NODE, &show_memory_lib_cmd);
install_element (VIEW_NODE, &show_memory_rip_cmd);
install_element (VIEW_NODE, &show_memory_ripng_cmd);
install_element (VIEW_NODE, &show_memory_babel_cmd);
install_element (VIEW_NODE, &show_memory_bgp_cmd);
install_element (VIEW_NODE, &show_memory_ospf_cmd);
install_element (VIEW_NODE, &show_memory_ospf6_cmd);
@ -539,6 +552,7 @@ memory_init (void)
install_element (ENABLE_NODE, &show_memory_zebra_cmd);
install_element (ENABLE_NODE, &show_memory_rip_cmd);
install_element (ENABLE_NODE, &show_memory_ripng_cmd);
install_element (ENABLE_NODE, &show_memory_babel_cmd);
install_element (ENABLE_NODE, &show_memory_bgp_cmd);
install_element (ENABLE_NODE, &show_memory_ospf_cmd);
install_element (ENABLE_NODE, &show_memory_ospf6_cmd);

View File

@ -5,8 +5,6 @@
*
* The script is sensitive to the format (though not whitespace), see
* the top of memtypes.awk for more details.
*
* $Id$
*/
#include "zebra.h"
@ -176,6 +174,13 @@ struct memory_list memory_list_ripng[] =
{ -1, NULL }
};
struct memory_list memory_list_babel[] =
{
{ MTYPE_BABEL, "Babel structure" },
{ MTYPE_BABEL_IF, "Babel interface" },
{ -1, NULL }
};
struct memory_list memory_list_ospf[] =
{
{ MTYPE_OSPF_TOP, "OSPF top" },

View File

@ -32,6 +32,139 @@
static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
0xf8, 0xfc, 0xfe, 0xff};
static const struct in6_addr maskbytes6[] =
{
/* /0 */ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /1 */ { { { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /2 */ { { { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /3 */ { { { 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /4 */ { { { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /5 */ { { { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /6 */ { { { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /7 */ { { { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /8 */ { { { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /9 */ { { { 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /10 */ { { { 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /11 */ { { { 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /12 */ { { { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /13 */ { { { 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /14 */ { { { 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /15 */ { { { 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /16 */ { { { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /17 */ { { { 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /18 */ { { { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /19 */ { { { 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /20 */ { { { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /21 */ { { { 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /22 */ { { { 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /23 */ { { { 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /24 */ { { { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /25 */ { { { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /26 */ { { { 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /27 */ { { { 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /28 */ { { { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /29 */ { { { 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /30 */ { { { 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /31 */ { { { 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /32 */ { { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /33 */ { { { 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /34 */ { { { 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /35 */ { { { 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /36 */ { { { 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /37 */ { { { 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /38 */ { { { 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /39 */ { { { 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /40 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /41 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /42 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /43 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /44 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /45 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /46 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /47 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /48 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /49 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /50 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /51 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /52 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /53 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /54 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /55 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /56 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /57 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /58 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /59 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /60 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /61 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /62 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /63 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /64 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /65 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /66 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /67 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /68 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /69 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /70 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /71 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /72 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /73 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /74 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /75 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /76 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /77 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /78 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /79 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /80 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /81 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /82 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /83 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /84 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /85 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /86 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /87 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /88 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
/* /89 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 } } },
/* /90 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 } } },
/* /91 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 } } },
/* /92 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } } },
/* /93 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 } } },
/* /94 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 } } },
/* /95 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 } } },
/* /96 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
/* /97 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 } } },
/* /98 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 } } },
/* /99 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 } } },
/* /100 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } } },
/* /101 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 } } },
/* /102 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 } } },
/* /103 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 } } },
/* /104 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } } },
/* /105 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 } } },
/* /106 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 } } },
/* /107 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 } } },
/* /108 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } } },
/* /109 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 } } },
/* /110 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 } } },
/* /111 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 } } },
/* /112 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } } },
/* /113 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 } } },
/* /114 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 } } },
/* /115 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 } } },
/* /116 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 } } },
/* /117 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 } } },
/* /118 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 } } },
/* /119 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 } } },
/* /120 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 } } },
/* /121 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 } } },
/* /122 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 } } },
/* /123 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 } } },
/* /124 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 } } },
/* /125 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 } } },
/* /126 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc } } },
/* /127 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe } } },
/* /128 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } }
};
/* Number of bits in prefix type. */
#ifndef PNBBY
#define PNBBY 8
@ -39,6 +172,21 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
unsigned int
prefix_bit (const u_char *prefix, const u_char prefixlen)
{
unsigned int offset = prefixlen / 8;
unsigned int shift = 7 - (prefixlen % 8);
return (prefix[offset] >> shift) & 1;
}
unsigned int
prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen)
{
return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen);
}
/* Address Famiy Identifier to Address Family converter. */
int
afi2family (afi_t afi)
@ -133,11 +281,11 @@ prefix_same (const struct prefix *p1, const struct prefix *p2)
if (p1->family == p2->family && p1->prefixlen == p2->prefixlen)
{
if (p1->family == AF_INET)
if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
if (IPV4_ADDR_SAME (&p1->u.prefix4.s_addr, &p2->u.prefix4.s_addr))
return 1;
#ifdef HAVE_IPV6
if (p1->family == AF_INET6 )
if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
return 1;
#endif /* HAVE_IPV6 */
}
@ -167,8 +315,8 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2)
if (p1->family != p2->family || p1->prefixlen != p2->prefixlen)
return 1;
offset = p1->prefixlen / 8;
shift = p1->prefixlen % 8;
offset = p1->prefixlen / PNBBY;
shift = p1->prefixlen % PNBBY;
if (shift)
if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
@ -181,6 +329,46 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2)
return 0;
}
/*
* Count the number of common bits in 2 prefixes. The prefix length is
* ignored for this function; the whole prefix is compared. If the prefix
* address families don't match, return -1; otherwise the return value is
* in range 0 ... maximum prefix length for the address family.
*/
int
prefix_common_bits (const struct prefix *p1, const struct prefix *p2)
{
int pos, bit;
int length = 0;
u_char xor;
/* Set both prefix's head pointer. */
const u_char *pp1 = (const u_char *)&p1->u.prefix;
const u_char *pp2 = (const u_char *)&p2->u.prefix;
if (p1->family == AF_INET)
length = IPV4_MAX_BYTELEN;
#ifdef HAVE_IPV6
if (p1->family == AF_INET6)
length = IPV6_MAX_BYTELEN;
#endif
if (p1->family != p2->family || !length)
return -1;
for (pos = 0; pos < length; pos++)
if (pp1[pos] != pp2[pos])
break;
if (pos == length)
return pos * 8;
xor = pp1[pos] ^ pp2[pos];
for (bit = 0; bit < 8; bit++)
if (xor & (1 << (7 - bit)))
break;
return pos * 8 + bit;
}
/* Return prefix family type string. */
const char *
prefix_family_str (const struct prefix *p)
@ -261,25 +449,20 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
return ret;
}
/* Convert masklen into IP address's netmask. */
/* Convert masklen into IP address's netmask (network byte order). */
void
masklen2ip (int masklen, struct in_addr *netmask)
masklen2ip (const int masklen, struct in_addr *netmask)
{
u_char *pnt;
int bit;
int offset;
assert (masklen >= 0 && masklen <= IPV4_MAX_BITLEN);
memset (netmask, 0, sizeof (struct in_addr));
pnt = (unsigned char *) netmask;
/* left shift is only defined for less than the size of the type.
* we unconditionally use long long in case the target platform
* has defined behaviour for << 32 (or has a 64-bit left shift) */
offset = masklen / 8;
bit = masklen % 8;
while (offset--)
*pnt++ = 0xff;
if (bit)
*pnt = maskbit[bit];
if (sizeof(unsigned long long) > 4)
netmask->s_addr = htonl(0xffffffffULL << (32 - masklen));
else
netmask->s_addr = htonl(masklen ? 0xffffffffU << (32 - masklen) : 0);
}
/* Convert IP address's netmask into integer. We assume netmask is
@ -287,54 +470,22 @@ masklen2ip (int masklen, struct in_addr *netmask)
u_char
ip_masklen (struct in_addr netmask)
{
u_char len;
u_char *pnt;
u_char *end;
u_char val;
len = 0;
pnt = (u_char *) &netmask;
end = pnt + 4;
while ((pnt < end) && (*pnt == 0xff))
{
len+= 8;
pnt++;
uint32_t tmp = ~ntohl(netmask.s_addr);
if (tmp)
/* clz: count leading zeroes. sadly, the behaviour of this builtin
* is undefined for a 0 argument, even though most CPUs give 32 */
return __builtin_clz(tmp);
else
return 32;
}
if (pnt < end)
{
val = *pnt;
while (val)
{
len++;
val <<= 1;
}
}
return len;
}
/* Apply mask to IPv4 prefix. */
/* Apply mask to IPv4 prefix (network byte order). */
void
apply_mask_ipv4 (struct prefix_ipv4 *p)
{
u_char *pnt;
int index;
int offset;
index = p->prefixlen / 8;
if (index < 4)
{
pnt = (u_char *) &p->prefix;
offset = p->prefixlen % 8;
pnt[index] &= maskbit[offset];
index++;
while (index < 4)
pnt[index++] = 0;
}
struct in_addr mask;
masklen2ip(p->prefixlen, &mask);
p->prefix.s_addr &= mask.s_addr;
}
/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
@ -396,7 +547,7 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
if (ret == 0)
return 0;
plen = (u_char) atoi (++pnt);
if (plen > 128)
if (plen > IPV6_MAX_BITLEN)
return 0;
p->prefixlen = plen;
}
@ -416,13 +567,13 @@ ip6_masklen (struct in6_addr netmask)
pnt = (unsigned char *) & netmask;
while ((*pnt == 0xff) && len < 128)
while ((*pnt == 0xff) && len < IPV6_MAX_BITLEN)
{
len += 8;
pnt++;
}
if (len < 128)
if (len < IPV6_MAX_BITLEN)
{
val = *pnt;
while (val)
@ -435,23 +586,10 @@ ip6_masklen (struct in6_addr netmask)
}
void
masklen2ip6 (int masklen, struct in6_addr *netmask)
masklen2ip6 (const int masklen, struct in6_addr *netmask)
{
unsigned char *pnt;
int bit;
int offset;
memset (netmask, 0, sizeof (struct in6_addr));
pnt = (unsigned char *) netmask;
offset = masklen / 8;
bit = masklen % 8;
while (offset--)
*pnt++ = 0xff;
if (bit)
*pnt = maskbit[bit];
assert (masklen >= 0 && masklen <= IPV6_MAX_BITLEN);
memcpy (netmask, maskbytes6 + masklen, sizeof (struct in6_addr));
}
void
@ -570,6 +708,20 @@ sockunion2hostprefix (const union sockunion *su)
return NULL;
}
void
prefix2sockunion (const struct prefix *p, union sockunion *su)
{
memset (su, 0, sizeof (*su));
su->sa.sa_family = p->family;
if (p->family == AF_INET)
su->sin.sin_addr = p->u.prefix4;
#ifdef HAVE_IPV6
if (p->family == AF_INET6)
memcpy (&su->sin6.sin6_addr, &p->u.prefix6, sizeof (struct in6_addr));
#endif /* HAVE_IPV6 */
}
int
prefix_blen (const struct prefix *p)
{

View File

@ -112,6 +112,7 @@ struct prefix_rd
#define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000)
#define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)
#define IPV4_LINKLOCAL(a) ((((u_int32_t) (a)) & 0xffff0000) == 0xa9fe0000)
#define IPV4_CLASS_DE(a) ((((u_int32_t) (a)) & 0xe0000000) == 0xe0000000)
/* Max bit/byte length of IPv6 address. */
#define IPV6_MAX_BYTELEN 16
@ -127,26 +128,14 @@ struct prefix_rd
/* Prefix's family member. */
#define PREFIX_FAMILY(p) ((p)->family)
/* Check bit of the prefix. */
static inline unsigned int
prefix_bit (const u_char *prefix, const u_char prefixlen)
{
unsigned int offset = prefixlen / 8;
unsigned int shift = 7 - (prefixlen % 8);
return (prefix[offset] >> shift) & 1;
}
static inline unsigned int
prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen)
{
return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen);
}
/* Prototypes. */
extern int afi2family (afi_t);
extern afi_t family2afi (int);
/* Check bit of the prefix. */
extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen);
extern unsigned int prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen);
extern struct prefix *prefix_new (void);
extern void prefix_free (struct prefix *);
extern const char *prefix_family_str (const struct prefix *);
@ -156,12 +145,14 @@ extern int prefix2str (const struct prefix *, char *, int);
extern int prefix_match (const struct prefix *, const struct prefix *);
extern int prefix_same (const struct prefix *, const struct prefix *);
extern int prefix_cmp (const struct prefix *, const struct prefix *);
extern int prefix_common_bits (const struct prefix *, const struct prefix *);
extern void prefix_copy (struct prefix *dest, const struct prefix *src);
extern void apply_mask (struct prefix *);
extern struct prefix *sockunion2prefix (const union sockunion *dest,
const union sockunion *mask);
extern struct prefix *sockunion2hostprefix (const union sockunion *);
extern void prefix2sockunion (const struct prefix *, union sockunion *);
extern struct prefix_ipv4 *prefix_ipv4_new (void);
extern void prefix_ipv4_free (struct prefix_ipv4 *);
@ -175,7 +166,7 @@ extern int prefix_ipv4_any (const struct prefix_ipv4 *);
extern void apply_classful_mask_ipv4 (struct prefix_ipv4 *);
extern u_char ip_masklen (struct in_addr);
extern void masklen2ip (int, struct in_addr *);
extern void masklen2ip (const int, struct in_addr *);
/* returns the network portion of the host address */
extern in_addr_t ipv4_network_addr (in_addr_t hostaddr, int masklen);
/* given the address of a host on a network and the network mask length,
@ -196,7 +187,7 @@ extern void apply_mask_ipv6 (struct prefix_ipv6 *);
*((struct prefix_ipv6 *)(DST)) = *((const struct prefix_ipv6 *)(SRC));
extern int ip6_masklen (struct in6_addr);
extern void masklen2ip6 (int, struct in6_addr *);
extern void masklen2ip6 (const int, struct in6_addr *);
extern void str2in6_addr (const char *, struct in6_addr *);
extern const char *inet6_ntoa (struct in6_addr);

View File

@ -1,187 +0,0 @@
# $Id$
#
# Scan a file of route-type definitions (see eg route_types.txt) and
# generate a corresponding header file with:
#
# - enum of Zserv route-types
# - redistribute strings for the various Quagga daemons
#
# See route_types.txt for the format.
#
#
BEGIN {
FS="[,]";
# globals
exitret = 0;
tcount = 0;
# formats for output
## the define format
redist_def_fmt = "#define QUAGGA_REDIST_STR_%s \\\n";
## DEFUN/vty route-type argument
redist_str_fmt = "\"(%s)\"\n";
redist_help_def_fmt = "#define QUAGGA_REDIST_HELP_STR_%s";
redist_help_str_fmt = " \\\n \"%s\\n\"";
# header
header = "/* Auto-generated from route_types.txt by " ARGV[0] ". */\n";
header = header "/* Do not edit! */\n";
header = header "\n#ifndef _QUAGGA_ROUTE_TYPES_H\n";
header = header "#define _QUAGGA_ROUTE_TYPES_H\n";
footer = "#endif /* _QUAGGA_ROUTE_TYPES_H */\n";
printf ("%s\n", header);
}
# Chomp comment lines
($0 ~ /^#/) {
next;
}
# get rid of the commas, leading/trailling whitespace and
# quotes
{
for (i = 1; i <= NF; i++) {
#print "before:" $i;
$i = gensub(/^[[:blank:]]*(.*)[,]*.*/, "\\1", "g",$i);
$i = gensub(/^["](.*)["]$/, "\\1", "g", $i);
#print "after :" $i;
}
}
# 7 field format:
# type cname daemon C 4 6 short help
(NF >= 7) {
#print "7", $1, $0;
if ($1 in types) {
print "error: attempt to redefine", $1;
exitret = 1;
exit exitret;
}
typesbynum[tcount] = $1;
types[$1,"num"] = tcount++;
types[$1,"cname"] = $2;
types[$1,"daemon"] = $3;
types[$1,"C"] = $4;
types[$1,"4"] = strtonum($5);
types[$1,"6"] = strtonum($6);
types[$1,"shelp"] = $7;
#print "num :", types[$1,"num"]
#print "cname :", types[$1,"cname"]
#print "daemon:", types[$1,"daemon"];
#print "char :", types[$1,"C"];
};
# 2 field: type "long description"
(NF == 2) {
#print "2", $1, $2;
if (!(($1 SUBSEP "num") in types)) {
print "error: type", $1, "must be defined before help str";
exitret = 2;
exit exitret;
}
types[$1,"lhelp"] = $2;
}
END {
if (exitret)
exit exitret;
# The enums
# not yet...
#printf("enum\n{\n");
#for (i = 0; i < tcount; i++) {
# type = typesbynum[i];
# if (type != "" && types[type,"num"] == i)
# printf (" %s,\n", type);
#}
#printf (" ZEBRA_ROUTE_MAX,\n};\n\n");
# the redistribute defines
for (i = 0; i < tcount; i++) {
type = typesbynum[i];
# must be a type, and must cross-check against recorded type
if (type == "" || types[type,"num"] != i)
continue;
# ignore route types that can't be redistributed
if (!(types[type,"4"] || types[type,"6"]))
continue;
# must have a daemon name
if (!((type SUBSEP "daemon") in types))
continue;
if (!(daemon = types[type,"daemon"]))
continue;
# might have done this daemon already?
if (daemon in seen_daemons)
continue;
cname = types[type,"cname"];
all = all "|" cname;
rstr = "";
hstr = "";
# add it to the others
for (j = 0; j < tcount; j++) {
# ignore self
if (i == j)
continue;
type2 = typesbynum[j];
# type2 must be valid, and self-check.
if (type2 == "" || types[type2,"num"] != j)
continue;
# ignore different route types for the same daemon
# (eg system/kernel/connected)
if (types[type2,"daemon"] == daemon)
continue;
if ((types[type2,"4"] && types[type,"4"]) \
|| (types[type2,"6"] && types[type,"6"])) {
if (rstr == "")
rstr = types[type2,"cname"];
else
rstr = rstr "|" types[type2,"cname"];
if ((type2 SUBSEP "lhelp") in types)
hstr2 = types[type2,"lhelp"];
else if ((type2 SUBSEP "shelp") in types)
hstr2 = types[type2,"shelp"];
else
hstr2 = types[type2,"cname"];
hstr = hstr sprintf(redist_help_str_fmt, hstr2);
}
}
# dont double-process daemons.
seen_daemons[daemon] = 1;
printf("/* %s */\n", daemon);
printf(redist_def_fmt, toupper(daemon));
printf(redist_str_fmt, rstr);
printf(redist_help_def_fmt, toupper(daemon));
printf("%s", hstr);
printf("\n\n");
}
#printf("#define QUAGGA_REDIST_STR_ALL %s\n",all);
# for (i = 0; i < lcount; i++) {
# if (mlists[i] != "")
# printf (mlistformat "\n", mlists[i]);
# }
printf (footer);
}

199
lib/route_types.pl Executable file
View File

@ -0,0 +1,199 @@
#!/usr/bin/perl
##
## Scan a file of route-type definitions (see eg route_types.txt) and
## generate a corresponding header file with:
##
## - enum of Zserv route-types
## - redistribute strings for the various Quagga daemons
##
## See route_types.txt for the format.
##
##
## Copyright (C) 2009 David Lamparter.
## This file is part of GNU Zebra.
##
## GNU Zebra is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by the
## Free Software Foundation; either version 2, or (at your option) any
## later version.
##
## GNU Zebra is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with GNU Zebra; see the file COPYING. If not, write to the Free
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
## 02111-1307, USA.
##
use strict;
# input processing
#
my @protos;
my %protodetail;
my %daemons;
while (<STDIN>) {
# skip comments and empty lines
next if (/^\s*(#|$)/);
# strip whitespace
chomp;
$_ =~ s/^\s*//;
$_ =~ s/\s*$//;
# match help strings
if (/^(ZEBRA_ROUTE_[^\s]+)\s*,\s*"(.*)"$/) {
$protodetail{$1}->{'longhelp'} = $2;
next;
}
$_ =~ s/\s*,\s*/,/g;
# else: 7-field line
my @f = split(/,/, $_);
unless (@f == 7) {
die "invalid input on route_types line $.\n";
}
my $proto = $f[0];
$f[3] = $1 if ($f[3] =~ /^'(.*)'$/);
$f[6] = $1 if ($f[6] =~ /^"(.*)"$/);
$protodetail{$proto} = {
"number" => scalar @protos,
"type" => $f[0],
"cname" => $f[1],
"daemon" => $f[2],
"char" => $f[3],
"ipv4" => int($f[4]),
"ipv6" => int($f[5]),
"shorthelp" => $f[6],
};
push @protos, $proto;
$daemons{$f[2]} = {
"ipv4" => int($f[4]),
"ipv6" => int($f[5])
} unless ($f[2] eq "NULL");
}
# output
printf <<EOF, $ARGV[0];
/* Auto-generated from route_types.txt by %s. */
/* Do not edit! */
#ifndef _QUAGGA_ROUTE_TYPES_H
#define _QUAGGA_ROUTE_TYPES_H
/* Zebra route's types. */
EOF
push @protos, "ZEBRA_ROUTE_MAX";
my (@protosv4, @protosv6) = ((), ());
for (my $c = 0; $c < @protos; $c++) {
my $p = $protos[$c];
printf "#define %-32s %d\n", $p, $c;
push @protosv4, $p if ($protodetail{$p}->{"ipv4"});
push @protosv6, $p if ($protodetail{$p}->{"ipv6"});
}
pop @protos;
sub codelist {
my (@protos) = @_;
my (@lines) = ();
my $str = " \"Codes: ";
for my $p (@protos) {
my $s = sprintf("%s - %s, ",
$protodetail{$p}->{"char"},
$protodetail{$p}->{"shorthelp"});
if (length($str . $s) > 70) {
$str =~ s/ $//;
push @lines, $str . "%s\" \\\n";
$str = " \" ";
}
$str .= $s;
}
$str =~ s/ $//;
push @lines, $str . "%s\" \\\n";
push @lines, " \" > - selected route, * - FIB route%s%s\", \\\n";
my @nl = ();
for (my $c = 0; $c < @lines + 1; $c++) {
push @nl, "VTY_NEWLINE"
}
return join("", @lines) ." ". join(", ", @nl);
}
print "\n";
printf "#define SHOW_ROUTE_V4_HEADER \\\n%s\n", codelist(@protosv4);
printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6);
print "\n";
sub collect {
my ($daemon, $ipv4, $ipv6) = @_;
my (@names, @help) = ((), ());
for my $p (@protos) {
next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra");
next unless (($ipv4 && $protodetail{$p}->{"ipv4"})
|| ($ipv6 && $protodetail{$p}->{"ipv6"}));
push @names, $protodetail{$p}->{"cname"};
push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\"";
}
return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help));
}
for my $daemon (sort keys %daemons) {
next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"});
printf "/* %s */\n", $daemon;
if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) {
my ($names, $help) = collect($daemon, 1, 1);
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
($names, $help) = collect($daemon, 1, 0);
printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
($names, $help) = collect($daemon, 0, 1);
printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
} else {
my ($names, $help) = collect($daemon,
$daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"});
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
}
print "\n";
}
print <<EOF;
#ifdef QUAGGA_DEFINE_DESC_TABLE
struct zebra_desc_table
{
unsigned int type;
const char *string;
char chr;
};
#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) }
static const struct zebra_desc_table route_types[] = {
EOF
for (my $c = 0; $c < @protos; $c++) {
my $p = $protos[$c];
printf " DESC_ENTRY\t(%s\t \"%s\",\t'%s' ),\n",
$p.",", $protodetail{$p}->{"cname"}, $protodetail{$p}->{"char"};
}
print <<EOF;
};
#undef DESC_ENTRY
#endif /* QUAGGA_DEFINE_DESC_TABLE */
#endif /* _QUAGGA_ROUTE_TYPES_H */
EOF

View File

@ -42,13 +42,13 @@
## type cname daemon C 4 6 short help
ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, "Reserved"
ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, NULL
ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, NULL
ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, NULL
ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, "kernel route"
ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, "connected"
ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, "static"
ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, "RIP"
ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, "RIPng"
ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, "OSPF"
ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPF"
ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6"
ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS"
ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
# HSLS and OLSR both are AFI independent (so: 1, 1), however
@ -57,7 +57,8 @@ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
# to 'switch on' redist support (direct numeric entry remaining
# possible).
ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
ZEBRA_ROUTE_OLSR, olsr, oslrd, 'o', 0, 0, "OLSR"
ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
## help strings
ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
@ -72,3 +73,4 @@ ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"

View File

@ -43,6 +43,7 @@ typedef enum
{
RMAP_RIP,
RMAP_RIPNG,
RMAP_BABEL,
RMAP_OSPF,
RMAP_OSPF6,
RMAP_BGP,

Some files were not shown because too many files have changed in this diff Show More