mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-25 01:03:34 +00:00
Merge branch 'master' into stylechecker
This commit is contained in:
commit
42732e05a9
3
.gitignore
vendored
3
.gitignore
vendored
@ -82,3 +82,6 @@ GPATH
|
||||
*.lo
|
||||
compile_commands.json
|
||||
.dirstamp
|
||||
|
||||
# clippy generated source
|
||||
*_clippy.c
|
||||
|
||||
499
COMMUNITY.md
499
COMMUNITY.md
@ -1,498 +1 @@
|
||||
Developing for FRRouting
|
||||
=========================
|
||||
|
||||
## Table of Contents
|
||||
|
||||
[TOC]
|
||||
|
||||
## General note on this document
|
||||
|
||||
This document is "descriptive/post-factual" in that it documents pratices that
|
||||
are in use; it is not "definitive/pre-factual" in prescribing practices.
|
||||
|
||||
This means that when a procedure changes, it is agreed upon, then put into
|
||||
practice, and then documented here. If this document doesn't match reality,
|
||||
it's the document that needs to be updated, not reality.
|
||||
|
||||
|
||||
## Git Structure
|
||||
|
||||
The master Git for FRRouting resides on Github at
|
||||
[https://github.com/frrouting/frr](https://github.com/FRRouting/frr)
|
||||
|
||||

|
||||
|
||||
There is one main branch for development and a release branch for each major
|
||||
release.
|
||||
|
||||
New contributions are done against the head of the master branch. The CI
|
||||
systems will pick up the Github Pull Requests or the new patch from Patchwork,
|
||||
run some basic build and functional tests.
|
||||
|
||||
For each major release (1.0, 1.1 etc) a new release branch is created based on
|
||||
the master.
|
||||
|
||||
There was an attempt to use a "develop" branch automatically maintained by the
|
||||
CI system. This is not currently in active use, though the system is
|
||||
operational. If the "develop" branch is in active use and this paragraph is
|
||||
still here, this document obviously wasn't updated.
|
||||
|
||||
|
||||
## Programming language, Tools and Libraries
|
||||
|
||||
The core of FRRouting is written in C (gcc or clang supported) and makes use of
|
||||
GNU compiler extensions. A few non-essential scripts are implemented in Perl
|
||||
and Python. FRRouting requires the following tools to build distribution
|
||||
packages: automake, autoconf, texinfo, libtool and gawk and various libraries
|
||||
(i.e. libpam and libjson-c).
|
||||
|
||||
If your contribution requires a new library or other tool, then please
|
||||
highlight this in your description of the change. Also make sure it’s supported
|
||||
by all FRRouting platform OSes or provide a way to build without the library
|
||||
(potentially without the new feature) on the other platforms.
|
||||
|
||||
Documentation should be written in Tex (.texi) or Markdown (.md) format with a
|
||||
preference for Markdown.
|
||||
|
||||
|
||||
## Mailing lists
|
||||
|
||||
Italicized lists are private.
|
||||
|
||||
| Topic | List |
|
||||
|--------------------------------|------------------------------|
|
||||
| Development | dev@lists.frrouting.org |
|
||||
| Users & Operators | frog@lists.frrouting.org |
|
||||
| Announcements | announce@lists.frrouting.org |
|
||||
| _Security_ | security@lists.frrouting.org |
|
||||
| _Technical Steering Committee_ | tsc@lists.frrouting.org |
|
||||
|
||||
The Development list is used to discuss and document general issues
|
||||
related to project development and governance. The public Slack
|
||||
instance, frrouting.slack.com, and weekly technical meetings provide a
|
||||
higher bandwidth channel for discussions. The results of such
|
||||
discussions must be reflected in updates, as appropriate, to code (i.e.,
|
||||
merges), [github](https://github.com/FRRouting/frr/issues) tracked
|
||||
issues, and for governance or process changes, updates to the
|
||||
Development list and either this file or information posted at
|
||||
[https://frrouting.org/](https://frrouting.org/).
|
||||
|
||||
|
||||
### Changelog
|
||||
|
||||
The changelog will be the base for the release notes. A changelog entry for
|
||||
your changes is usually not required and will be added based on your commit
|
||||
messages by the maintainers. However, you are free to include an update to
|
||||
the changelog with some better description. The changelog will be the base
|
||||
for the release notes.
|
||||
|
||||
|
||||
## Submitting Patches and Enhancements
|
||||
|
||||
### Pre-submission Checklist
|
||||
|
||||
* Format code (see [Developer's Guidelines](#developers-guidelines))
|
||||
* Verify and acknowledge license (see [License for contributions](#license-for-contributions))
|
||||
* Ensure you have properly signed off (see [Signing Off](#signing-off))
|
||||
* Test building with various configurations:
|
||||
* `buildtest.sh`
|
||||
* Verify building source distribution:
|
||||
* `make dist` (and try rebuilding from the resulting tar file)
|
||||
* Run unit tests:
|
||||
* `make test`
|
||||
* Document Regression Runs and plans for continued maintenance of the feature
|
||||
|
||||
### License for contributions
|
||||
|
||||
FRRouting is under a “GPLv2 or later” license. Any code submitted must be
|
||||
released under the same license (preferred) or any license which allows
|
||||
redistribution under this GPLv2 license (eg MIT License).
|
||||
|
||||
### Signing Off
|
||||
|
||||
Code submitted to FRRouting must be signed off. We have the same requirements
|
||||
for using the signed-off-by process as the Linux kernel. In short, you must
|
||||
include a signed-off-by tag in every patch.
|
||||
|
||||
`Signed-off-by:` this is a developer's certification that he or she has the
|
||||
right to submit the patch for inclusion into the project. It is an agreement to
|
||||
the Developer's Certificate of Origin (below). Code without a proper signoff
|
||||
can not and will not be merged.
|
||||
|
||||
If you are unfamiliar with this process, you should read the [official policy
|
||||
at kernel.org](https://www.kernel.org/doc/html/latest/process/submitting-patches.html) and
|
||||
you might find this article about [participating in the Linux community on the
|
||||
Linux Foundation
|
||||
website](http://www.linuxfoundation.org/content/how-participate-linux-community-0)
|
||||
to be a helpful resource.
|
||||
|
||||
In short, when you sign off on a commit, you assert your agreement to all of
|
||||
the following:
|
||||
|
||||
> Developer's Certificate of Origin 1.1
|
||||
>
|
||||
> By making a contribution to this project, I certify that:
|
||||
>
|
||||
> (a) The contribution was created in whole or in part by me and I
|
||||
> have the right to submit it under the open source license
|
||||
> indicated in the file; or
|
||||
>
|
||||
> (b) The contribution is based upon previous work that, to the best
|
||||
> of my knowledge, is covered under an appropriate open source
|
||||
> license and I have the right under that license to submit that
|
||||
> work with modifications, whether created in whole or in part
|
||||
> by me, under the same open source license (unless I am
|
||||
> permitted to submit under a different license), as indicated
|
||||
> in the file; or
|
||||
>
|
||||
> (c) The contribution was provided directly to me by some other
|
||||
> person who certified (a), (b) or (c) and I have not modified
|
||||
> it.
|
||||
>
|
||||
> (d) I understand and agree that this project and the contribution
|
||||
> are public and that a record of the contribution (including all
|
||||
> personal information I submit with it, including my sign-off) is
|
||||
> maintained indefinitely and may be redistributed consistent with
|
||||
> this project or the open source license(s) involved.
|
||||
|
||||
### What do I submit my changes against?
|
||||
|
||||
We've documented where we would like to have the different fixes applied at
|
||||
https://github.com/FRRouting/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F
|
||||
If you are unsure where your submission goes, look at that document or ask a
|
||||
project maintainer.
|
||||
|
||||
### Github pull requests
|
||||
|
||||
The preferred method of submitting changes is a Github pull request. Code
|
||||
submitted by pull request will be automatically tested by one or more CI
|
||||
systems. Once the automated tests succeed, other developers will review your
|
||||
code for quality and correctness. After any concerns are resolved, your code
|
||||
will be merged into the branch it was submitted against.
|
||||
|
||||
### Patch submission via mailing list
|
||||
|
||||
As an alternative submission method, a patch can be mailed to the development
|
||||
mailing list. Patches received on the mailing list will be picked up by
|
||||
Patchwork and tested against the latest development branch.
|
||||
|
||||
The recommended way to send the patch (or series of NN patches) to the list is
|
||||
by using `git send-email` as follows (assuming they are the N most recent
|
||||
commit(s) in your git history:
|
||||
|
||||
```
|
||||
git send-email -NN --annotate --to=dev@lists.frrouting.org
|
||||
```
|
||||
|
||||
If your commits do not already contain a `Signed-off-by` line, then use the
|
||||
following command to add it (after making sure you agree to the Developer
|
||||
Certificate of Origin as outlined above):
|
||||
|
||||
```
|
||||
git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
|
||||
```
|
||||
|
||||
Submitting multi-commit patches as a Github pull request is **strongly
|
||||
encouraged** and increases the probability of your patch getting reviewed and
|
||||
merged in a timely manner.
|
||||
|
||||
|
||||
## After submitting your changes
|
||||
|
||||
* Watch for Continuous Integration (CI) Test results
|
||||
* You should automatically receive an email with the test results within
|
||||
less than 2 hrs of the submission. If you don’t get the email, then check
|
||||
status on the github pull request (if submitted by pull request) or on
|
||||
Patchwork at
|
||||
[https://patchwork.frrouting.org](https://patchwork.frrouting.org) (if
|
||||
submitted as patch to mailing list).
|
||||
* Please notify the development mailing list if you think something doesn’t
|
||||
work.
|
||||
* If the tests failed:
|
||||
* In general, expect the community to ignore the submission until the tests
|
||||
pass.
|
||||
* It is up to you to fix and resubmit.
|
||||
* This includes fixing existing unit (“make test”) tests if your
|
||||
changes broke or changed them.
|
||||
* It also includes fixing distribution packages for the failing
|
||||
platforms (ie if new libraries are required).
|
||||
* Feel free to ask for help on the development list.
|
||||
* Go back to the submission process and repeat until the tests pass.
|
||||
* If the tests pass:
|
||||
* Wait for reviewers. Someone will review your code or be assigned to
|
||||
review your code.
|
||||
* Respond to any comments or concerns the reviewer has.
|
||||
* After all comments and concerns are addressed, expect your patch to be
|
||||
merged.
|
||||
* Watch out for questions on the mailing list. At this time there will be a
|
||||
manual code review and further (longer) tests by various community members.
|
||||
* Your submission is done once it is merged to the master branch.
|
||||
|
||||
|
||||
## Developer's Guidelines
|
||||
|
||||
### Commit messages
|
||||
|
||||
Commit messages should be formatted in the same way as Linux kernel commit
|
||||
messages. The format is roughly
|
||||
|
||||
```
|
||||
dir: short summary
|
||||
|
||||
extended summary
|
||||
```
|
||||
|
||||
`dir` should be the top level source directory under which the change was made.
|
||||
For example, a change in bgpd/rfapi would be formatted as:
|
||||
|
||||
`bgpd: short summary`
|
||||
|
||||
The first line should be no longer than 50 characters. Subsequent lines should
|
||||
be wrapped to 72 characters.
|
||||
|
||||
### Source file header
|
||||
|
||||
New files need to have a Copyright header (see [License for
|
||||
contributions](#license-for-contributions) above) added to the file. Preferred
|
||||
form of the header is as follows:
|
||||
|
||||
```
|
||||
/*
|
||||
* Title/Function of file
|
||||
* Copyright (C) YEAR Author’s Name
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
```
|
||||
|
||||
### Adding copyright claims to existing files
|
||||
|
||||
When adding copyright claims for modifications to an existing file, please
|
||||
preface the claim with "Portions: " on a line before it and indent the
|
||||
"Copyright ..." string. If such a case already exists, add your indented claim
|
||||
immediately after. E.g.:
|
||||
|
||||
```
|
||||
Portions:
|
||||
Copyright (C) 2010 Entity A ....
|
||||
Copyright (C) 2016 Your name [optional brief change description]
|
||||
```
|
||||
|
||||
### Code formatting
|
||||
|
||||
FRR uses Linux kernel style except where noted below. Code which does not
|
||||
comply with these style guidelines will not be accepted.
|
||||
|
||||
To assist with compliance, in the project root there is a .clang-format
|
||||
configuration file which can be used with the `clang-format` tool from the LLVM
|
||||
project. In the `tools/` directory there is a Python script named `indent.py`
|
||||
that wraps clang-format and handles some edge cases specific to FRR. If you are
|
||||
submitting a new file, it is recommended to run that script over the new file
|
||||
after ensuring that the latest stable release of `clang-format` is in your
|
||||
PATH.
|
||||
|
||||
**Whitespace changes in untouched parts of the code are not acceptable in
|
||||
patches that change actual code.** To change/fix formatting issues, please
|
||||
create a separate patch that only does formatting changes and nothing else.
|
||||
|
||||
#### Style documentation
|
||||
Kernel and BSD styles are documented externally:
|
||||
|
||||
* [https://www.kernel.org/doc/html/latest/process/coding-style.html](https://www.kernel.org/doc/html/latest/process/coding-style.html)
|
||||
* [http://man.openbsd.org/style](http://man.openbsd.org/style)
|
||||
|
||||
For GNU coding style, use `indent` with the following invocation:
|
||||
|
||||
```
|
||||
indent -nut -nfc1 file_for_submission.c
|
||||
```
|
||||
|
||||
#### Exceptions
|
||||
|
||||
FRR project code comes from a variety of sources, so there are some stylistic
|
||||
exceptions in place. They are organized here by branch.
|
||||
|
||||
**For `master`:**
|
||||
|
||||
BSD coding style applies to:
|
||||
|
||||
* `ldpd/`
|
||||
|
||||
`babeld` uses, approximately, the following style:
|
||||
|
||||
* K&R style braces
|
||||
* Indents are 4 spaces
|
||||
* Function return types are on their own line
|
||||
|
||||
|
||||
**For `stable/3.0` and `stable/2.0`:**
|
||||
|
||||
GNU coding style apply to the following parts:
|
||||
|
||||
* `lib/`
|
||||
* `zebra/`
|
||||
* `bgpd/`
|
||||
* `ospfd/`
|
||||
* `ospf6d/`
|
||||
* `isisd/`
|
||||
* `ripd/`
|
||||
* `ripngd/`
|
||||
* `vtysh/`
|
||||
|
||||
BSD coding style applies to:
|
||||
|
||||
* `ldpd/`
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
FRRouting is a large and complex software project developed by many different
|
||||
people over a long period of time. Without adequate documentation, it can be
|
||||
exceedingly difficult to understand code segments, APIs and other interfaces.
|
||||
In the interest of keeping the project healthy and maintainable, you should
|
||||
make every effort to document your code so that other people can understand
|
||||
what it does without needing to closely read the code itself.
|
||||
|
||||
Some specific guidelines that contributors should follow are:
|
||||
|
||||
* Functions exposed in header files should have descriptive comments above
|
||||
their signatures in the header file. At a minimum, a function comment should
|
||||
contain information about the return value, parameters, and a general summary
|
||||
of the function's purpose. Documentation on parameter values can be omitted
|
||||
if it is (very) obvious what they are used for.
|
||||
|
||||
Function comments must follow the style for multiline comments laid out in
|
||||
the kernel style guide.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
/*
|
||||
* Determines whether or not a string is cool.
|
||||
*
|
||||
* @param text - the string to check for coolness
|
||||
* @param is_clccfc - whether capslock is cruise control for cool
|
||||
* @return 7 if the text is cool, 0 otherwise
|
||||
*/
|
||||
int check_coolness(const char *text, bool is_clccfc);
|
||||
```
|
||||
|
||||
The Javadoc-style annotations are not required, but you should still strive to
|
||||
make it equally clear what parameters and return values are used for.
|
||||
|
||||
* Static functions should have descriptive comments in the same form as above
|
||||
if what they do is not immediately obvious. Use good engineering judgement
|
||||
when deciding whether a comment is necessary. If you are unsure, document
|
||||
your code.
|
||||
|
||||
* Global variables, static or not, should have a comment describing their use.
|
||||
|
||||
* **For new code in `lib/`, these guidelines are hard requirements.**
|
||||
|
||||
|
||||
If you are contributing code that adds significant user-visible functionality
|
||||
or introduces a new API, please document it in `doc/`. Markdown and LaTeX are
|
||||
acceptable formats, although Markdown is currently preferred for new
|
||||
documentation. This may change in the near future.
|
||||
|
||||
Finally, if you come across some code that is undocumented and feel like going
|
||||
above and beyond, document it! We absolutely appreciate and accept patches that
|
||||
document previously undocumented code.
|
||||
|
||||
### Compile-time conditional code
|
||||
|
||||
Many users access FRR via binary packages from 3rd party sources; compile-time
|
||||
code puts inclusion/exclusion in the hands of the package maintainer. Please
|
||||
think very carefully before making code conditional at compile time, as it
|
||||
increases regression testing, maintenance burdens, and user confusion. In
|
||||
particular, please avoid gratuitous `--enable-…` switches to the configure
|
||||
script - in general, code should be of high quality and in working condition,
|
||||
or it shouldn’t be in FRR 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. For example,
|
||||
|
||||
```
|
||||
if (SOME_SYMBOL)
|
||||
frobnicate();
|
||||
```
|
||||
|
||||
is preferred to
|
||||
|
||||
```
|
||||
#ifdef SOME_SYMBOL
|
||||
frobnicate ();
|
||||
#endif /* SOME_SYMBOL */
|
||||
```
|
||||
|
||||
Note that the former approach requires ensuring that `SOME_SYMBOL` will be
|
||||
defined (watch your `AC_DEFINE`s).
|
||||
|
||||
### Debug-guards in code
|
||||
|
||||
Debugging statements are an important methodology to allow developers to fix
|
||||
issues found in the code after it has been released. The caveat here is that
|
||||
the developer must remember that people will be using the code at scale and in
|
||||
ways that can be unexpected for the original implementor. As such debugs
|
||||
**MUST** be guarded in such a way that they can be turned off. FRR has the
|
||||
ability to turn on/off debugs from the CLI and it is expected that the
|
||||
developer will use this convention to allow control of their debugs.
|
||||
|
||||
### CLI changes
|
||||
|
||||
CLI's are a complicated ugly beast. Additions or changes to the CLI should use
|
||||
a DEFUN to encapsulate one setting as much as is possible. Additionally as new
|
||||
DEFUN's are added to the system, documentation should be provided for the new
|
||||
commands.
|
||||
|
||||
### Backwards Compatibility
|
||||
|
||||
As a general principle, changes to CLI and code in the lib/ directory should be
|
||||
made in a backwards compatible fashion. This means that changes that are purely
|
||||
stylistic in nature should be avoided, e.g., renaming an existing macro or
|
||||
library function name without any functional change. When adding new parameters
|
||||
to common functions, it is also good to consider if this too should be done in
|
||||
a backward compatible fashion, e.g., by preserving the old form in addition to
|
||||
adding the new form.
|
||||
|
||||
This is not to say that minor or even major functional changes to CLI and
|
||||
common code should be avoided, but rather that the benefit gained from a change
|
||||
should be weighed against the added cost/complexity to existing code. Also,
|
||||
that when making such changes, it is good to preserve compatibility when
|
||||
possible to do so without introducing maintenance overhead/cost. It is also
|
||||
important to keep in mind, existing code includes code that may reside in
|
||||
private repositories (and is yet to be submitted) or code that has yet to be
|
||||
migrated from Quagga to FRR.
|
||||
|
||||
That said, compatibility measures can (and should) be removed when either:
|
||||
|
||||
* they become a significant burden, e.g. when data structures change and the
|
||||
compatibility measure would need a complex adaptation layer or becomes
|
||||
flat-out impossible
|
||||
* some measure of time (dependent on the specific case) has passed, so that the
|
||||
compatibility grace period is considered expired.
|
||||
|
||||
In all cases, compatibility pieces should be marked with compiler/preprocessor
|
||||
annotations to print warnings at compile time, pointing to the appropriate
|
||||
update path. A `-Werror` build should fail if compatibility bits are used.
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
|
||||
the development mailing list / public Slack instance.
|
||||
Moved to doc/developer/workflow.rst
|
||||
|
||||
@ -114,3 +114,6 @@ EXTRA_DIST += \
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
noinst_HEADERS += defaults.h
|
||||
|
||||
indent:
|
||||
tools/indent.py `find sharpd bgpd eigrpd include isisd lib nhrpd ospf6d ospfd pimd qpb ripd vtysh zebra -name '*.[ch]' | grep -v include/linux`
|
||||
|
||||
1
alpine/.gitignore
vendored
Normal file
1
alpine/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/APKBUILD
|
||||
37
alpine/APKBUILD.in
Normal file
37
alpine/APKBUILD.in
Normal file
@ -0,0 +1,37 @@
|
||||
# Maintainer: Arthur Jones <arthur.jones@riverbed.com>
|
||||
pkgname=frr
|
||||
pkgver=@VERSION@
|
||||
pkgrel=0
|
||||
pkgdesc="Free Range Routing is a fork of quagga"
|
||||
url="https://frrouting.org/"
|
||||
arch="all"
|
||||
license="GPL-2.0"
|
||||
depends="iproute2 json-c c-ares ipsec-tools iproute2"
|
||||
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
||||
acct autoconf automake bash
|
||||
binutils binutils-libs bison bsd-compat-headers build-base
|
||||
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
|
||||
device-mapper-libs expat fakeroot flex fortify-headers gdbm
|
||||
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
|
||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
|
||||
libgomp libisoburn libisofs libltdl libressl libssh2
|
||||
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
|
||||
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
|
||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline
|
||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
|
||||
py-sphinx"
|
||||
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
||||
source="$pkgname-$pkgver.tar.gz"
|
||||
|
||||
builddir="$srcdir"/$pkgname-$pkgver
|
||||
|
||||
build() {
|
||||
cd "$builddir"
|
||||
./configure --prefix=/usr || return 1
|
||||
make || return 1
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$builddir"
|
||||
make DESTDIR="$pkgdir" install || return 1
|
||||
}
|
||||
1
bgpd/.gitignore
vendored
1
bgpd/.gitignore
vendored
@ -16,4 +16,3 @@ TAGS
|
||||
.arch-ids
|
||||
*~
|
||||
*.loT
|
||||
*clippy.c
|
||||
|
||||
@ -498,7 +498,8 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
|
||||
if (!as->segments) {
|
||||
if (make_json) {
|
||||
json_object_string_add(as->json, "string", "Local");
|
||||
json_object_object_add(as->json, "segments", jaspath_segments);
|
||||
json_object_object_add(as->json, "segments",
|
||||
jaspath_segments);
|
||||
json_object_int_add(as->json, "length", 0);
|
||||
}
|
||||
as->str = XMALLOC(MTYPE_AS_STR, 1);
|
||||
@ -575,8 +576,9 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
|
||||
/* write out the ASNs, with their seperators, bar the last one*/
|
||||
for (i = 0; i < seg->length; i++) {
|
||||
if (make_json)
|
||||
json_object_array_add(jseg_list,
|
||||
json_object_new_int(seg->as[i]));
|
||||
json_object_array_add(
|
||||
jseg_list,
|
||||
json_object_new_int(seg->as[i]));
|
||||
|
||||
len += snprintf(str_buf + len, str_size - len, "%u",
|
||||
seg->as[i]);
|
||||
@ -588,8 +590,9 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
|
||||
|
||||
if (make_json) {
|
||||
jseg = json_object_new_object();
|
||||
json_object_string_add(jseg, "type",
|
||||
aspath_segment_type_str[seg->type]);
|
||||
json_object_string_add(
|
||||
jseg, "type",
|
||||
aspath_segment_type_str[seg->type]);
|
||||
json_object_object_add(jseg, "list", jseg_list);
|
||||
json_object_array_add(jaspath_segments, jseg);
|
||||
}
|
||||
@ -904,7 +907,8 @@ size_t aspath_put(struct stream *s, struct aspath *as, int use32bit)
|
||||
assegment_data_put(s, seg->as, AS_SEGMENT_MAX,
|
||||
use32bit);
|
||||
written += AS_SEGMENT_MAX;
|
||||
bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX, use32bit);
|
||||
bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX,
|
||||
use32bit);
|
||||
}
|
||||
|
||||
/* write the final segment, probably is also the first
|
||||
@ -2032,9 +2036,7 @@ int aspath_cmp(const void *arg1, const void *arg2)
|
||||
/* AS path hash initialize. */
|
||||
void aspath_init(void)
|
||||
{
|
||||
ashash = hash_create_size(32768,
|
||||
aspath_key_make,
|
||||
aspath_cmp,
|
||||
ashash = hash_create_size(32768, aspath_key_make, aspath_cmp,
|
||||
"BGP AS Path");
|
||||
}
|
||||
|
||||
|
||||
209
bgpd/bgp_attr.c
209
bgpd/bgp_attr.c
@ -83,15 +83,14 @@ static const struct message attr_str[] = {
|
||||
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
|
||||
{0}};
|
||||
|
||||
static const struct message attr_flag_str[] =
|
||||
{
|
||||
{BGP_ATTR_FLAG_OPTIONAL, "Optional"},
|
||||
{BGP_ATTR_FLAG_TRANS, "Transitive"},
|
||||
{BGP_ATTR_FLAG_PARTIAL, "Partial"},
|
||||
/* bgp_attr_flags_diagnose() relies on this bit being last in
|
||||
this list */
|
||||
{BGP_ATTR_FLAG_EXTLEN, "Extended Length"},
|
||||
{0}};
|
||||
static const struct message attr_flag_str[] = {
|
||||
{BGP_ATTR_FLAG_OPTIONAL, "Optional"},
|
||||
{BGP_ATTR_FLAG_TRANS, "Transitive"},
|
||||
{BGP_ATTR_FLAG_PARTIAL, "Partial"},
|
||||
/* bgp_attr_flags_diagnose() relies on this bit being last in
|
||||
this list */
|
||||
{BGP_ATTR_FLAG_EXTLEN, "Extended Length"},
|
||||
{0}};
|
||||
|
||||
static struct hash *cluster_hash;
|
||||
|
||||
@ -185,8 +184,7 @@ void cluster_unintern(struct cluster_list *cluster)
|
||||
|
||||
static void cluster_init(void)
|
||||
{
|
||||
cluster_hash = hash_create(cluster_hash_key_make,
|
||||
cluster_hash_cmp,
|
||||
cluster_hash = hash_create(cluster_hash_key_make, cluster_hash_cmp,
|
||||
"BGP Cluster");
|
||||
}
|
||||
|
||||
@ -363,12 +361,10 @@ static int encap_hash_cmp(const void *p1, const void *p2)
|
||||
|
||||
static void encap_init(void)
|
||||
{
|
||||
encap_hash = hash_create(encap_hash_key_make,
|
||||
encap_hash_cmp,
|
||||
encap_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
|
||||
"BGP Encap Hash");
|
||||
#if ENABLE_BGP_VNC
|
||||
vnc_hash = hash_create(encap_hash_key_make,
|
||||
encap_hash_cmp,
|
||||
vnc_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
|
||||
"BGP VNC Hash");
|
||||
#endif
|
||||
}
|
||||
@ -454,8 +450,7 @@ static int transit_hash_cmp(const void *p1, const void *p2)
|
||||
|
||||
static void transit_init(void)
|
||||
{
|
||||
transit_hash = hash_create(transit_hash_key_make,
|
||||
transit_hash_cmp,
|
||||
transit_hash = hash_create(transit_hash_key_make, transit_hash_cmp,
|
||||
"BGP Transit Hash");
|
||||
}
|
||||
|
||||
@ -496,7 +491,8 @@ unsigned int attrhash_key_make(void *p)
|
||||
#define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
|
||||
|
||||
MIX3(attr->origin, attr->nexthop.s_addr, attr->med);
|
||||
MIX3(attr->local_pref, attr->aggregator_as, attr->aggregator_addr.s_addr);
|
||||
MIX3(attr->local_pref, attr->aggregator_as,
|
||||
attr->aggregator_addr.s_addr);
|
||||
MIX3(attr->weight, attr->mp_nexthop_global_in.s_addr,
|
||||
attr->originator_id.s_addr);
|
||||
MIX3(attr->tag, attr->label, attr->label_index);
|
||||
@ -571,9 +567,8 @@ int attrhash_cmp(const void *p1, const void *p2)
|
||||
|
||||
static void attrhash_init(void)
|
||||
{
|
||||
attrhash = hash_create(attrhash_key_make,
|
||||
attrhash_cmp,
|
||||
"BGP Attributes");
|
||||
attrhash =
|
||||
hash_create(attrhash_key_make, attrhash_cmp, "BGP Attributes");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -747,8 +742,8 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, u_char origin,
|
||||
/* If we are not shutting down ourselves and we are
|
||||
* aggregating a route that contains the GSHUT community we
|
||||
* need to remove that community when creating the aggregate */
|
||||
if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN) &&
|
||||
community_include(community, gshut)) {
|
||||
if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)
|
||||
&& community_include(community, gshut)) {
|
||||
community_del_val(community, &gshut);
|
||||
}
|
||||
|
||||
@ -840,7 +835,6 @@ void bgp_attr_undup(struct attr *new, struct attr *old)
|
||||
|
||||
if (new->lcommunity != old->lcommunity)
|
||||
lcommunity_free(&new->lcommunity);
|
||||
|
||||
}
|
||||
|
||||
/* Free bgp attribute and aspath. */
|
||||
@ -1661,14 +1655,14 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
||||
case BGP_ATTR_NHLEN_VPNV4:
|
||||
stream_getl(s); /* RD high */
|
||||
stream_getl(s); /* RD low */
|
||||
/*
|
||||
* NOTE: intentional fall through
|
||||
* - for consistency in rx processing
|
||||
*
|
||||
* The following comment is to signal GCC this intention
|
||||
* and supress the warning
|
||||
*/
|
||||
/* FALLTHRU */
|
||||
/*
|
||||
* NOTE: intentional fall through
|
||||
* - for consistency in rx processing
|
||||
*
|
||||
* The following comment is to signal GCC this intention
|
||||
* and supress the warning
|
||||
*/
|
||||
/* FALLTHRU */
|
||||
case BGP_ATTR_NHLEN_IPV4:
|
||||
stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
|
||||
/* Probably needed for RFC 2283 */
|
||||
@ -1960,8 +1954,7 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
|
||||
/* alloc and copy sub-tlv */
|
||||
/* TBD make sure these are freed when attributes are released */
|
||||
tlv = XCALLOC(MTYPE_ENCAP_TLV,
|
||||
sizeof(struct bgp_attr_encap_subtlv)
|
||||
+ sublength);
|
||||
sizeof(struct bgp_attr_encap_subtlv) + sublength);
|
||||
tlv->type = subtype;
|
||||
tlv->length = sublength;
|
||||
stream_get(tlv->value, peer->curr, sublength);
|
||||
@ -2114,6 +2107,51 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
|
||||
return BGP_ATTR_PARSE_PROCEED;
|
||||
}
|
||||
|
||||
/* PMSI tunnel attribute (RFC 6514)
|
||||
* Basic validation checks done here.
|
||||
*/
|
||||
static bgp_attr_parse_ret_t
|
||||
bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
|
||||
{
|
||||
struct peer *const peer = args->peer;
|
||||
struct attr *const attr = args->attr;
|
||||
const bgp_size_t length = args->length;
|
||||
u_int8_t tnl_type;
|
||||
|
||||
/* Verify that the receiver is expecting "ingress replication" as we
|
||||
* can only support that.
|
||||
*/
|
||||
if (length < 2) {
|
||||
zlog_err("Bad PMSI tunnel attribute length %d", length);
|
||||
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
stream_getc(peer->curr); /* Flags */
|
||||
tnl_type = stream_getc(peer->curr);
|
||||
if (tnl_type > PMSI_TNLTYPE_MAX) {
|
||||
zlog_err("Invalid PMSI tunnel attribute type %d", tnl_type);
|
||||
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
||||
args->total);
|
||||
}
|
||||
if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
|
||||
if (length != 9) {
|
||||
zlog_err("Bad PMSI tunnel attribute length %d for IR",
|
||||
length);
|
||||
return bgp_attr_malformed(
|
||||
args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
}
|
||||
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
||||
attr->pmsi_tnl_type = tnl_type;
|
||||
|
||||
/* Forward read pointer of input stream. */
|
||||
stream_forward_getp(peer->curr, length - 2);
|
||||
|
||||
return BGP_ATTR_PARSE_PROCEED;
|
||||
}
|
||||
|
||||
/* BGP unknown attribute treatment. */
|
||||
static bgp_attr_parse_ret_t bgp_attr_unknown(struct bgp_attr_parser_args *args)
|
||||
{
|
||||
@ -2447,6 +2485,9 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
|
||||
case BGP_ATTR_PREFIX_SID:
|
||||
ret = bgp_attr_prefix_sid(&attr_args, mp_update);
|
||||
break;
|
||||
case BGP_ATTR_PMSI_TUNNEL:
|
||||
ret = bgp_attr_pmsi_tunnel(&attr_args);
|
||||
break;
|
||||
default:
|
||||
ret = bgp_attr_unknown(&attr_args);
|
||||
break;
|
||||
@ -2715,8 +2756,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
|
||||
stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
|
||||
} else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
|
||||
/* EVPN prefix - contents depend on type */
|
||||
bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
|
||||
attr, addpath_encode, addpath_tx_id);
|
||||
bgp_evpn_encode_prefix(s, p, prd, label, num_labels, attr,
|
||||
addpath_encode, addpath_tx_id);
|
||||
} else if (safi == SAFI_LABELED_UNICAST) {
|
||||
/* Prefix write with label. */
|
||||
stream_put_labeled_prefix(s, p, label);
|
||||
@ -2799,8 +2840,9 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
|
||||
|
||||
if (attrlenfield > 0xff) {
|
||||
/* 2-octet length field */
|
||||
stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, attrtype);
|
||||
stream_putw(s, attrlenfield & 0xffff);
|
||||
} else {
|
||||
@ -2867,9 +2909,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
|
||||
mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
|
||||
vecarr, attr);
|
||||
bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
|
||||
label, num_labels,
|
||||
addpath_encode, addpath_tx_id, attr);
|
||||
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
|
||||
num_labels, addpath_encode,
|
||||
addpath_tx_id, attr);
|
||||
bgp_packet_mpattr_end(s, mpattrlen_pos);
|
||||
}
|
||||
|
||||
@ -3039,14 +3081,15 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
||||
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
|
||||
if (attr->community->size * 4 > 255) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_COMMUNITIES);
|
||||
stream_putw(s, attr->community->size * 4);
|
||||
} else {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_COMMUNITIES);
|
||||
stream_putc(s, attr->community->size * 4);
|
||||
}
|
||||
@ -3060,14 +3103,15 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY)
|
||||
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
|
||||
if (lcom_length(attr->lcommunity) > 255) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
|
||||
stream_putw(s, lcom_length(attr->lcommunity));
|
||||
} else {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
|
||||
stream_putc(s, lcom_length(attr->lcommunity));
|
||||
}
|
||||
@ -3119,14 +3163,16 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
if (peer->sort == BGP_PEER_IBGP
|
||||
|| peer->sort == BGP_PEER_CONFED) {
|
||||
if (attr->ecommunity->size * 8 > 255) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
|
||||
stream_putw(s, attr->ecommunity->size * 8);
|
||||
} else {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
|
||||
stream_putc(s, attr->ecommunity->size * 8);
|
||||
}
|
||||
@ -3192,8 +3238,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
label_index = attr->label_index;
|
||||
|
||||
if (label_index != BGP_INVALID_LABEL_INDEX) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_PREFIX_SID);
|
||||
stream_putc(s, 10);
|
||||
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
|
||||
@ -3221,8 +3268,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
*/
|
||||
aspath = aspath_delete_confed_seq(aspath);
|
||||
|
||||
stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_AS4_PATH);
|
||||
aspath_sizep = stream_get_endp(s);
|
||||
stream_putw(s, 0);
|
||||
@ -3263,9 +3311,11 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
|
||||
stream_putc(s, 9); // Length
|
||||
stream_putc(s, 0); // Flags
|
||||
stream_putc(s, 6); // Tunnel type: Ingress Replication (6)
|
||||
stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
|
||||
stream_put_ipv4(s, attr->nexthop.s_addr); // Unicast tunnel endpoint IP address
|
||||
stream_putc(s, PMSI_TNLTYPE_INGR_REPL); // IR (6)
|
||||
stream_put(s, &(attr->label),
|
||||
BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
|
||||
stream_put_ipv4(s, attr->nexthop.s_addr);
|
||||
// Unicast tunnel endpoint IP address
|
||||
}
|
||||
|
||||
/* Unknown transit attribute. */
|
||||
@ -3311,8 +3361,7 @@ void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
|
||||
num_labels = 1;
|
||||
}
|
||||
|
||||
return bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
|
||||
label, num_labels,
|
||||
return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
|
||||
addpath_encode, addpath_tx_id, attr);
|
||||
}
|
||||
|
||||
@ -3422,14 +3471,15 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
||||
/* Community attribute. */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
|
||||
if (attr->community->size * 4 > 255) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_COMMUNITIES);
|
||||
stream_putw(s, attr->community->size * 4);
|
||||
} else {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_COMMUNITIES);
|
||||
stream_putc(s, attr->community->size * 4);
|
||||
}
|
||||
@ -3439,19 +3489,21 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
||||
/* Large Community attribute. */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
|
||||
if (lcom_length(attr->lcommunity) > 255) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
|
||||
| BGP_ATTR_FLAG_EXTLEN);
|
||||
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
|
||||
stream_putw(s, lcom_length(attr->lcommunity));
|
||||
} else {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
|
||||
stream_putc(s, lcom_length(attr->lcommunity));
|
||||
}
|
||||
|
||||
stream_put(s, attr->lcommunity->val, lcom_length(attr->lcommunity));
|
||||
stream_put(s, attr->lcommunity->val,
|
||||
lcom_length(attr->lcommunity));
|
||||
}
|
||||
|
||||
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
|
||||
@ -3490,8 +3542,9 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
|
||||
/* Prefix SID */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
|
||||
if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
|
||||
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s,
|
||||
BGP_ATTR_FLAG_OPTIONAL
|
||||
| BGP_ATTR_FLAG_TRANS);
|
||||
stream_putc(s, BGP_ATTR_PREFIX_SID);
|
||||
stream_putc(s, 10);
|
||||
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
|
||||
|
||||
@ -66,6 +66,8 @@
|
||||
#define BGP_PREFIX_SID_IPV6_LENGTH 19
|
||||
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
|
||||
|
||||
/* PMSI tunnel types (RFC 6514) */
|
||||
|
||||
struct bgp_attr_encap_subtlv {
|
||||
struct bgp_attr_encap_subtlv *next; /* for chaining */
|
||||
/* Reference count of this attribute. */
|
||||
@ -96,6 +98,18 @@ struct overlay_index {
|
||||
union gw_addr gw_ip;
|
||||
};
|
||||
|
||||
enum pta_type {
|
||||
PMSI_TNLTYPE_NO_INFO = 0,
|
||||
PMSI_TNLTYPE_RSVP_TE_P2MP,
|
||||
PMSI_TNLTYPE_MLDP_P2MP,
|
||||
PMSI_TNLTYPE_PIM_SSM,
|
||||
PMSI_TNLTYPE_PIM_SM,
|
||||
PMSI_TNLTYPE_PIM_BIDIR,
|
||||
PMSI_TNLTYPE_INGR_REPL,
|
||||
PMSI_TNLTYPE_MLDP_MP2MP,
|
||||
PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP
|
||||
};
|
||||
|
||||
/* BGP core attribute structure. */
|
||||
struct attr {
|
||||
/* AS Path structure */
|
||||
@ -119,6 +133,9 @@ struct attr {
|
||||
/* Path origin attribute */
|
||||
u_char origin;
|
||||
|
||||
/* PMSI tunnel type (RFC 6514). */
|
||||
enum pta_type pmsi_tnl_type;
|
||||
|
||||
/* has the route-map changed any attribute?
|
||||
Used on the peer outbound side. */
|
||||
u_int32_t rmap_change_flags;
|
||||
@ -215,10 +232,8 @@ struct transit {
|
||||
|
||||
/* "(void) 0" will generate a compiler error. this is a safety check to
|
||||
* ensure we're not using a value that exceeds the bit size of attr->flag. */
|
||||
#define ATTR_FLAG_BIT(X) \
|
||||
__builtin_choose_expr((X) >= 1 && (X) <= 64, \
|
||||
1ULL << ((X) - 1), \
|
||||
(void) 0)
|
||||
#define ATTR_FLAG_BIT(X) \
|
||||
__builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0)
|
||||
|
||||
#define BGP_CLUSTER_LIST_LENGTH(attr) \
|
||||
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
|
||||
@ -260,8 +275,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
|
||||
struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *, afi_t, safi_t,
|
||||
struct peer *, struct prefix_rd *,
|
||||
mpls_label_t *, u_int32_t,
|
||||
int, u_int32_t);
|
||||
mpls_label_t *, u_int32_t, int,
|
||||
u_int32_t);
|
||||
extern void bgp_dump_routes_attr(struct stream *, struct attr *,
|
||||
struct prefix *);
|
||||
extern int attrhash_cmp(const void *, const void *);
|
||||
@ -320,9 +335,9 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
|
||||
safi_t safi);
|
||||
extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
|
||||
afi_t afi, safi_t safi,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *, u_int32_t,
|
||||
int, u_int32_t, struct attr *);
|
||||
struct prefix_rd *prd, mpls_label_t *,
|
||||
u_int32_t, int, u_int32_t,
|
||||
struct attr *);
|
||||
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
|
||||
|
||||
static inline int bgp_rmap_nhop_changed(u_int32_t out_rmap_flags,
|
||||
|
||||
@ -106,8 +106,7 @@ char *ecom_mac2str(char *ecom_mac)
|
||||
}
|
||||
|
||||
/* Fetch router-mac from extended community */
|
||||
void bgp_attr_rmac(struct attr *attr,
|
||||
struct ethaddr *rmac)
|
||||
void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
|
||||
{
|
||||
int i = 0;
|
||||
struct ecommunity *ecom;
|
||||
@ -126,8 +125,8 @@ void bgp_attr_rmac(struct attr *attr,
|
||||
type = *pnt++;
|
||||
sub_type = *pnt++;
|
||||
|
||||
if (!(type == ECOMMUNITY_ENCODE_EVPN &&
|
||||
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
|
||||
if (!(type == ECOMMUNITY_ENCODE_EVPN
|
||||
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
|
||||
continue;
|
||||
|
||||
memcpy(rmac, pnt, ETH_ALEN);
|
||||
@ -139,8 +138,8 @@ void bgp_attr_rmac(struct attr *attr,
|
||||
*/
|
||||
uint8_t bgp_attr_default_gw(struct attr *attr)
|
||||
{
|
||||
struct ecommunity *ecom;
|
||||
int i;
|
||||
struct ecommunity *ecom;
|
||||
int i;
|
||||
|
||||
ecom = attr->ecommunity;
|
||||
if (!ecom || !ecom->size)
|
||||
@ -149,15 +148,15 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
|
||||
/* If there is a default gw extendd community return true otherwise
|
||||
* return 0 */
|
||||
for (i = 0; i < ecom->size; i++) {
|
||||
u_char *pnt;
|
||||
u_char type, sub_type;
|
||||
u_char *pnt;
|
||||
u_char type, sub_type;
|
||||
|
||||
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
|
||||
type = *pnt++;
|
||||
sub_type = *pnt++;
|
||||
|
||||
if ((type == ECOMMUNITY_ENCODE_OPAQUE
|
||||
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
|
||||
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -101,7 +101,7 @@ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
|
||||
|
||||
bfd_info = (struct bfd_info *)peer->bfd_info;
|
||||
|
||||
if (peer->bgp && (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF))
|
||||
if (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
vrf_id = peer->bgp->vrf_id;
|
||||
|
||||
if (command == ZEBRA_BFD_DEST_DEREGISTER) {
|
||||
|
||||
@ -222,7 +222,8 @@ static void set_community_string(struct community *com, bool make_json)
|
||||
|
||||
if (make_json) {
|
||||
json_object_string_add(com->json, "string", "");
|
||||
json_object_object_add(com->json, "list", json_community_list);
|
||||
json_object_object_add(com->json, "list",
|
||||
json_community_list);
|
||||
}
|
||||
com->str = str;
|
||||
return;
|
||||
@ -277,24 +278,30 @@ static void set_community_string(struct community *com, bool make_json)
|
||||
strcpy(pnt, "internet");
|
||||
pnt += strlen("internet");
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string("internet");
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_string =
|
||||
json_object_new_string("internet");
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
break;
|
||||
case COMMUNITY_NO_EXPORT:
|
||||
strcpy(pnt, "no-export");
|
||||
pnt += strlen("no-export");
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string("noExport");
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_string =
|
||||
json_object_new_string("noExport");
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
break;
|
||||
case COMMUNITY_NO_ADVERTISE:
|
||||
strcpy(pnt, "no-advertise");
|
||||
pnt += strlen("no-advertise");
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string("noAdvertise");
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_string =
|
||||
json_object_new_string("noAdvertise");
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
break;
|
||||
case COMMUNITY_LOCAL_AS:
|
||||
@ -302,15 +309,18 @@ static void set_community_string(struct community *com, bool make_json)
|
||||
pnt += strlen("local-AS");
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string("localAs");
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
break;
|
||||
case COMMUNITY_GSHUT:
|
||||
strcpy(pnt, "graceful-shutdown");
|
||||
pnt += strlen("graceful-shutdown");
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string("gracefulShutdown");
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_string = json_object_new_string(
|
||||
"gracefulShutdown");
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -319,7 +329,8 @@ static void set_community_string(struct community *com, bool make_json)
|
||||
sprintf(pnt, "%u:%d", as, val);
|
||||
if (make_json) {
|
||||
json_string = json_object_new_string(pnt);
|
||||
json_object_array_add(json_community_list, json_string);
|
||||
json_object_array_add(json_community_list,
|
||||
json_string);
|
||||
}
|
||||
pnt += strlen(pnt);
|
||||
break;
|
||||
@ -545,7 +556,8 @@ community_gettoken(const char *buf, enum community_token *token, u_int32_t *val)
|
||||
p += strlen("local-AS");
|
||||
return p;
|
||||
}
|
||||
if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown")) == 0) {
|
||||
if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown"))
|
||||
== 0) {
|
||||
*val = COMMUNITY_GSHUT;
|
||||
*token = community_token_gshut;
|
||||
p += strlen("graceful-shutdown");
|
||||
@ -662,10 +674,10 @@ struct hash *community_hash(void)
|
||||
/* Initialize comminity related hash. */
|
||||
void community_init(void)
|
||||
{
|
||||
comhash = hash_create(
|
||||
(unsigned int (*)(void *))community_hash_make,
|
||||
(int (*)(const void *, const void *))community_cmp,
|
||||
"BGP Community Hash");
|
||||
comhash =
|
||||
hash_create((unsigned int (*)(void *))community_hash_make,
|
||||
(int (*)(const void *, const void *))community_cmp,
|
||||
"BGP Community Hash");
|
||||
}
|
||||
|
||||
void community_finish(void)
|
||||
|
||||
@ -542,7 +542,7 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
|
||||
} else
|
||||
reuse_time = 0;
|
||||
|
||||
/* Making formatted timer strings. */
|
||||
/* Making formatted timer strings. */
|
||||
if (reuse_time == 0) {
|
||||
if (use_json)
|
||||
json_object_int_add(json, "reuseTimerMsecs", 0);
|
||||
|
||||
144
bgpd/bgp_debug.c
144
bgpd/bgp_debug.c
@ -55,6 +55,7 @@ unsigned long conf_bgp_debug_zebra;
|
||||
unsigned long conf_bgp_debug_allow_martians;
|
||||
unsigned long conf_bgp_debug_nht;
|
||||
unsigned long conf_bgp_debug_update_groups;
|
||||
unsigned long conf_bgp_debug_vpn;
|
||||
|
||||
unsigned long term_bgp_debug_as4;
|
||||
unsigned long term_bgp_debug_neighbor_events;
|
||||
@ -68,6 +69,7 @@ unsigned long term_bgp_debug_zebra;
|
||||
unsigned long term_bgp_debug_allow_martians;
|
||||
unsigned long term_bgp_debug_nht;
|
||||
unsigned long term_bgp_debug_update_groups;
|
||||
unsigned long term_bgp_debug_vpn;
|
||||
|
||||
struct list *bgp_debug_neighbor_events_peers = NULL;
|
||||
struct list *bgp_debug_keepalive_peers = NULL;
|
||||
@ -160,7 +162,6 @@ static const struct message bgp_notify_capability_msg[] = {
|
||||
const char *bgp_origin_str[] = {"i", "e", "?"};
|
||||
const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"};
|
||||
|
||||
|
||||
/* Given a string return a pointer the corresponding peer structure */
|
||||
static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str)
|
||||
{
|
||||
@ -415,6 +416,10 @@ int bgp_dump_attr(struct attr *attr, char *buf, size_t size)
|
||||
inet_ntoa(attr->cluster->list[i]));
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)))
|
||||
snprintf(buf + strlen(buf), size - strlen(buf),
|
||||
", pmsi tnltype %u", attr->pmsi_tnl_type);
|
||||
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
|
||||
snprintf(buf + strlen(buf), size - strlen(buf), ", path %s",
|
||||
aspath_print(attr->aspath));
|
||||
@ -1557,6 +1562,96 @@ DEFUN (no_debug_bgp_update_groups,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (debug_bgp_vpn,
|
||||
debug_bgp_vpn_cmd,
|
||||
"debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>",
|
||||
DEBUG_STR
|
||||
BGP_STR
|
||||
"VPN routes\n"
|
||||
"leaked from vrf to vpn\n"
|
||||
"leaked to vrf from vpn\n"
|
||||
"route-map updates\n"
|
||||
"labels\n")
|
||||
{
|
||||
int idx = 3;
|
||||
|
||||
if (argv_find(argv, argc, "leak-from-vrf", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_ON(vpn, VPN_LEAK_FROM_VRF);
|
||||
else
|
||||
TERM_DEBUG_ON(vpn, VPN_LEAK_FROM_VRF);
|
||||
} else if (argv_find(argv, argc, "leak-to-vrf", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_ON(vpn, VPN_LEAK_TO_VRF);
|
||||
else
|
||||
TERM_DEBUG_ON(vpn, VPN_LEAK_TO_VRF);
|
||||
} else if (argv_find(argv, argc, "rmap-event", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT);
|
||||
else
|
||||
TERM_DEBUG_ON(vpn, VPN_LEAK_RMAP_EVENT);
|
||||
} else if (argv_find(argv, argc, "label", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_ON(vpn, VPN_LEAK_LABEL);
|
||||
else
|
||||
TERM_DEBUG_ON(vpn, VPN_LEAK_LABEL);
|
||||
} else {
|
||||
vty_out(vty, "%% unknown debug bgp vpn keyword\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
if (vty->node != CONFIG_NODE)
|
||||
vty_out(vty, "enabled debug bgp vpn %s\n", argv[idx]->text);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_debug_bgp_vpn,
|
||||
no_debug_bgp_vpn_cmd,
|
||||
"no debug bgp vpn <leak-from-vrf|leak-to-vrf|rmap-event|label>",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
BGP_STR
|
||||
"VPN routes\n"
|
||||
"leaked from vrf to vpn\n"
|
||||
"leaked to vrf from vpn\n"
|
||||
"route-map updates\n"
|
||||
"labels\n")
|
||||
{
|
||||
int idx = 4;
|
||||
|
||||
if (argv_find(argv, argc, "leak-from-vrf", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
|
||||
else
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
|
||||
|
||||
} else if (argv_find(argv, argc, "leak-to-vrf", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
|
||||
else
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
|
||||
} else if (argv_find(argv, argc, "rmap-event", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
|
||||
else
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
|
||||
} else if (argv_find(argv, argc, "label", &idx)) {
|
||||
if (vty->node == CONFIG_NODE)
|
||||
DEBUG_OFF(vpn, VPN_LEAK_LABEL);
|
||||
else
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL);
|
||||
} else {
|
||||
vty_out(vty, "%% unknown debug bgp vpn keyword\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
if (vty->node != CONFIG_NODE)
|
||||
vty_out(vty, "disabled debug bgp vpn %s\n", argv[idx]->text);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_debug_bgp,
|
||||
no_debug_bgp_cmd,
|
||||
"no debug bgp",
|
||||
@ -1589,6 +1684,10 @@ DEFUN (no_debug_bgp,
|
||||
TERM_DEBUG_OFF(zebra, ZEBRA);
|
||||
TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
|
||||
TERM_DEBUG_OFF(nht, NHT);
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT);
|
||||
TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL);
|
||||
vty_out(vty, "All possible debugging has been turned off\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@ -1648,6 +1747,18 @@ DEFUN_NOSH (show_debugging_bgp,
|
||||
|
||||
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
|
||||
vty_out(vty, " BGP allow martian next hop debugging is on\n");
|
||||
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
|
||||
vty_out(vty,
|
||||
" BGP route leak from vrf to vpn debugging is on\n");
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
|
||||
vty_out(vty,
|
||||
" BGP route leak to vrf from vpn debugging is on\n");
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT))
|
||||
vty_out(vty, " BGP vpn route-map event debugging is on\n");
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
|
||||
vty_out(vty, " BGP vpn label event debugging is on\n");
|
||||
|
||||
vty_out(vty, "\n");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -1692,6 +1803,15 @@ int bgp_debug_count(void)
|
||||
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
|
||||
ret++;
|
||||
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
|
||||
ret++;
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
|
||||
ret++;
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT))
|
||||
ret++;
|
||||
if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1768,6 +1888,23 @@ static int bgp_config_write_debug(struct vty *vty)
|
||||
write++;
|
||||
}
|
||||
|
||||
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) {
|
||||
vty_out(vty, "debug bgp vpn leak-from-vrf\n");
|
||||
write++;
|
||||
}
|
||||
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) {
|
||||
vty_out(vty, "debug bgp vpn leak-to-vrf\n");
|
||||
write++;
|
||||
}
|
||||
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) {
|
||||
vty_out(vty, "debug bgp vpn rmap-event\n");
|
||||
write++;
|
||||
}
|
||||
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
|
||||
vty_out(vty, "debug bgp vpn label\n");
|
||||
write++;
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
||||
@ -1861,6 +1998,11 @@ void bgp_debug_init(void)
|
||||
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
|
||||
|
||||
install_element(ENABLE_NODE, &debug_bgp_vpn_cmd);
|
||||
install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_bgp_vpn_cmd);
|
||||
}
|
||||
|
||||
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
|
||||
|
||||
@ -72,6 +72,7 @@ extern unsigned long conf_bgp_debug_zebra;
|
||||
extern unsigned long conf_bgp_debug_allow_martians;
|
||||
extern unsigned long conf_bgp_debug_nht;
|
||||
extern unsigned long conf_bgp_debug_update_groups;
|
||||
extern unsigned long conf_bgp_debug_vpn;
|
||||
|
||||
extern unsigned long term_bgp_debug_as4;
|
||||
extern unsigned long term_bgp_debug_neighbor_events;
|
||||
@ -83,6 +84,7 @@ extern unsigned long term_bgp_debug_zebra;
|
||||
extern unsigned long term_bgp_debug_allow_martians;
|
||||
extern unsigned long term_bgp_debug_nht;
|
||||
extern unsigned long term_bgp_debug_update_groups;
|
||||
extern unsigned long term_bgp_debug_vpn;
|
||||
|
||||
extern struct list *bgp_debug_neighbor_events_peers;
|
||||
extern struct list *bgp_debug_keepalive_peers;
|
||||
@ -111,6 +113,10 @@ struct bgp_debug_filter {
|
||||
#define BGP_DEBUG_ALLOW_MARTIANS 0x01
|
||||
#define BGP_DEBUG_NHT 0x01
|
||||
#define BGP_DEBUG_UPDATE_GROUPS 0x01
|
||||
#define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01
|
||||
#define BGP_DEBUG_VPN_LEAK_TO_VRF 0x02
|
||||
#define BGP_DEBUG_VPN_LEAK_RMAP_EVENT 0x04
|
||||
#define BGP_DEBUG_VPN_LEAK_LABEL 0x08
|
||||
|
||||
#define BGP_DEBUG_PACKET_SEND 0x01
|
||||
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
|
||||
@ -136,6 +142,7 @@ struct bgp_debug_filter {
|
||||
#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
|
||||
|
||||
extern const char *bgp_type_str[];
|
||||
extern const char *pmsi_tnltype_str[];
|
||||
|
||||
extern int bgp_dump_attr(struct attr *, char *, size_t);
|
||||
extern int bgp_debug_peer_updout_enabled(char *host);
|
||||
|
||||
@ -465,7 +465,7 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer,
|
||||
}
|
||||
|
||||
if (peer->su.sa.sa_family == AF_INET) {
|
||||
stream_putw(obuf, peer->ifindex);
|
||||
stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
|
||||
stream_putw(obuf, AFI_IP);
|
||||
|
||||
stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
|
||||
@ -477,7 +477,7 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer,
|
||||
stream_put(obuf, empty, IPV4_MAX_BYTELEN);
|
||||
} else if (peer->su.sa.sa_family == AF_INET6) {
|
||||
/* Interface Index and Address family. */
|
||||
stream_putw(obuf, peer->ifindex);
|
||||
stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
|
||||
stream_putw(obuf, AFI_IP6);
|
||||
|
||||
/* Source IP Address and Destination IP Address. */
|
||||
|
||||
@ -260,8 +260,7 @@ int ecommunity_cmp(const void *arg1, const void *arg2)
|
||||
/* Initialize Extended Comminities related hash. */
|
||||
void ecommunity_init(void)
|
||||
{
|
||||
ecomhash = hash_create(ecommunity_hash_make,
|
||||
ecommunity_cmp,
|
||||
ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp,
|
||||
"BGP ecommunity hash");
|
||||
}
|
||||
|
||||
@ -690,7 +689,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
||||
tunneltype = ntohs(tunneltype);
|
||||
len = sprintf(str_buf + str_pnt, "ET:%d",
|
||||
tunneltype);
|
||||
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
|
||||
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
|
||||
len = sprintf(str_buf + str_pnt,
|
||||
"Default Gateway");
|
||||
} else
|
||||
|
||||
660
bgpd/bgp_evpn.c
660
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load Diff
@ -55,12 +55,30 @@ static inline vni_t label2vni(mpls_label_t *label)
|
||||
return vni;
|
||||
}
|
||||
|
||||
static inline int advertise_type5_routes(struct bgp *bgp_vrf,
|
||||
afi_t afi)
|
||||
{
|
||||
if (!bgp_vrf->l3vni)
|
||||
return 0;
|
||||
|
||||
if (afi == AFI_IP &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
return 1;
|
||||
|
||||
if (afi == AFI_IP6 &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr,
|
||||
afi_t afi, safi_t safi);
|
||||
extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr, afi_t afi,
|
||||
safi_t safi);
|
||||
extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
||||
afi_t afi, safi_t safi);
|
||||
extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
||||
safi_t safi);
|
||||
@ -73,10 +91,9 @@ extern char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
|
||||
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
|
||||
extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
|
||||
extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
struct attr *attr, int addpath_encode,
|
||||
u_int32_t addpath_tx_id);
|
||||
struct prefix_rd *prd, mpls_label_t *label,
|
||||
u_int32_t num_labels, struct attr *attr,
|
||||
int addpath_encode, u_int32_t addpath_tx_id);
|
||||
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
|
||||
struct bgp_nlri *packet, int withdraw);
|
||||
extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
@ -91,7 +108,7 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
|
||||
u_char flags);
|
||||
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
|
||||
struct ethaddr *rmac,
|
||||
struct in_addr originator_ip);
|
||||
struct in_addr originator_ip, int filter);
|
||||
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
|
||||
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
|
||||
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
|
||||
|
||||
@ -61,30 +61,39 @@ struct bgpevpn {
|
||||
#define VNI_FLAG_RD_CFGD 0x4 /* RD is user configured. */
|
||||
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
|
||||
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
|
||||
#define VNI_FLAG_USE_TWO_LABELS 0x20 /* Attach both L2-VNI and L3-VNI if
|
||||
needed for this VPN */
|
||||
|
||||
/* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
|
||||
u_int8_t advertise_gw_macip;
|
||||
struct bgp *bgp_vrf; /* back pointer to the vrf instance */
|
||||
|
||||
/* Flag to indicate if we are advertising subnet for this VNI */
|
||||
u_int8_t advertise_subnet;
|
||||
/* Flag to indicate if we are
|
||||
* advertising the g/w mac ip for
|
||||
* this VNI*/
|
||||
u_int8_t advertise_gw_macip;
|
||||
|
||||
/* Id for deriving the RD automatically for this VNI */
|
||||
u_int16_t rd_id;
|
||||
/* Flag to indicate if we are
|
||||
* advertising subnet for this VNI */
|
||||
u_int8_t advertise_subnet;
|
||||
|
||||
/* RD for this VNI. */
|
||||
struct prefix_rd prd;
|
||||
/* Id for deriving the RD
|
||||
* automatically for this VNI */
|
||||
u_int16_t rd_id;
|
||||
|
||||
/* Route type 3 field */
|
||||
struct in_addr originator_ip;
|
||||
/* RD for this VNI. */
|
||||
struct prefix_rd prd;
|
||||
|
||||
/* Import and Export RTs. */
|
||||
struct list *import_rtl;
|
||||
struct list *export_rtl;
|
||||
/* Route type 3 field */
|
||||
struct in_addr originator_ip;
|
||||
|
||||
/* Route table for EVPN routes for this VNI. */
|
||||
struct bgp_table *route_table;
|
||||
/* Import and Export RTs. */
|
||||
struct list *import_rtl;
|
||||
struct list *export_rtl;
|
||||
|
||||
QOBJ_FIELDS
|
||||
/* Route table for EVPN routes for
|
||||
* this VNI. */
|
||||
struct bgp_table *route_table;
|
||||
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
|
||||
DECLARE_QOBJ_TYPE(bgpevpn)
|
||||
@ -120,8 +129,7 @@ struct vrf_irt_node {
|
||||
|
||||
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
|
||||
{
|
||||
return (CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_RD_CFGD));
|
||||
return (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD));
|
||||
}
|
||||
|
||||
static inline int bgp_evpn_vrf_rd_matches_existing(struct bgp *bgp_vrf,
|
||||
@ -132,66 +140,65 @@ static inline int bgp_evpn_vrf_rd_matches_existing(struct bgp *bgp_vrf,
|
||||
|
||||
static inline vni_t bgpevpn_get_l3vni(struct bgpevpn *vpn)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
return 0;
|
||||
|
||||
return bgp_vrf->l3vni;
|
||||
return vpn->bgp_vrf ? vpn->bgp_vrf->l3vni : 0;
|
||||
}
|
||||
|
||||
static inline void bgpevpn_get_rmac(struct bgpevpn *vpn, struct ethaddr *rmac)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
memset(rmac, 0, sizeof(struct ethaddr));
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
if (!vpn->bgp_vrf)
|
||||
return;
|
||||
memcpy(rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
|
||||
memcpy(rmac, &vpn->bgp_vrf->rmac, sizeof(struct ethaddr));
|
||||
}
|
||||
|
||||
static inline struct list *bgpevpn_get_vrf_export_rtl(struct bgpevpn *vpn)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
if (!vpn->bgp_vrf)
|
||||
return NULL;
|
||||
|
||||
return bgp_vrf->vrf_export_rtl;
|
||||
return vpn->bgp_vrf->vrf_export_rtl;
|
||||
}
|
||||
|
||||
static inline struct list *bgpevpn_get_vrf_import_rtl(struct bgpevpn *vpn)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
if (!vpn->bgp_vrf)
|
||||
return NULL;
|
||||
|
||||
return bgp_vrf->vrf_import_rtl;
|
||||
return vpn->bgp_vrf->vrf_import_rtl;
|
||||
}
|
||||
|
||||
static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf || !bgp_vrf->l2vnis)
|
||||
/* bail if vpn is not associated to bgp_vrf */
|
||||
if (!vpn->bgp_vrf)
|
||||
return;
|
||||
listnode_delete(bgp_vrf->l2vnis, vpn);
|
||||
|
||||
UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
|
||||
listnode_delete(vpn->bgp_vrf->l2vnis, vpn);
|
||||
|
||||
/* remove the backpointer to the vrf instance */
|
||||
vpn->bgp_vrf = NULL;
|
||||
}
|
||||
|
||||
static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf || !bgp_vrf->l2vnis)
|
||||
/* bail if vpn is already associated to vrf */
|
||||
if (vpn->bgp_vrf)
|
||||
return;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
return;
|
||||
|
||||
/* associate the vpn to the bgp_vrf instance */
|
||||
vpn->bgp_vrf = bgp_vrf;
|
||||
listnode_add_sort(bgp_vrf->l2vnis, vpn);
|
||||
|
||||
/* check if we are advertising two labels for this vpn */
|
||||
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY))
|
||||
SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
|
||||
}
|
||||
|
||||
static inline int is_vni_configured(struct bgpevpn *vpn)
|
||||
@ -268,18 +275,24 @@ static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp,
|
||||
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
|
||||
ip->family = AF_INET;
|
||||
ip->prefixlen = evp->prefix.ip_prefix_length;
|
||||
memcpy(&(ip->u.prefix4),
|
||||
&(evp->prefix.ip.ip),
|
||||
memcpy(&(ip->u.prefix4), &(evp->prefix.ip.ip),
|
||||
IPV4_MAX_BYTELEN);
|
||||
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
|
||||
ip->family = AF_INET6;
|
||||
ip->prefixlen = evp->prefix.ip_prefix_length;
|
||||
memcpy(&(ip->u.prefix6),
|
||||
&(evp->prefix.ip.ip),
|
||||
memcpy(&(ip->u.prefix6), &(evp->prefix.ip.ip),
|
||||
IPV6_MAX_BYTELEN);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int is_evpn_prefix_default(struct prefix *evp)
|
||||
{
|
||||
if (evp->family != AF_EVPN)
|
||||
return 0;
|
||||
|
||||
return ((evp->u.prefix_evpn.ip_prefix_length == 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
|
||||
struct prefix *ip)
|
||||
{
|
||||
@ -287,14 +300,12 @@ static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
|
||||
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
|
||||
ip->family = AF_INET;
|
||||
ip->prefixlen = IPV4_MAX_BITLEN;
|
||||
memcpy(&(ip->u.prefix4),
|
||||
&(evp->prefix.ip.ip),
|
||||
memcpy(&(ip->u.prefix4), &(evp->prefix.ip.ip),
|
||||
IPV4_MAX_BYTELEN);
|
||||
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
|
||||
ip->family = AF_INET6;
|
||||
ip->prefixlen = IPV6_MAX_BITLEN;
|
||||
memcpy(&(ip->u.prefix6),
|
||||
&(evp->prefix.ip.ip),
|
||||
memcpy(&(ip->u.prefix6), &(evp->prefix.ip.ip),
|
||||
IPV6_MAX_BYTELEN);
|
||||
}
|
||||
}
|
||||
@ -349,24 +360,21 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
|
||||
p->prefix.ip.ipaddr_v4 = originator_ip;
|
||||
}
|
||||
|
||||
static inline int advertise_type5_routes(struct bgp *bgp_vrf,
|
||||
afi_t afi)
|
||||
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
|
||||
safi_t safi)
|
||||
{
|
||||
if (!bgp_vrf->l3vni)
|
||||
return 0;
|
||||
|
||||
if (afi == AFI_IP &&
|
||||
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
|
||||
return 1;
|
||||
|
||||
if (afi == AFI_IP6 &&
|
||||
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
else if (afi == AFI_IP6 &&
|
||||
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void evpn_rt_delete_auto(struct bgp*, vni_t, struct list*);
|
||||
extern void evpn_rt_delete_auto(struct bgp *, vni_t, struct list *);
|
||||
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
struct ecommunity *ecomadd);
|
||||
extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
|
||||
|
||||
@ -53,8 +53,7 @@ struct vni_walk_ctx {
|
||||
};
|
||||
|
||||
#if defined(HAVE_CUMULUS)
|
||||
static void display_vrf_import_rt(struct vty *vty,
|
||||
struct vrf_irt_node *irt,
|
||||
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
|
||||
json_object *json)
|
||||
{
|
||||
u_char *pnt;
|
||||
@ -138,8 +137,7 @@ static void display_vrf_import_rt(struct vty *vty,
|
||||
json_object_array_add(
|
||||
json_vrfs,
|
||||
json_object_new_string(
|
||||
vrf_id_to_name(
|
||||
tmp_bgp_vrf->vrf_id)));
|
||||
vrf_id_to_name(tmp_bgp_vrf->vrf_id)));
|
||||
else
|
||||
vty_out(vty, " %s\n",
|
||||
vrf_id_to_name(tmp_bgp_vrf->vrf_id));
|
||||
@ -151,8 +149,7 @@ static void display_vrf_import_rt(struct vty *vty,
|
||||
}
|
||||
}
|
||||
|
||||
static void show_vrf_import_rt_entry(struct hash_backet *backet,
|
||||
void *args[])
|
||||
static void show_vrf_import_rt_entry(struct hash_backet *backet, void *args[])
|
||||
{
|
||||
json_object *json = NULL;
|
||||
struct vty *vty = NULL;
|
||||
@ -491,53 +488,6 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||
json_object_object_add(json, "exportRts", json_export_rtl);
|
||||
}
|
||||
|
||||
static void evpn_show_vrf_routes(struct vty *vty,
|
||||
struct bgp *bgp_vrf)
|
||||
{
|
||||
struct bgp *bgp_def = NULL;
|
||||
struct bgp_node *rn;
|
||||
struct bgp_info *ri;
|
||||
int header = 1;
|
||||
u_int32_t prefix_cnt, path_cnt;
|
||||
struct bgp_table *table;
|
||||
|
||||
prefix_cnt = path_cnt = 0;
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return;
|
||||
|
||||
table = (struct bgp_table *)bgp_vrf->rib[AFI_L2VPN][SAFI_EVPN];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
char prefix_str[BUFSIZ];
|
||||
|
||||
bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
|
||||
sizeof(prefix_str));
|
||||
|
||||
if (rn->info) {
|
||||
/* Overall header/legend displayed once. */
|
||||
if (header) {
|
||||
bgp_evpn_show_route_header(vty, bgp_def, NULL);
|
||||
header = 0;
|
||||
}
|
||||
prefix_cnt++;
|
||||
}
|
||||
|
||||
/* For EVPN, the prefix is displayed for each path (to fit in
|
||||
* with code that already exists).
|
||||
*/
|
||||
for (ri = rn->info; ri; ri = ri->next) {
|
||||
route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, NULL);
|
||||
path_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix_cnt == 0)
|
||||
vty_out(vty, "No EVPN prefixes exist for this VRF");
|
||||
else
|
||||
vty_out(vty, "\nDisplayed %u prefixes (%u paths)",
|
||||
prefix_cnt, path_cnt);
|
||||
}
|
||||
|
||||
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
|
||||
struct vty *vty, struct in_addr vtep_ip,
|
||||
json_object *json)
|
||||
@ -651,7 +601,7 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
|
||||
}
|
||||
|
||||
static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
|
||||
json_object *json)
|
||||
json_object *json)
|
||||
{
|
||||
json_object *json_vni;
|
||||
json_object *json_import_rtl;
|
||||
@ -686,8 +636,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
|
||||
json_vni, "rd",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
|
||||
} else {
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s",
|
||||
buf1, bgp->l3vni, "L3",
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, bgp->l3vni, "L3",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
|
||||
}
|
||||
|
||||
@ -795,8 +744,7 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
|
||||
json_vni, "rd",
|
||||
prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
|
||||
} else {
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s",
|
||||
buf1, vpn->vni, "L2",
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, vpn->vni, "L2",
|
||||
prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
|
||||
}
|
||||
|
||||
@ -1477,8 +1425,7 @@ DEFUN(evpnrt5_network,
|
||||
|
||||
return bgp_static_set_safi(
|
||||
AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
|
||||
argv[idx_route_distinguisher]->arg, argv[idx_label]->arg,
|
||||
NULL,
|
||||
argv[idx_route_distinguisher]->arg, argv[idx_label]->arg, NULL,
|
||||
BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
|
||||
argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
|
||||
argv[idx_routermac]->arg);
|
||||
@ -1679,8 +1626,7 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
/*
|
||||
* Configure RD for VRF
|
||||
*/
|
||||
static void evpn_configure_vrf_rd(struct bgp *bgp_vrf,
|
||||
struct prefix_rd *rd)
|
||||
static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
|
||||
{
|
||||
/* If we have already advertise type-5 routes with a diffrent RD, we
|
||||
* have to delete and withdraw them firs
|
||||
@ -1824,8 +1770,7 @@ static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
* Display import RT mapping to VRFs (vty handler)
|
||||
* bgp_def: default bgp instance
|
||||
*/
|
||||
static void evpn_show_vrf_import_rts(struct vty *vty,
|
||||
struct bgp *bgp_def,
|
||||
static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_def,
|
||||
json_object *json)
|
||||
{
|
||||
void *args[2];
|
||||
@ -1834,8 +1779,8 @@ static void evpn_show_vrf_import_rts(struct vty *vty,
|
||||
args[1] = json;
|
||||
|
||||
hash_iterate(bgp_def->vrf_import_rt_hash,
|
||||
(void (*)(struct hash_backet *, void *))
|
||||
show_vrf_import_rt_entry,
|
||||
(void (*)(struct hash_backet *,
|
||||
void *))show_vrf_import_rt_entry,
|
||||
args);
|
||||
}
|
||||
|
||||
@ -2411,8 +2356,7 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
|
||||
if (!json) {
|
||||
vty_out(vty, "Flags: * - Kernel\n");
|
||||
vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
|
||||
"Type", "RD", "Import RT",
|
||||
"Export RT", "Tenant VRF");
|
||||
"Type", "RD", "Import RT", "Export RT", "Tenant VRF");
|
||||
}
|
||||
|
||||
/* print all L2 VNIS */
|
||||
@ -2425,7 +2369,6 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
|
||||
/* print all L3 VNIs */
|
||||
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp))
|
||||
show_l3vni_entry(vty, bgp_temp, json);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2473,6 +2416,48 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* evpn - enable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf,
|
||||
afi_t afi, int add)
|
||||
{
|
||||
struct prefix ip_prefix;
|
||||
safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */
|
||||
|
||||
/* form the default prefix 0.0.0.0/0 */
|
||||
memset(&ip_prefix, 0, sizeof(struct prefix));
|
||||
ip_prefix.family = afi2family(afi);
|
||||
ip_prefix.prefixlen = 0;
|
||||
|
||||
if (add) {
|
||||
/* bail if we are already advertising default route */
|
||||
if (evpn_default_originate_set(bgp_vrf, afi, safi))
|
||||
return;
|
||||
|
||||
if (afi == AFI_IP)
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
|
||||
else if (afi == AFI_IP6)
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
|
||||
bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
|
||||
NULL, afi, safi);
|
||||
} else {
|
||||
/* bail out if we havent advertised the default route */
|
||||
if (!evpn_default_originate_set(bgp_vrf, afi, safi))
|
||||
return;
|
||||
if (afi == AFI_IP)
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
|
||||
else if (afi == AFI_IP6)
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
|
||||
afi, safi);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* evpn - enable advertisement of default g/w
|
||||
*/
|
||||
@ -2489,8 +2474,7 @@ static void evpn_set_advertise_subnet(struct bgp *bgp,
|
||||
/*
|
||||
* evpn - disable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_unset_advertise_subnet(struct bgp *bgp,
|
||||
struct bgpevpn *vpn)
|
||||
static void evpn_unset_advertise_subnet(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
{
|
||||
if (!vpn->advertise_subnet)
|
||||
return;
|
||||
@ -2671,6 +2655,43 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_default_originate,
|
||||
bgp_evpn_default_originate_cmd,
|
||||
"default-originate <ipv4 | ipv6>",
|
||||
"originate a default route\n"
|
||||
"ipv4 address family\n"
|
||||
"ipv6 address family\n")
|
||||
{
|
||||
afi_t afi = 0;
|
||||
int idx_afi = 0;
|
||||
struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
|
||||
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
evpn_process_default_originate_cmd(bgp_vrf, afi, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_bgp_evpn_default_originate,
|
||||
no_bgp_evpn_default_originate_cmd,
|
||||
"no default-originate <ipv4 | ipv6>",
|
||||
NO_STR
|
||||
"withdraw a default route\n"
|
||||
"ipv4 address family\n"
|
||||
"ipv6 address family\n")
|
||||
{
|
||||
afi_t afi = 0;
|
||||
int idx_afi = 0;
|
||||
struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
|
||||
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
evpn_process_default_originate_cmd(bgp_vrf, afi, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||
bgp_evpn_advertise_vni_subnet_cmd,
|
||||
"advertise-subnet",
|
||||
@ -2690,14 +2711,6 @@ DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!(advertise_type5_routes(bgp_vrf, AFI_IP) ||
|
||||
advertise_type5_routes(bgp_vrf, AFI_IP6))) {
|
||||
vty_out(vty,
|
||||
"%%Please enable ip prefix advertisement under l2vpn evpn in %s",
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
evpn_set_advertise_subnet(bgp, vpn);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -2746,13 +2759,14 @@ DEFUN (bgp_evpn_advertise_type5,
|
||||
if (!bgp_vrf->adv_cmd_rmap[afi][safi].name)
|
||||
rmap_changed = 1;
|
||||
else if (strcmp(argv[idx_rmap + 1]->arg,
|
||||
bgp_vrf->adv_cmd_rmap[afi][safi].name) != 0)
|
||||
bgp_vrf->adv_cmd_rmap[afi][safi].name)
|
||||
!= 0)
|
||||
rmap_changed = 1;
|
||||
} else if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
|
||||
rmap_changed = 1;
|
||||
}
|
||||
|
||||
if (!(afi == AFI_IP) || (afi == AFI_IP6)) {
|
||||
if (!(afi == AFI_IP || afi == AFI_IP6)) {
|
||||
vty_out(vty,
|
||||
"%%only ipv4 or ipv6 address families are supported");
|
||||
return CMD_WARNING;
|
||||
@ -2769,21 +2783,23 @@ DEFUN (bgp_evpn_advertise_type5,
|
||||
/* if we are already advertising ipv4 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
if (!rmap_changed &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
return CMD_WARNING;
|
||||
SET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
|
||||
} else {
|
||||
|
||||
/* if we are already advertising ipv6 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
if (!rmap_changed &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
return CMD_WARNING;
|
||||
SET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
|
||||
}
|
||||
|
||||
if (rmap_changed) {
|
||||
@ -2799,8 +2815,7 @@ DEFUN (bgp_evpn_advertise_type5,
|
||||
/* set the route-map for advertise command */
|
||||
if (ret && argv[idx_rmap + 1]->arg) {
|
||||
bgp_vrf->adv_cmd_rmap[afi][safi].name =
|
||||
XSTRDUP(MTYPE_ROUTE_MAP_NAME,
|
||||
argv[idx_rmap + 1]->arg);
|
||||
XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[idx_rmap + 1]->arg);
|
||||
bgp_vrf->adv_cmd_rmap[afi][safi].map =
|
||||
route_map_lookup_by_name(argv[idx_rmap + 1]->arg);
|
||||
}
|
||||
@ -2827,7 +2842,7 @@ DEFUN (no_bgp_evpn_advertise_type5,
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
|
||||
|
||||
if (!(afi == AFI_IP) || (afi == AFI_IP6)) {
|
||||
if (!(afi == AFI_IP || afi == AFI_IP6)) {
|
||||
vty_out(vty,
|
||||
"%%only ipv4 or ipv6 address families are supported");
|
||||
return CMD_WARNING;
|
||||
@ -2841,25 +2856,25 @@ DEFUN (no_bgp_evpn_advertise_type5,
|
||||
|
||||
if (afi == AFI_IP) {
|
||||
|
||||
/* if we are already advertising ipv4 prefix as type-5
|
||||
/* if we are not advertising ipv4 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) {
|
||||
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* if we are already advertising ipv6 prefix as type-5
|
||||
/* if we are not advertising ipv6 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) {
|
||||
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2926,16 +2941,15 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
||||
? "Enabled"
|
||||
: "Disabled");
|
||||
json_object_string_add(json, "advertiseAllVnis",
|
||||
is_evpn_enabled()
|
||||
? "Enabled"
|
||||
: "Disabled");
|
||||
is_evpn_enabled() ? "Enabled"
|
||||
: "Disabled");
|
||||
json_object_int_add(json, "numVnis", num_vnis);
|
||||
json_object_int_add(json, "numL2Vnis", num_l2vnis);
|
||||
json_object_int_add(json, "numL3Vnis", num_l3vnis);
|
||||
} else {
|
||||
vty_out(vty, "Advertise Gateway Macip: %s\n",
|
||||
bgp_def->advertise_gw_macip ? "Enabled"
|
||||
: "Disabled");
|
||||
: "Disabled");
|
||||
vty_out(vty, "Advertise All VNI flag: %s\n",
|
||||
is_evpn_enabled() ? "Enabled" : "Disabled");
|
||||
vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
|
||||
@ -2967,16 +2981,23 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
||||
*/
|
||||
DEFUN(show_bgp_l2vpn_evpn_summary,
|
||||
show_bgp_l2vpn_evpn_summary_cmd,
|
||||
"show bgp l2vpn evpn summary [json]",
|
||||
"show bgp [vrf VRFNAME] l2vpn evpn summary [json]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
"bgp vrf\n"
|
||||
"vrf name\n"
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Summary of BGP neighbor status\n"
|
||||
JSON_STR)
|
||||
{
|
||||
int idx_vrf = 0;
|
||||
u_char uj = use_json(argc, argv);
|
||||
return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj);
|
||||
char *vrf = NULL;
|
||||
|
||||
if (argv_find(argv, argc, "vrf", &idx_vrf))
|
||||
vrf = argv[++idx_vrf]->arg;
|
||||
return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, uj);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3183,33 +3204,6 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VRF EVPN routing table.
|
||||
*/
|
||||
DEFUN(show_bgp_l2vpn_evpn_route_vrf, show_bgp_l2vpn_evpn_route_vrf_cmd,
|
||||
"show bgp l2vpn evpn route vrf VRFNAME",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"EVPN route information\n"
|
||||
"VRF\n"
|
||||
"VRF Name\n")
|
||||
{
|
||||
int vrf_idx = 6;
|
||||
char *vrf_name = NULL;
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
|
||||
vrf_name = argv[vrf_idx]->arg;
|
||||
bgp_vrf = bgp_lookup_by_name(vrf_name);
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
evpn_show_vrf_routes(vty, bgp_vrf);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display per-VNI EVPN routing table.
|
||||
*/
|
||||
@ -3545,8 +3539,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
|
||||
|
||||
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
|
||||
"show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR
|
||||
"Summary of BGP neighbor status\n"
|
||||
JSON_STR)
|
||||
"Summary of BGP neighbor status\n" JSON_STR)
|
||||
|
||||
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
|
||||
"show bgp evpn route [type <macip|multicast>]",
|
||||
@ -3922,13 +3915,11 @@ DEFUN (show_bgp_vrf_l3vni_info,
|
||||
bgp = bgp_lookup_by_name(name);
|
||||
if (!bgp) {
|
||||
if (!uj)
|
||||
vty_out(vty, "BGP instance for VRF %s not found",
|
||||
name);
|
||||
vty_out(vty, "BGP instance for VRF %s not found", name);
|
||||
else {
|
||||
json_object_string_add(json, "warning",
|
||||
"BGP instance not found");
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string(json));
|
||||
vty_out(vty, "%s\n", json_object_to_json_string(json));
|
||||
json_object_free(json);
|
||||
}
|
||||
return CMD_WARNING;
|
||||
@ -3936,11 +3927,15 @@ DEFUN (show_bgp_vrf_l3vni_info,
|
||||
|
||||
if (!json) {
|
||||
vty_out(vty, "BGP VRF: %s\n", name);
|
||||
vty_out(vty, " Local-Ip: %s\n",
|
||||
inet_ntoa(bgp->originator_ip));
|
||||
vty_out(vty, " Local-Ip: %s\n", inet_ntoa(bgp->originator_ip));
|
||||
vty_out(vty, " L3-VNI: %u\n", bgp->l3vni);
|
||||
vty_out(vty, " Rmac: %s\n",
|
||||
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
|
||||
vty_out(vty, " VNI Filter: %s\n",
|
||||
CHECK_FLAG(bgp->vrf_flags,
|
||||
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
|
||||
? "prefix-routes-only"
|
||||
: "none");
|
||||
vty_out(vty, " L2-VNI List:\n");
|
||||
vty_out(vty, " ");
|
||||
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
|
||||
@ -3963,9 +3958,15 @@ DEFUN (show_bgp_vrf_l3vni_info,
|
||||
json_object_string_add(json, "local-ip",
|
||||
inet_ntoa(bgp->originator_ip));
|
||||
json_object_int_add(json, "l3vni", bgp->l3vni);
|
||||
json_object_string_add(json, "rmac",
|
||||
prefix_mac2str(&bgp->rmac, buf,
|
||||
sizeof(buf)));
|
||||
json_object_string_add(
|
||||
json, "rmac",
|
||||
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
|
||||
json_object_string_add(
|
||||
json, "vniFilter",
|
||||
CHECK_FLAG(bgp->vrf_flags,
|
||||
BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
|
||||
? "prefix-routes-only"
|
||||
: "none");
|
||||
/* list of l2vnis */
|
||||
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
|
||||
json_object_array_add(json_vnis,
|
||||
@ -3974,21 +3975,20 @@ DEFUN (show_bgp_vrf_l3vni_info,
|
||||
|
||||
/* export rts */
|
||||
for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
|
||||
json_object_array_add(json_export_rts,
|
||||
json_object_new_string(
|
||||
ecommunity_str(ecom)));
|
||||
json_object_array_add(
|
||||
json_export_rts,
|
||||
json_object_new_string(ecommunity_str(ecom)));
|
||||
json_object_object_add(json, "export-rts", json_export_rts);
|
||||
|
||||
/* import rts */
|
||||
for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
|
||||
json_object_array_add(json_import_rts,
|
||||
json_object_new_string(
|
||||
ecommunity_str(ecom)));
|
||||
json_object_array_add(
|
||||
json_import_rts,
|
||||
json_object_new_string(ecommunity_str(ecom)));
|
||||
json_object_object_add(json, "import-rts", json_import_rts);
|
||||
json_object_string_add(
|
||||
json, "rd",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
|
||||
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
@ -4038,8 +4038,7 @@ DEFUN (bgp_evpn_vrf_rt,
|
||||
ecommunity_str(ecomadd);
|
||||
|
||||
/* Do nothing if we already have this import route-target */
|
||||
if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
|
||||
ecomadd))
|
||||
if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, ecomadd))
|
||||
bgp_evpn_configure_import_rt_for_vrf(bgp, ecomadd);
|
||||
}
|
||||
|
||||
@ -4054,8 +4053,7 @@ DEFUN (bgp_evpn_vrf_rt,
|
||||
ecommunity_str(ecomadd);
|
||||
|
||||
/* Do nothing if we already have this export route-target */
|
||||
if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
|
||||
ecomadd))
|
||||
if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, ecomadd))
|
||||
bgp_evpn_configure_export_rt_for_vrf(bgp, ecomadd);
|
||||
}
|
||||
|
||||
@ -4369,6 +4367,8 @@ DEFUN (no_bgp_evpn_vni_rt_without_val,
|
||||
void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
safi_t safi)
|
||||
{
|
||||
char buf1[RD_ADDRSTRLEN];
|
||||
|
||||
if (bgp->vnihash)
|
||||
hash_iterate(bgp->vnihash,
|
||||
(void (*)(struct hash_backet *,
|
||||
@ -4381,11 +4381,55 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
if (bgp->advertise_gw_macip)
|
||||
vty_out(vty, " advertise-default-gw\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
vty_out(vty, " advertise ipv4 unicast\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
vty_out(vty, " advertise ipv6 unicast\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
|
||||
vty_out(vty, " default-originate ipv4\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
|
||||
vty_out(vty, " default-originate ipv6\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
|
||||
vty_out(vty, " rd %s\n",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
|
||||
|
||||
/* import route-target */
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
|
||||
ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(
|
||||
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
vty_out(vty, " route-target import %s\n", ecom_str);
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* export route-target */
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
|
||||
ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(
|
||||
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
vty_out(vty, " route-target export %s\n", ecom_str);
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bgp_ethernetvpn_init(void)
|
||||
@ -4415,6 +4459,8 @@ void bgp_ethernetvpn_init(void)
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
|
||||
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
|
||||
install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
|
||||
|
||||
/* "show bgp l2vpn evpn" commands. */
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
|
||||
@ -4423,7 +4469,6 @@ void bgp_ethernetvpn_init(void)
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vrf_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
|
||||
|
||||
@ -289,7 +289,8 @@ void bgp_timer_set(struct peer *peer)
|
||||
/* First entry point of peer's finite state machine. In Idle
|
||||
status start timer is on unless peer is shutdown or peer is
|
||||
inactive. All other timer must be turned off */
|
||||
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)) {
|
||||
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
|
||||
|| peer->bgp->vrf_id == VRF_UNKNOWN) {
|
||||
BGP_TIMER_OFF(peer->t_start);
|
||||
} else {
|
||||
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
|
||||
@ -1055,8 +1056,8 @@ int 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_MPLS_VPN; safi++)
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN;
|
||||
safi++)
|
||||
peer->nsf[afi][safi] = 0;
|
||||
}
|
||||
|
||||
@ -1376,6 +1377,14 @@ int bgp_start(struct peer *peer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_err(
|
||||
"%s [FSM] In a VRF that is not initialised yet",
|
||||
peer->host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register to be notified on peer up */
|
||||
if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1
|
||||
&& !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|
||||
@ -1508,9 +1517,8 @@ static int bgp_establish(struct peer *peer)
|
||||
}
|
||||
|
||||
if (other == peer)
|
||||
ret =
|
||||
1; /* bgp_establish specific code when xfer_conn
|
||||
happens. */
|
||||
ret = 1; /* bgp_establish specific code when xfer_conn
|
||||
happens. */
|
||||
|
||||
/* Reset capability open status flag. */
|
||||
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
|
||||
|
||||
@ -290,8 +290,8 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
uint16_t status = 0;
|
||||
uint32_t wpkt_quanta_old;
|
||||
|
||||
wpkt_quanta_old =
|
||||
atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed);
|
||||
wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta,
|
||||
memory_order_relaxed);
|
||||
|
||||
while (count < wpkt_quanta_old && (s = stream_fifo_head(peer->obuf))) {
|
||||
int writenum;
|
||||
@ -402,7 +402,7 @@ static uint16_t bgp_read(struct peer *peer)
|
||||
/* EAGAIN or EWOULDBLOCK; come back later */
|
||||
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
|
||||
SET_FLAG(status, BGP_IO_TRANS_ERR);
|
||||
/* Fatal error; tear down session */
|
||||
/* Fatal error; tear down session */
|
||||
} else if (nbytes < 0) {
|
||||
zlog_err("%s [Error] bgp_read_packet error: %s", peer->host,
|
||||
safe_strerror(errno));
|
||||
@ -417,7 +417,7 @@ static uint16_t bgp_read(struct peer *peer)
|
||||
|
||||
BGP_EVENT_ADD(peer, TCP_fatal_error);
|
||||
SET_FLAG(status, BGP_IO_FATAL_ERR);
|
||||
/* Received EOF / TCP session closed */
|
||||
/* Received EOF / TCP session closed */
|
||||
} else if (nbytes == 0) {
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%s [Event] BGP connection closed fd %d",
|
||||
@ -485,8 +485,8 @@ static bool validate_header(struct peer *peer)
|
||||
type);
|
||||
|
||||
bgp_notify_send_with_data(peer, BGP_NOTIFY_HEADER_ERR,
|
||||
BGP_NOTIFY_HEADER_BAD_MESTYPE,
|
||||
&type, 1);
|
||||
BGP_NOTIFY_HEADER_BAD_MESTYPE, &type,
|
||||
1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -506,14 +506,14 @@ static bool validate_header(struct peer *peer)
|
||||
zlog_debug("%s bad message length - %d for %s",
|
||||
peer->host, size,
|
||||
type == 128 ? "ROUTE-REFRESH"
|
||||
: bgp_type_str[(int) type]);
|
||||
: bgp_type_str[(int)type]);
|
||||
}
|
||||
|
||||
uint16_t nsize = htons(size);
|
||||
|
||||
bgp_notify_send_with_data(peer, BGP_NOTIFY_HEADER_ERR,
|
||||
BGP_NOTIFY_HEADER_BAD_MESLEN,
|
||||
(unsigned char *) &nsize, 2);
|
||||
(unsigned char *)&nsize, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ static void peer_process(struct hash_backet *hb, void *arg)
|
||||
}
|
||||
|
||||
/* if calculated next update for this peer < current delay, use it */
|
||||
if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <))
|
||||
if (next_update->tv_sec < 0 || timercmp(&diff, next_update, <))
|
||||
*next_update = diff;
|
||||
}
|
||||
|
||||
|
||||
@ -212,10 +212,6 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
|
||||
mpls_label_t label = MPLS_INVALID_LABEL;
|
||||
u_char llen;
|
||||
|
||||
/* Check peer status. */
|
||||
if (peer->status != Established)
|
||||
return 0;
|
||||
|
||||
pnt = packet->nlri;
|
||||
lim = pnt + packet->length;
|
||||
afi = packet->afi;
|
||||
|
||||
@ -174,13 +174,11 @@ struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
|
||||
struct lcommunity *lcom2)
|
||||
{
|
||||
if (lcom1->val)
|
||||
lcom1->val =
|
||||
XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom1->val,
|
||||
lcom_length(lcom1) + lcom_length(lcom2));
|
||||
lcom1->val = XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom1->val,
|
||||
lcom_length(lcom1) + lcom_length(lcom2));
|
||||
else
|
||||
lcom1->val =
|
||||
XMALLOC(MTYPE_LCOMMUNITY_VAL,
|
||||
lcom_length(lcom1) + lcom_length(lcom2));
|
||||
lcom1->val = XMALLOC(MTYPE_LCOMMUNITY_VAL,
|
||||
lcom_length(lcom1) + lcom_length(lcom2));
|
||||
|
||||
memcpy(lcom1->val + lcom_length(lcom1), lcom2->val, lcom_length(lcom2));
|
||||
lcom1->size += lcom2->size;
|
||||
@ -243,8 +241,7 @@ int lcommunity_cmp(const void *arg1, const void *arg2)
|
||||
const struct lcommunity *lcom2 = arg2;
|
||||
|
||||
return (lcom1->size == lcom2->size
|
||||
&& memcmp(lcom1->val, lcom2->val, lcom_length(lcom1))
|
||||
== 0);
|
||||
&& memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0);
|
||||
}
|
||||
|
||||
/* Return communities hash. */
|
||||
@ -256,8 +253,7 @@ struct hash *lcommunity_hash(void)
|
||||
/* Initialize Large Comminities related hash. */
|
||||
void lcommunity_init(void)
|
||||
{
|
||||
lcomhash = hash_create(lcommunity_hash_make,
|
||||
lcommunity_cmp,
|
||||
lcomhash = hash_create(lcommunity_hash_make, lcommunity_cmp,
|
||||
"BGP lcommunity hash");
|
||||
}
|
||||
|
||||
@ -462,8 +458,8 @@ int lcommunity_match(const struct lcommunity *lcom1,
|
||||
|
||||
/* Every community on com2 needs to be on com1 for this to match */
|
||||
while (i < lcom1->size && j < lcom2->size) {
|
||||
if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE), lcom2->val + (j * LCOMMUNITY_SIZE),
|
||||
LCOMMUNITY_SIZE)
|
||||
if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE),
|
||||
lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE)
|
||||
== 0)
|
||||
j++;
|
||||
i++;
|
||||
@ -499,8 +495,8 @@ void lcommunity_del_val(struct lcommunity *lcom, u_char *ptr)
|
||||
|
||||
if (lcom->size > 0)
|
||||
lcom->val =
|
||||
XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom->val,
|
||||
lcom_length(lcom));
|
||||
XREALLOC(MTYPE_LCOMMUNITY_VAL,
|
||||
lcom->val, lcom_length(lcom));
|
||||
else {
|
||||
XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
|
||||
lcom->val = NULL;
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "vrf.h"
|
||||
#include "bfd.h"
|
||||
#include "libfrr.h"
|
||||
#include "ns.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
@ -57,6 +58,7 @@
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_packet.h"
|
||||
#include "bgpd/bgp_keepalives.h"
|
||||
#include "bgpd/bgp_network.h"
|
||||
|
||||
#ifdef ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
@ -103,9 +105,8 @@ static struct quagga_signal_t bgp_signals[] = {
|
||||
static int retain_mode = 0;
|
||||
|
||||
/* privileges */
|
||||
static zebra_capabilities_t _caps_p[] = {
|
||||
ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN,
|
||||
};
|
||||
static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW,
|
||||
ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN};
|
||||
|
||||
struct zebra_privs_t bgpd_privs = {
|
||||
#if defined(FRR_USER) && defined(FRR_GROUP)
|
||||
@ -259,10 +260,13 @@ static int bgp_vrf_enable(struct vrf *vrf)
|
||||
/* We have instance configured, link to VRF and make it "up". */
|
||||
bgp_vrf_link(bgp, vrf);
|
||||
|
||||
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
|
||||
/* Update any redistribute vrf bitmaps if the vrf_id changed */
|
||||
if (old_vrf_id != bgp->vrf_id)
|
||||
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
|
||||
bgp_instance_up(bgp);
|
||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -281,7 +285,12 @@ static int bgp_vrf_disable(struct vrf *vrf)
|
||||
|
||||
bgp = bgp_lookup_by_name(vrf->name);
|
||||
if (bgp) {
|
||||
|
||||
vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
|
||||
vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6);
|
||||
|
||||
old_vrf_id = bgp->vrf_id;
|
||||
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false);
|
||||
/* We have instance configured, unlink from VRF and make it
|
||||
* "down". */
|
||||
bgp_vrf_unlink(bgp, vrf);
|
||||
|
||||
@ -92,6 +92,26 @@ int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bgp_interface_same
|
||||
*
|
||||
* Return true if ifindex for ifp1 and ifp2 are the same, else return false.
|
||||
*/
|
||||
static int bgp_interface_same(struct interface *ifp1, struct interface *ifp2)
|
||||
{
|
||||
if (!ifp1 && !ifp2)
|
||||
return 1;
|
||||
|
||||
if (!ifp1 && ifp2)
|
||||
return 0;
|
||||
|
||||
if (ifp1 && !ifp2)
|
||||
return 0;
|
||||
|
||||
return (ifp1->ifindex == ifp2->ifindex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bgp_info_nexthop_cmp
|
||||
*
|
||||
@ -121,16 +141,18 @@ int bgp_info_nexthop_cmp(struct bgp_info *bi1, struct bgp_info *bi2)
|
||||
&bi2->attr->mp_nexthop_global);
|
||||
break;
|
||||
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
|
||||
addr1 = (bi1->attr->mp_nexthop_prefer_global) ?
|
||||
bi1->attr->mp_nexthop_global
|
||||
: bi1->attr->mp_nexthop_local;
|
||||
addr2 = (bi2->attr->mp_nexthop_prefer_global) ?
|
||||
bi2->attr->mp_nexthop_global
|
||||
: bi2->attr->mp_nexthop_local;
|
||||
addr1 = (bi1->attr->mp_nexthop_prefer_global)
|
||||
? bi1->attr->mp_nexthop_global
|
||||
: bi1->attr->mp_nexthop_local;
|
||||
addr2 = (bi2->attr->mp_nexthop_prefer_global)
|
||||
? bi2->attr->mp_nexthop_global
|
||||
: bi2->attr->mp_nexthop_local;
|
||||
|
||||
if (!bi1->attr->mp_nexthop_prefer_global
|
||||
&& !bi2->attr->mp_nexthop_prefer_global)
|
||||
compare = !bgp_interface_same(
|
||||
bi1->peer->ifp, bi2->peer->ifp);
|
||||
|
||||
if (!bi1->attr->mp_nexthop_prefer_global &&
|
||||
!bi2->attr->mp_nexthop_prefer_global)
|
||||
compare = !(bi1->peer->ifindex == bi2->peer->ifindex);
|
||||
if (!compare)
|
||||
compare = IPV6_ADDR_CMP(&addr1, &addr2);
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_rd.h"
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
|
||||
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
|
||||
#define MPLS_LABEL_IS_NULL(label) \
|
||||
@ -51,4 +52,128 @@ extern int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg,
|
||||
int tags, u_char use_json);
|
||||
|
||||
extern void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
|
||||
struct bgp_info *info_vrf);
|
||||
|
||||
extern void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
|
||||
struct bgp_info *info_vrf);
|
||||
|
||||
extern void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn,
|
||||
struct bgp *bgp_vrf, afi_t afi);
|
||||
|
||||
extern void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn,
|
||||
struct bgp *bgp_vrf, afi_t afi);
|
||||
|
||||
extern void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, afi_t afi);
|
||||
|
||||
extern void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, struct bgp *bgp_vpn,
|
||||
afi_t afi);
|
||||
|
||||
extern void vpn_leak_to_vrf_update(struct bgp *bgp_vpn,
|
||||
struct bgp_info *info_vpn);
|
||||
|
||||
extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
|
||||
struct bgp_info *info_vpn);
|
||||
|
||||
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
|
||||
extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi);
|
||||
|
||||
static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
|
||||
const char **pmsg)
|
||||
{
|
||||
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
|
||||
&& bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
|
||||
if (pmsg)
|
||||
*pmsg = "source bgp instance neither vrf nor default";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is vrf configured to export to vpn? */
|
||||
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
|
||||
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
|
||||
if (pmsg)
|
||||
*pmsg = "export not set";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is there an RT list set? */
|
||||
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
|
||||
if (pmsg)
|
||||
*pmsg = "rtlist tovpn not defined";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is there an RD set? */
|
||||
if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
|
||||
BGP_VPN_POLICY_TOVPN_RD_SET)) {
|
||||
if (pmsg)
|
||||
*pmsg = "rd not defined";
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
|
||||
const char **pmsg)
|
||||
{
|
||||
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
|
||||
&& bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
|
||||
if (pmsg)
|
||||
*pmsg = "destination bgp instance neither vrf nor default";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is vrf configured to import from vpn? */
|
||||
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
|
||||
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
|
||||
if (pmsg)
|
||||
*pmsg = "import not set";
|
||||
return 0;
|
||||
}
|
||||
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
|
||||
if (pmsg)
|
||||
*pmsg = "rtlist fromvpn not defined";
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void vpn_leak_prechange(vpn_policy_direction_t direction,
|
||||
afi_t afi, struct bgp *bgp_vpn,
|
||||
struct bgp *bgp_vrf)
|
||||
{
|
||||
if ((direction == BGP_VPN_POLICY_DIR_FROMVPN) &&
|
||||
vpn_leak_from_vpn_active(bgp_vrf, afi, NULL)) {
|
||||
|
||||
vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi);
|
||||
}
|
||||
if ((direction == BGP_VPN_POLICY_DIR_TOVPN) &&
|
||||
vpn_leak_to_vpn_active(bgp_vrf, afi, NULL)) {
|
||||
|
||||
vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
||||
afi_t afi, struct bgp *bgp_vpn,
|
||||
struct bgp *bgp_vrf)
|
||||
{
|
||||
if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
|
||||
vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
|
||||
if (direction == BGP_VPN_POLICY_DIR_TOVPN) {
|
||||
|
||||
if (bgp_vrf->vpn_policy[afi].tovpn_label !=
|
||||
bgp_vrf->vpn_policy[afi]
|
||||
.tovpn_zebra_vrf_label_last_sent) {
|
||||
vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
|
||||
}
|
||||
|
||||
vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
|
||||
}
|
||||
}
|
||||
|
||||
extern void vpn_policy_routemap_event(const char *rmap_name);
|
||||
|
||||
#endif /* _QUAGGA_BGP_MPLSVPN_H */
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include "queue.h"
|
||||
#include "hash.h"
|
||||
#include "filter.h"
|
||||
#include "ns.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_open.h"
|
||||
@ -44,13 +45,14 @@
|
||||
|
||||
extern struct zebra_privs_t bgpd_privs;
|
||||
|
||||
static int bgp_bind(struct peer *);
|
||||
static char *bgp_get_bound_name(struct peer *peer);
|
||||
|
||||
/* BGP listening socket. */
|
||||
struct bgp_listener {
|
||||
int fd;
|
||||
union sockunion su;
|
||||
struct thread *thread;
|
||||
struct bgp *bgp;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -284,6 +286,7 @@ static int bgp_accept(struct thread *thread)
|
||||
return -1;
|
||||
}
|
||||
listener->thread = NULL;
|
||||
|
||||
thread_add_read(bm->master, bgp_accept, listener, accept_sock,
|
||||
&listener->thread);
|
||||
|
||||
@ -296,8 +299,13 @@ static int bgp_accept(struct thread *thread)
|
||||
}
|
||||
set_nonblocking(bgp_sock);
|
||||
|
||||
/* Obtain BGP instance this connection is meant for. */
|
||||
if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) {
|
||||
/* Obtain BGP instance this connection is meant for.
|
||||
* - if it is a VRF netns sock, then BGP is in listener structure
|
||||
* - otherwise, the bgp instance need to be demultiplexed
|
||||
*/
|
||||
if (listener->bgp)
|
||||
bgp = listener->bgp;
|
||||
else if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) {
|
||||
if (bgp_debug_neighbor_events(NULL))
|
||||
zlog_debug(
|
||||
"[Event] Could not get instance for incoming conn from %s",
|
||||
@ -407,7 +415,7 @@ static int bgp_accept(struct thread *thread)
|
||||
peer->doppelganger = peer1;
|
||||
peer1->doppelganger = peer;
|
||||
peer->fd = bgp_sock;
|
||||
bgp_bind(peer);
|
||||
vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer));
|
||||
bgp_fsm_change_status(peer, Active);
|
||||
BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
|
||||
|
||||
@ -435,20 +443,20 @@ static int bgp_accept(struct thread *thread)
|
||||
}
|
||||
|
||||
/* BGP socket bind. */
|
||||
static int bgp_bind(struct peer *peer)
|
||||
static char *bgp_get_bound_name(struct peer *peer)
|
||||
{
|
||||
#ifdef SO_BINDTODEVICE
|
||||
int ret;
|
||||
int myerrno;
|
||||
char *name = NULL;
|
||||
|
||||
/* If not bound to an interface or part of a VRF, we don't care. */
|
||||
if (!peer->bgp->vrf_id && !peer->ifname && !peer->conf_if)
|
||||
return 0;
|
||||
if (!peer)
|
||||
return NULL;
|
||||
|
||||
if ((peer->bgp->vrf_id == VRF_DEFAULT) && !peer->ifname
|
||||
&& !peer->conf_if)
|
||||
return NULL;
|
||||
|
||||
if (peer->su.sa.sa_family != AF_INET
|
||||
&& peer->su.sa.sa_family != AF_INET6)
|
||||
return 0; // unexpected
|
||||
return NULL; // unexpected
|
||||
|
||||
/* For IPv6 peering, interface (unnumbered or link-local with interface)
|
||||
* takes precedence over VRF. For IPv4 peering, explicit interface or
|
||||
@ -461,30 +469,7 @@ static int bgp_bind(struct peer *peer)
|
||||
else
|
||||
name = peer->ifname ? peer->ifname : peer->bgp->name;
|
||||
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%s Binding to interface %s", peer->host, name);
|
||||
|
||||
if (bgpd_privs.change(ZPRIVS_RAISE))
|
||||
zlog_err("bgp_bind: could not raise privs");
|
||||
|
||||
ret = setsockopt(peer->fd, SOL_SOCKET, SO_BINDTODEVICE, name,
|
||||
strlen(name));
|
||||
myerrno = errno;
|
||||
|
||||
if (bgpd_privs.change(ZPRIVS_LOWER))
|
||||
zlog_err("bgp_bind: could not lower privs");
|
||||
|
||||
if (ret < 0) {
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("bind to interface %s failed, errno=%d",
|
||||
name, myerrno);
|
||||
return ret;
|
||||
}
|
||||
#endif /* SO_BINDTODEVICE */
|
||||
return 0;
|
||||
return name;
|
||||
}
|
||||
|
||||
static int bgp_update_address(struct interface *ifp, const union sockunion *dst,
|
||||
@ -558,8 +543,13 @@ int bgp_connect(struct peer *peer)
|
||||
zlog_debug("Peer address not learnt: Returning from connect");
|
||||
return 0;
|
||||
}
|
||||
if (bgpd_privs.change(ZPRIVS_RAISE))
|
||||
zlog_err("Can't raise privileges");
|
||||
/* Make socket for the peer. */
|
||||
peer->fd = sockunion_socket(&peer->su);
|
||||
peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id,
|
||||
bgp_get_bound_name(peer));
|
||||
if (bgpd_privs.change(ZPRIVS_LOWER))
|
||||
zlog_err("Can't lower privileges");
|
||||
if (peer->fd < 0)
|
||||
return -1;
|
||||
|
||||
@ -591,9 +581,6 @@ int bgp_connect(struct peer *peer)
|
||||
if (peer->password)
|
||||
bgp_md5_set_connect(peer->fd, &peer->su, peer->password);
|
||||
|
||||
/* Bind socket. */
|
||||
bgp_bind(peer);
|
||||
|
||||
/* Update source bind. */
|
||||
if (bgp_update_source(peer) < 0) {
|
||||
return connect_error;
|
||||
@ -642,12 +629,12 @@ int bgp_getsockname(struct peer *peer)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
|
||||
static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
|
||||
struct bgp *bgp)
|
||||
{
|
||||
struct bgp_listener *listener;
|
||||
int ret, en;
|
||||
@ -683,8 +670,13 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
|
||||
return ret;
|
||||
}
|
||||
|
||||
listener = XMALLOC(MTYPE_BGP_LISTENER, sizeof(*listener));
|
||||
listener = XCALLOC(MTYPE_BGP_LISTENER, sizeof(*listener));
|
||||
listener->fd = sock;
|
||||
|
||||
/* this socket needs a change of ns. record bgp back pointer */
|
||||
if (bgp->vrf_id != VRF_DEFAULT && vrf_is_mapped_on_netns(bgp->vrf_id))
|
||||
listener->bgp = bgp;
|
||||
|
||||
memcpy(&listener->su, sa, salen);
|
||||
listener->thread = NULL;
|
||||
thread_add_read(bm->master, bgp_accept, listener, sock,
|
||||
@ -695,7 +687,7 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen)
|
||||
}
|
||||
|
||||
/* IPv6 supported version of BGP server socket setup. */
|
||||
int bgp_socket(unsigned short port, const char *address)
|
||||
int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
|
||||
{
|
||||
struct addrinfo *ainfo;
|
||||
struct addrinfo *ainfo_save;
|
||||
@ -710,7 +702,12 @@ int bgp_socket(unsigned short port, const char *address)
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
port_str[sizeof(port_str) - 1] = '\0';
|
||||
|
||||
ret = getaddrinfo(address, port_str, &req, &ainfo_save);
|
||||
if (bgpd_privs.change(ZPRIVS_RAISE))
|
||||
zlog_err("Can't raise privileges");
|
||||
ret = vrf_getaddrinfo(address, port_str, &req, &ainfo_save,
|
||||
bgp->vrf_id);
|
||||
if (bgpd_privs.change(ZPRIVS_LOWER))
|
||||
zlog_err("Can't lower privileges");
|
||||
if (ret != 0) {
|
||||
zlog_err("getaddrinfo: %s", gai_strerror(ret));
|
||||
return -1;
|
||||
@ -723,8 +720,12 @@ int bgp_socket(unsigned short port, const char *address)
|
||||
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
sock = socket(ainfo->ai_family, ainfo->ai_socktype,
|
||||
ainfo->ai_protocol);
|
||||
if (bgpd_privs.change(ZPRIVS_RAISE))
|
||||
zlog_err("Can't raise privileges");
|
||||
sock = vrf_socket(ainfo->ai_family, ainfo->ai_socktype,
|
||||
ainfo->ai_protocol, bgp->vrf_id, NULL);
|
||||
if (bgpd_privs.change(ZPRIVS_LOWER))
|
||||
zlog_err("Can't lower privileges");
|
||||
if (sock < 0) {
|
||||
zlog_err("socket: %s", safe_strerror(errno));
|
||||
continue;
|
||||
@ -734,7 +735,8 @@ int bgp_socket(unsigned short port, const char *address)
|
||||
* ttl=255 */
|
||||
sockopt_ttl(ainfo->ai_family, sock, MAXTTL);
|
||||
|
||||
ret = bgp_listener(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
ret = bgp_listener(sock, ainfo->ai_addr, ainfo->ai_addrlen,
|
||||
bgp);
|
||||
if (ret == 0)
|
||||
++count;
|
||||
else
|
||||
@ -742,8 +744,9 @@ int bgp_socket(unsigned short port, const char *address)
|
||||
}
|
||||
freeaddrinfo(ainfo_save);
|
||||
if (count == 0) {
|
||||
zlog_err("%s: no usable addresses please check other programs usage of specified port %d",
|
||||
__func__, port);
|
||||
zlog_err(
|
||||
"%s: no usable addresses please check other programs usage of specified port %d",
|
||||
__func__, port);
|
||||
zlog_err("%s: Program cannot continue", __func__);
|
||||
exit(-1);
|
||||
}
|
||||
@ -751,6 +754,32 @@ int bgp_socket(unsigned short port, const char *address)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this function closes vrf socket
|
||||
* this should be called only for vrf socket with netns backend
|
||||
*/
|
||||
void bgp_close_vrf_socket(struct bgp *bgp)
|
||||
{
|
||||
struct listnode *node, *next;
|
||||
struct bgp_listener *listener;
|
||||
|
||||
if (!bgp)
|
||||
return;
|
||||
|
||||
if (bm->listen_sockets == NULL)
|
||||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->listen_sockets, node, next, listener)) {
|
||||
if (listener->bgp == bgp) {
|
||||
thread_cancel(listener->thread);
|
||||
close(listener->fd);
|
||||
listnode_delete(bm->listen_sockets, listener);
|
||||
XFREE(MTYPE_BGP_LISTENER, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* this function closes main socket
|
||||
*/
|
||||
void bgp_close(void)
|
||||
{
|
||||
struct listnode *node, *next;
|
||||
@ -760,6 +789,8 @@ void bgp_close(void)
|
||||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->listen_sockets, node, next, listener)) {
|
||||
if (listener->bgp)
|
||||
continue;
|
||||
thread_cancel(listener->thread);
|
||||
close(listener->fd);
|
||||
listnode_delete(bm->listen_sockets, listener);
|
||||
|
||||
@ -23,7 +23,9 @@
|
||||
|
||||
#define BGP_SOCKET_SNDBUF_SIZE 65536
|
||||
|
||||
extern int bgp_socket(unsigned short, const char *);
|
||||
extern int bgp_socket(struct bgp *bgp, unsigned short port,
|
||||
const char *address);
|
||||
extern void bgp_close_vrf_socket(struct bgp *bgp);
|
||||
extern void bgp_close(void);
|
||||
extern int bgp_connect(struct peer *);
|
||||
extern int bgp_getsockname(struct peer *);
|
||||
|
||||
@ -122,8 +122,7 @@ static int bgp_tip_hash_cmp(const void *p1, const void *p2)
|
||||
|
||||
void bgp_tip_hash_init(struct bgp *bgp)
|
||||
{
|
||||
bgp->tip_hash = hash_create(bgp_tip_hash_key_make,
|
||||
bgp_tip_hash_cmp,
|
||||
bgp->tip_hash = hash_create(bgp_tip_hash_key_make, bgp_tip_hash_cmp,
|
||||
"BGP TIP hash");
|
||||
}
|
||||
|
||||
@ -204,9 +203,9 @@ static int bgp_address_hash_cmp(const void *p1, const void *p2)
|
||||
|
||||
void bgp_address_init(struct bgp *bgp)
|
||||
{
|
||||
bgp->address_hash = hash_create(bgp_address_hash_key_make,
|
||||
bgp_address_hash_cmp,
|
||||
"BGP Address Hash");
|
||||
bgp->address_hash =
|
||||
hash_create(bgp_address_hash_key_make, bgp_address_hash_cmp,
|
||||
"BGP Address Hash");
|
||||
}
|
||||
|
||||
void bgp_address_destroy(struct bgp *bgp)
|
||||
@ -448,16 +447,14 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
|
||||
rn1 = rn2 = NULL;
|
||||
|
||||
bgp = SUBGRP_INST(subgrp);
|
||||
rn1 = bgp_node_match(bgp->connected_table[AFI_IP],
|
||||
&np);
|
||||
rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
|
||||
if (!rn1)
|
||||
return 0;
|
||||
|
||||
SUBGRP_FOREACH_PEER(subgrp, paf) {
|
||||
SUBGRP_FOREACH_PEER (subgrp, paf) {
|
||||
p.u.prefix4 = paf->peer->su.sin.sin_addr;
|
||||
|
||||
rn2 = bgp_node_match(bgp->connected_table[AFI_IP],
|
||||
&p);
|
||||
rn2 = bgp_node_match(bgp->connected_table[AFI_IP], &p);
|
||||
if (rn1 == rn2) {
|
||||
bgp_unlock_node(rn1);
|
||||
bgp_unlock_node(rn2);
|
||||
@ -472,8 +469,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bgp_show_nexthops_detail(struct vty *vty,
|
||||
struct bgp *bgp,
|
||||
static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
|
||||
struct bgp_nexthop_cache *bnc)
|
||||
{
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
@ -483,39 +479,35 @@ static void bgp_show_nexthops_detail(struct vty *vty,
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
vty_out(vty, " gate %s\n",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6,
|
||||
buf, sizeof(buf)));
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
|
||||
sizeof(buf)));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " gate %s, if %s\n",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6,
|
||||
buf, sizeof(buf)),
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
bgp->vrf_id));
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
|
||||
sizeof(buf)),
|
||||
ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
vty_out(vty, " gate %s\n",
|
||||
inet_ntop(AF_INET, &nexthop->gate.ipv4,
|
||||
buf, sizeof(buf)));
|
||||
inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
|
||||
sizeof(buf)));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " if %s\n",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
bgp->vrf_id));
|
||||
ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " gate %s, if %s\n",
|
||||
inet_ntop(AF_INET, &nexthop->gate.ipv4,
|
||||
buf, sizeof(buf)),
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
bgp->vrf_id));
|
||||
inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
|
||||
sizeof(buf)),
|
||||
ifindex2ifname(nexthop->ifindex, bgp->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " blackhole\n");
|
||||
break;
|
||||
default:
|
||||
vty_out(vty,
|
||||
" invalid nexthop type %u\n",
|
||||
vty_out(vty, " invalid nexthop type %u\n",
|
||||
nexthop->type);
|
||||
}
|
||||
}
|
||||
@ -549,7 +541,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail)
|
||||
|
||||
bgp_show_nexthops_detail(vty, bgp, bnc);
|
||||
|
||||
} else{
|
||||
} else {
|
||||
vty_out(vty, " %s invalid\n",
|
||||
inet_ntop(rn->p.family,
|
||||
&rn->p.u.prefix, buf,
|
||||
|
||||
@ -546,14 +546,14 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
|
||||
return;
|
||||
|
||||
p = &(bnc->node->p);
|
||||
if ((command == ZEBRA_NEXTHOP_REGISTER ||
|
||||
command == ZEBRA_IMPORT_ROUTE_REGISTER) &&
|
||||
(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|
||||
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
|
||||
if ((command == ZEBRA_NEXTHOP_REGISTER
|
||||
|| command == ZEBRA_IMPORT_ROUTE_REGISTER)
|
||||
&& (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|
||||
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
|
||||
exact_match = true;
|
||||
|
||||
ret = zclient_send_rnh(zclient, command, p,
|
||||
exact_match, bnc->bgp->vrf_id);
|
||||
ret = zclient_send_rnh(zclient, command, p, exact_match,
|
||||
bnc->bgp->vrf_id);
|
||||
/* TBD: handle the failure */
|
||||
if (ret < 0)
|
||||
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
|
||||
|
||||
@ -389,7 +389,7 @@ int bgp_generate_updgrp_packets(struct thread *thread)
|
||||
if (peer->status != Established)
|
||||
return 0;
|
||||
|
||||
if (peer->bgp && peer->bgp->main_peers_update_hold)
|
||||
if (peer->bgp->main_peers_update_hold)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
@ -1573,9 +1573,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
|
||||
* Non-MP IPv4/Unicast EoR is a completely empty UPDATE
|
||||
* and MP EoR should have only an empty MP_UNREACH
|
||||
*/
|
||||
if ((!update_len && !withdraw_len &&
|
||||
nlris[NLRI_MP_UPDATE].length == 0) ||
|
||||
(attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
|
||||
if ((!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0)
|
||||
|| (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
|
||||
afi_t afi = 0;
|
||||
safi_t safi;
|
||||
|
||||
|
||||
333
bgpd/bgp_route.c
333
bgpd/bgp_route.c
@ -82,6 +82,21 @@
|
||||
extern const char *bgp_origin_str[];
|
||||
extern const char *bgp_origin_long_str[];
|
||||
|
||||
/* PMSI strings. */
|
||||
#define PMSI_TNLTYPE_STR_NO_INFO "No info"
|
||||
#define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
|
||||
static const struct message bgp_pmsi_tnltype_str[] = {
|
||||
{PMSI_TNLTYPE_NO_INFO, PMSI_TNLTYPE_STR_NO_INFO},
|
||||
{PMSI_TNLTYPE_RSVP_TE_P2MP, "RSVP-TE P2MP"},
|
||||
{PMSI_TNLTYPE_MLDP_P2MP, "mLDP P2MP"},
|
||||
{PMSI_TNLTYPE_PIM_SSM, "PIM-SSM"},
|
||||
{PMSI_TNLTYPE_PIM_SM, "PIM-SM"},
|
||||
{PMSI_TNLTYPE_PIM_BIDIR, "PIM-BIDIR"},
|
||||
{PMSI_TNLTYPE_INGR_REPL, "Ingress Replication"},
|
||||
{PMSI_TNLTYPE_MLDP_MP2MP, "mLDP MP2MP"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
|
||||
safi_t safi, struct prefix *p,
|
||||
struct prefix_rd *prd)
|
||||
@ -542,7 +557,8 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new,
|
||||
* - BGP_ROUTE_AGGREGATE
|
||||
* - BGP_ROUTE_REDISTRIBUTE
|
||||
*/
|
||||
if (!(new->sub_type == BGP_ROUTE_NORMAL)) {
|
||||
if (!(new->sub_type == BGP_ROUTE_NORMAL ||
|
||||
new->sub_type == BGP_ROUTE_IMPORTED)) {
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to preferred BGP_ROUTE type",
|
||||
@ -550,7 +566,8 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(exist->sub_type == BGP_ROUTE_NORMAL)) {
|
||||
if (!(exist->sub_type == BGP_ROUTE_NORMAL ||
|
||||
new->sub_type == BGP_ROUTE_IMPORTED)) {
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to preferred BGP_ROUTE type",
|
||||
@ -1364,6 +1381,16 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (((afi == AFI_IP) || (afi == AFI_IP6))
|
||||
&& ((safi == SAFI_MPLS_VPN) || (safi == SAFI_UNICAST))
|
||||
&& (ri->type == ZEBRA_ROUTE_BGP)
|
||||
&& (ri->sub_type == BGP_ROUTE_IMPORTED)) {
|
||||
|
||||
/* Applies to routes leaked vpn->vrf and vrf->vpn */
|
||||
|
||||
samepeer_safe = 1;
|
||||
}
|
||||
|
||||
/* With addpath we may be asked to TX all kinds of paths so make sure
|
||||
* ri is valid */
|
||||
if (!CHECK_FLAG(ri->flags, BGP_INFO_VALID)
|
||||
@ -1852,17 +1879,30 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
|
||||
&& (ri != old_select))
|
||||
bgp_info_reap(rn, ri);
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: ri %p in holddown", __func__,
|
||||
ri);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ri->peer && ri->peer != bgp->peer_self
|
||||
&& !CHECK_FLAG(ri->peer->sflags, PEER_STATUS_NSF_WAIT))
|
||||
if (ri->peer->status != Established)
|
||||
if (ri->peer->status != Established) {
|
||||
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: ri %p non self peer %s not estab state",
|
||||
__func__, ri, ri->peer->host);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED)
|
||||
&& (!CHECK_FLAG(ri->flags, BGP_INFO_DMED_SELECTED))) {
|
||||
bgp_info_unset_flag(rn, ri, BGP_INFO_DMED_CHECK);
|
||||
if (debug)
|
||||
zlog_debug("%s: ri %p dmed", __func__, ri);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1966,10 +2006,16 @@ int subgroup_process_announce_selected(struct update_subgroup *subgrp,
|
||||
onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer
|
||||
: NULL);
|
||||
|
||||
if (BGP_DEBUG(update, UPDATE_OUT)) {
|
||||
char buf_prefix[PREFIX_STRLEN];
|
||||
prefix2str(p, buf_prefix, sizeof(buf_prefix));
|
||||
zlog_debug("%s: p=%s, selected=%p", __func__, buf_prefix,
|
||||
selected);
|
||||
}
|
||||
|
||||
/* First update is deferred until ORF or ROUTE-REFRESH is received */
|
||||
if (onlypeer
|
||||
&& CHECK_FLAG(onlypeer->af_sflags[afi][safi],
|
||||
PEER_STATUS_ORF_WAIT_REFRESH))
|
||||
if (onlypeer && CHECK_FLAG(onlypeer->af_sflags[afi][safi],
|
||||
PEER_STATUS_ORF_WAIT_REFRESH))
|
||||
return 0;
|
||||
|
||||
memset(&attr, 0, sizeof(struct attr));
|
||||
@ -2051,6 +2097,25 @@ struct bgp_process_queue {
|
||||
unsigned int queued;
|
||||
};
|
||||
|
||||
/*
|
||||
* old_select = The old best path
|
||||
* new_select = the new best path
|
||||
*
|
||||
* if (!old_select && new_select)
|
||||
* We are sending new information on.
|
||||
*
|
||||
* if (old_select && new_select) {
|
||||
* if (new_select != old_select)
|
||||
* We have a new best path send a change
|
||||
* else
|
||||
* We've received a update with new attributes that needs
|
||||
* to be passed on.
|
||||
* }
|
||||
*
|
||||
* if (old_select && !new_select)
|
||||
* We have no eligible route that we can announce or the rn
|
||||
* is being removed.
|
||||
*/
|
||||
static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
@ -2058,6 +2123,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
struct bgp_info *new_select;
|
||||
struct bgp_info *old_select;
|
||||
struct bgp_info_pair old_and_new;
|
||||
char pfx_buf[PREFIX2STR_BUFFER];
|
||||
int debug = 0;
|
||||
|
||||
/* Is it end of initial update? (after startup) */
|
||||
if (!rn) {
|
||||
@ -2075,6 +2142,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
return;
|
||||
}
|
||||
|
||||
debug = bgp_debug_bestpath(&rn->p);
|
||||
if (debug) {
|
||||
prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("%s: p=%s afi=%s, safi=%s start", __func__, pfx_buf,
|
||||
afi2str(afi), safi2str(safi));
|
||||
}
|
||||
|
||||
/* Best path selection. */
|
||||
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
|
||||
afi, safi);
|
||||
@ -2115,6 +2189,14 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
bgp_unregister_for_label(rn);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug(
|
||||
"%s: p=%s afi=%s, safi=%s, old_select=%p, new_select=%p",
|
||||
__func__, pfx_buf, afi2str(afi), safi2str(safi),
|
||||
old_select, new_select);
|
||||
}
|
||||
|
||||
/* If best route remains the same and this is not due to user-initiated
|
||||
* clear, see exactly what needs to be done.
|
||||
*/
|
||||
@ -2129,11 +2211,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
vnc_import_bgp_exterior_add_route(bgp, p, old_select);
|
||||
#endif
|
||||
if (bgp_fibupd_safi(safi)
|
||||
&& !bgp_option_check(BGP_OPT_NO_FIB)
|
||||
&& new_select->type == ZEBRA_ROUTE_BGP
|
||||
&& new_select->sub_type == BGP_ROUTE_NORMAL)
|
||||
bgp_zebra_announce(rn, p, old_select, bgp, afi,
|
||||
safi);
|
||||
&& !bgp_option_check(BGP_OPT_NO_FIB)) {
|
||||
|
||||
if (new_select->type == ZEBRA_ROUTE_BGP
|
||||
&& (new_select->sub_type == BGP_ROUTE_NORMAL
|
||||
|| new_select->sub_type
|
||||
== BGP_ROUTE_IMPORTED))
|
||||
|
||||
bgp_zebra_announce(rn, p, old_select,
|
||||
bgp, afi, safi);
|
||||
}
|
||||
}
|
||||
UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
|
||||
bgp_zebra_clear_route_change_flags(rn);
|
||||
@ -2180,6 +2267,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
if (old_select)
|
||||
bgp_info_unset_flag(rn, old_select, BGP_INFO_SELECTED);
|
||||
if (new_select) {
|
||||
if (debug)
|
||||
zlog_debug("%s: setting SELECTED flag", __func__);
|
||||
bgp_info_set_flag(rn, new_select, BGP_INFO_SELECTED);
|
||||
bgp_info_unset_flag(rn, new_select, BGP_INFO_ATTR_CHANGED);
|
||||
UNSET_FLAG(new_select->flags, BGP_INFO_MULTIPATH_CHG);
|
||||
@ -2215,23 +2304,30 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
&& !bgp_option_check(BGP_OPT_NO_FIB)) {
|
||||
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
|
||||
&& (new_select->sub_type == BGP_ROUTE_NORMAL
|
||||
|| new_select->sub_type == BGP_ROUTE_AGGREGATE))
|
||||
|| new_select->sub_type == BGP_ROUTE_AGGREGATE
|
||||
|| new_select->sub_type == BGP_ROUTE_IMPORTED))
|
||||
|
||||
bgp_zebra_announce(rn, p, new_select, bgp, afi, safi);
|
||||
else {
|
||||
/* Withdraw the route from the kernel. */
|
||||
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
|
||||
&& (old_select->sub_type == BGP_ROUTE_NORMAL
|
||||
|| old_select->sub_type == BGP_ROUTE_AGGREGATE))
|
||||
bgp_zebra_withdraw(p, old_select, safi);
|
||||
|| old_select->sub_type == BGP_ROUTE_AGGREGATE
|
||||
|| old_select->sub_type == BGP_ROUTE_IMPORTED))
|
||||
|
||||
bgp_zebra_withdraw(p, old_select, bgp, safi);
|
||||
}
|
||||
}
|
||||
|
||||
/* advertise/withdraw type-5 routes */
|
||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||
if (new_select)
|
||||
bgp_evpn_advertise_type5_route(
|
||||
bgp, &rn->p, new_select->attr, afi, safi);
|
||||
else if (old_select)
|
||||
if (advertise_type5_routes(bgp, afi) && new_select &&
|
||||
(!new_select->extra || !new_select->extra->parent))
|
||||
bgp_evpn_advertise_type5_route(bgp, &rn->p,
|
||||
new_select->attr,
|
||||
afi, safi);
|
||||
else if (advertise_type5_routes(bgp, afi) && old_select &&
|
||||
(!old_select->extra || !old_select->extra->parent))
|
||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||
}
|
||||
|
||||
@ -3120,6 +3216,18 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
bgp_unlock_node(rn);
|
||||
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp, ri);
|
||||
}
|
||||
if ((SAFI_MPLS_VPN == safi)
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_to_vrf_update(bgp, ri);
|
||||
}
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
if (SAFI_MPLS_VPN == safi) {
|
||||
mpls_label_t label_decoded = decode_label(label);
|
||||
@ -3236,6 +3344,16 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
/* Process change. */
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
|
||||
}
|
||||
if ((SAFI_MPLS_VPN == safi)
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_to_vrf_update(bgp, new);
|
||||
}
|
||||
#if ENABLE_BGP_VNC
|
||||
if (SAFI_MPLS_VPN == safi) {
|
||||
mpls_label_t label_decoded = decode_label(label);
|
||||
@ -3274,6 +3392,18 @@ filtered:
|
||||
if (safi == SAFI_EVPN)
|
||||
bgp_evpn_unimport_route(bgp, afi, safi, p, ri);
|
||||
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
|
||||
}
|
||||
if ((SAFI_MPLS_VPN == safi)
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_to_vrf_withdraw(bgp, ri);
|
||||
}
|
||||
|
||||
bgp_rib_remove(rn, ri, peer, afi, safi);
|
||||
}
|
||||
|
||||
@ -3360,9 +3490,19 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
}
|
||||
|
||||
/* Withdraw specified route from routing table. */
|
||||
if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY))
|
||||
if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) {
|
||||
bgp_rib_withdraw(rn, ri, peer, afi, safi, prd);
|
||||
else if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
|
||||
}
|
||||
if ((SAFI_MPLS_VPN == safi)
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_to_vrf_withdraw(bgp, ri);
|
||||
}
|
||||
} else if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
@ -3545,10 +3685,12 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
|
||||
struct bgp_node *rn = cnq->rn;
|
||||
struct peer *peer = wq->spec.data;
|
||||
struct bgp_info *ri;
|
||||
struct bgp *bgp;
|
||||
afi_t afi = bgp_node_table(rn)->afi;
|
||||
safi_t safi = bgp_node_table(rn)->safi;
|
||||
|
||||
assert(rn && peer);
|
||||
bgp = peer->bgp;
|
||||
|
||||
/* It is possible that we have multiple paths for a prefix from a peer
|
||||
* if that peer is using AddPath.
|
||||
@ -3567,8 +3709,18 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
|
||||
/* If this is an EVPN route, process for
|
||||
* un-import. */
|
||||
if (safi == SAFI_EVPN)
|
||||
bgp_evpn_unimport_route(peer->bgp, afi, safi,
|
||||
bgp_evpn_unimport_route(bgp, afi, safi,
|
||||
&rn->p, ri);
|
||||
/* Handle withdraw for VRF route-leaking and L3VPN */
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF ||
|
||||
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT))
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(),
|
||||
bgp, ri);
|
||||
if (SAFI_MPLS_VPN == safi &&
|
||||
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||
vpn_leak_to_vrf_withdraw(bgp, ri);
|
||||
|
||||
bgp_rib_remove(rn, ri, peer, afi, safi);
|
||||
}
|
||||
}
|
||||
@ -3834,7 +3986,8 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
|
||||
}
|
||||
}
|
||||
|
||||
static void bgp_cleanup_table(struct bgp_table *table, safi_t safi)
|
||||
static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
|
||||
safi_t safi)
|
||||
{
|
||||
struct bgp_node *rn;
|
||||
struct bgp_info *ri;
|
||||
@ -3846,9 +3999,12 @@ static void bgp_cleanup_table(struct bgp_table *table, safi_t safi)
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)
|
||||
&& ri->type == ZEBRA_ROUTE_BGP
|
||||
&& (ri->sub_type == BGP_ROUTE_NORMAL
|
||||
|| ri->sub_type == BGP_ROUTE_AGGREGATE)) {
|
||||
|| ri->sub_type == BGP_ROUTE_AGGREGATE
|
||||
|| ri->sub_type == BGP_ROUTE_IMPORTED)) {
|
||||
|
||||
if (bgp_fibupd_safi(safi))
|
||||
bgp_zebra_withdraw(&rn->p, ri, safi);
|
||||
bgp_zebra_withdraw(&rn->p, ri,
|
||||
bgp, safi);
|
||||
bgp_info_reap(rn, ri);
|
||||
}
|
||||
}
|
||||
@ -3863,7 +4019,8 @@ void bgp_cleanup_routes(struct bgp *bgp)
|
||||
for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
|
||||
if (afi == AFI_L2VPN)
|
||||
continue;
|
||||
bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST);
|
||||
bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST],
|
||||
SAFI_UNICAST);
|
||||
/*
|
||||
* VPN and ENCAP and EVPN tables are two-level (RD is top level)
|
||||
*/
|
||||
@ -3873,7 +4030,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
|
||||
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
|
||||
rn = bgp_route_next(rn)) {
|
||||
if (rn->info) {
|
||||
bgp_cleanup_table(
|
||||
bgp_cleanup_table(bgp,
|
||||
(struct bgp_table *)(rn->info),
|
||||
safi);
|
||||
bgp_table_finish((struct bgp_table **)&(
|
||||
@ -3886,7 +4043,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
|
||||
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
|
||||
rn = bgp_route_next(rn)) {
|
||||
if (rn->info) {
|
||||
bgp_cleanup_table(
|
||||
bgp_cleanup_table(bgp,
|
||||
(struct bgp_table *)(rn->info),
|
||||
safi);
|
||||
bgp_table_finish((struct bgp_table **)&(
|
||||
@ -3900,7 +4057,8 @@ void bgp_cleanup_routes(struct bgp *bgp)
|
||||
for (rn = bgp_table_top(bgp->rib[AFI_L2VPN][SAFI_EVPN]); rn;
|
||||
rn = bgp_route_next(rn)) {
|
||||
if (rn->info) {
|
||||
bgp_cleanup_table((struct bgp_table *)(rn->info),
|
||||
bgp_cleanup_table(bgp,
|
||||
(struct bgp_table *)(rn->info),
|
||||
SAFI_EVPN);
|
||||
bgp_table_finish((struct bgp_table **)&(rn->info));
|
||||
rn->info = NULL;
|
||||
@ -3939,10 +4097,6 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
|
||||
int addpath_encoded;
|
||||
u_int32_t addpath_id;
|
||||
|
||||
/* Check peer status. */
|
||||
if (peer->status != Established)
|
||||
return 0;
|
||||
|
||||
pnt = packet->nlri;
|
||||
lim = pnt + packet->length;
|
||||
afi = packet->afi;
|
||||
@ -4247,6 +4401,15 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
|
||||
/* Process change. */
|
||||
bgp_aggregate_increment(bgp, p, ri, afi, safi);
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type
|
||||
== BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp,
|
||||
ri);
|
||||
}
|
||||
|
||||
bgp_unlock_node(rn);
|
||||
aspath_unintern(&attr.aspath);
|
||||
return;
|
||||
@ -4294,6 +4457,12 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
|
||||
/* Process change. */
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
|
||||
}
|
||||
|
||||
/* Unintern original. */
|
||||
aspath_unintern(&attr.aspath);
|
||||
}
|
||||
@ -4314,6 +4483,11 @@ void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi,
|
||||
|
||||
/* Withdraw static BGP route from routing table. */
|
||||
if (ri) {
|
||||
if (SAFI_UNICAST == safi
|
||||
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, ri);
|
||||
}
|
||||
bgp_aggregate_decrement(bgp, p, ri, afi, safi);
|
||||
bgp_unlink_nexthop(ri);
|
||||
bgp_info_delete(rn, ri);
|
||||
@ -4349,6 +4523,10 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p,
|
||||
ri->peer, NULL, p, prd, ri->attr, afi, safi, ri->type,
|
||||
1); /* Kill, since it is an administrative change */
|
||||
#endif
|
||||
if (SAFI_MPLS_VPN == safi
|
||||
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
vpn_leak_to_vrf_withdraw(bgp, ri);
|
||||
}
|
||||
bgp_aggregate_decrement(bgp, p, ri, afi, safi);
|
||||
bgp_info_delete(rn, ri);
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
@ -4477,6 +4655,11 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
|
||||
/* Process change. */
|
||||
bgp_aggregate_increment(bgp, p, ri, afi, safi);
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
|
||||
if (SAFI_MPLS_VPN == safi
|
||||
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
vpn_leak_to_vrf_update(bgp, ri);
|
||||
}
|
||||
#if ENABLE_BGP_VNC
|
||||
rfapiProcessUpdate(ri->peer, NULL, p, &bgp_static->prd,
|
||||
ri->attr, afi, safi, ri->type,
|
||||
@ -4513,6 +4696,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
|
||||
/* Process change. */
|
||||
bgp_process(bgp, rn, afi, safi);
|
||||
|
||||
if (SAFI_MPLS_VPN == safi
|
||||
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
vpn_leak_to_vrf_update(bgp, new);
|
||||
}
|
||||
#if ENABLE_BGP_VNC
|
||||
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
|
||||
safi, new->type, new->sub_type, &label);
|
||||
@ -5977,6 +6164,14 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
||||
bgp_process(bgp, bn, afi, SAFI_UNICAST);
|
||||
bgp_unlock_node(bn);
|
||||
aspath_unintern(&attr.aspath);
|
||||
|
||||
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
|| (bgp->inst_type
|
||||
== BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_update(
|
||||
bgp_get_default(), bgp, bi);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -5989,6 +6184,12 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
||||
bgp_info_add(bn, new);
|
||||
bgp_unlock_node(bn);
|
||||
bgp_process(bgp, bn, afi, SAFI_UNICAST);
|
||||
|
||||
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
|| (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp, new);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unintern original. */
|
||||
@ -6015,6 +6216,12 @@ void bgp_redistribute_delete(struct bgp *bgp, struct prefix *p, u_char type,
|
||||
break;
|
||||
|
||||
if (ri) {
|
||||
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
|| (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(),
|
||||
bgp, ri);
|
||||
}
|
||||
bgp_aggregate_decrement(bgp, p, ri, afi, SAFI_UNICAST);
|
||||
bgp_info_delete(rn, ri);
|
||||
bgp_process(bgp, rn, afi, SAFI_UNICAST);
|
||||
@ -6040,6 +6247,12 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
|
||||
break;
|
||||
|
||||
if (ri) {
|
||||
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
|| (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
|
||||
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(),
|
||||
bgp, ri);
|
||||
}
|
||||
bgp_aggregate_decrement(bgp, &rn->p, ri, afi,
|
||||
SAFI_UNICAST);
|
||||
bgp_info_delete(rn, ri);
|
||||
@ -6839,10 +7052,9 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
|
||||
bgp_damp_reuse_time_vty(vty, binfo, timebuf, BGP_UPTIME_LEN,
|
||||
use_json, json);
|
||||
else
|
||||
vty_out(vty, "%s ",
|
||||
bgp_damp_reuse_time_vty(vty, binfo, timebuf,
|
||||
BGP_UPTIME_LEN, use_json,
|
||||
json));
|
||||
vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, binfo, timebuf,
|
||||
BGP_UPTIME_LEN,
|
||||
use_json, json));
|
||||
|
||||
/* Print attribute */
|
||||
attr = binfo->attr;
|
||||
@ -6921,9 +7133,8 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p,
|
||||
peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, use_json,
|
||||
json);
|
||||
else
|
||||
vty_out(vty, "%s ",
|
||||
peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
|
||||
NULL));
|
||||
vty_out(vty, "%s ", peer_uptime(bdi->start_time, timebuf,
|
||||
BGP_UPTIME_LEN, 0, NULL));
|
||||
|
||||
if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
|
||||
&& !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY)) {
|
||||
@ -7035,6 +7246,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
json_object *json_ext_community = NULL;
|
||||
json_object *json_lcommunity = NULL;
|
||||
json_object *json_last_update = NULL;
|
||||
json_object *json_pmsi = NULL;
|
||||
json_object *json_nexthop_global = NULL;
|
||||
json_object *json_nexthop_ll = NULL;
|
||||
json_object *json_nexthops = NULL;
|
||||
@ -7787,6 +7999,24 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
json_last_update);
|
||||
} else
|
||||
vty_out(vty, " Last update: %s", ctime(&tbuf));
|
||||
|
||||
/* Line 10 display PMSI tunnel attribute, if present */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
|
||||
const char *str = lookup_msg(bgp_pmsi_tnltype_str,
|
||||
attr->pmsi_tnl_type,
|
||||
PMSI_TNLTYPE_STR_DEFAULT);
|
||||
|
||||
if (json_paths) {
|
||||
json_pmsi = json_object_new_object();
|
||||
json_object_string_add(json_pmsi,
|
||||
"tunnelType", str);
|
||||
json_object_object_add(json_path, "pmsi",
|
||||
json_pmsi);
|
||||
} else
|
||||
vty_out(vty, " PMSI Tunnel Type: %s\n",
|
||||
str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We've constructed the json object for this path, add it to the json
|
||||
@ -8029,9 +8259,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
}
|
||||
|
||||
if (!use_json && header) {
|
||||
vty_out(vty,
|
||||
"BGP table version is %" PRIu64
|
||||
", local router ID is %s\n",
|
||||
vty_out(vty, "BGP table version is %" PRIu64
|
||||
", local router ID is %s\n",
|
||||
table->version,
|
||||
inet_ntoa(bgp->router_id));
|
||||
vty_out(vty, BGP_SHOW_SCODE_HEADER);
|
||||
@ -8513,9 +8742,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
|
||||
if (display)
|
||||
json_object_object_add(json, "paths", json_paths);
|
||||
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
} else {
|
||||
if (!display) {
|
||||
@ -9590,9 +9818,8 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
|
||||
json, "recommended",
|
||||
"Please report this bug, with the above command output");
|
||||
}
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
} else {
|
||||
|
||||
@ -9826,9 +10053,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
|
||||
"bgpOriginatingDefaultNetwork",
|
||||
"0.0.0.0");
|
||||
} else {
|
||||
vty_out(vty,
|
||||
"BGP table version is %" PRIu64
|
||||
", local router ID is %s\n",
|
||||
vty_out(vty, "BGP table version is %" PRIu64
|
||||
", local router ID is %s\n",
|
||||
table->version, inet_ntoa(bgp->router_id));
|
||||
vty_out(vty, BGP_SHOW_SCODE_HEADER);
|
||||
vty_out(vty, BGP_SHOW_OCODE_HEADER);
|
||||
@ -9971,9 +10197,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
|
||||
output_count);
|
||||
}
|
||||
if (use_json) {
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,10 +104,8 @@ struct bgp_info_extra {
|
||||
struct in6_addr addr6;
|
||||
} un; /* cached un address */
|
||||
time_t create_time;
|
||||
struct
|
||||
prefix
|
||||
aux_prefix; /* AFI_L2VPN: the IP addr,
|
||||
if family set */
|
||||
struct prefix aux_prefix; /* AFI_L2VPN: the IP addr,
|
||||
if family set */
|
||||
} import;
|
||||
|
||||
} vnc;
|
||||
@ -116,6 +114,30 @@ struct bgp_info_extra {
|
||||
/* For imported routes into a VNI (or VRF), this points to the parent.
|
||||
*/
|
||||
void *parent;
|
||||
|
||||
/*
|
||||
* Some tunnelish parameters follow. Maybe consolidate into an
|
||||
* internal tunnel structure?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original bgp instance for imported routes. Needed for:
|
||||
* 1. Find all routes from a specific vrf for deletion
|
||||
* 2. vrf context of original nexthop
|
||||
*
|
||||
* Store pointer to bgp instance rather than bgp->vrf_id because
|
||||
* bgp->vrf_id is not always valid (or may change?).
|
||||
*
|
||||
* Set to NULL if route is not imported from another bgp instance.
|
||||
*/
|
||||
struct bgp *bgp_orig;
|
||||
|
||||
/*
|
||||
* Nexthop in context of original bgp instance. Needed
|
||||
* for label resolution of core mpls routes exported to a vrf.
|
||||
* Set nexthop_orig.family to 0 if not valid.
|
||||
*/
|
||||
struct prefix nexthop_orig;
|
||||
};
|
||||
|
||||
struct bgp_info {
|
||||
@ -181,6 +203,7 @@ struct bgp_info {
|
||||
#ifdef ENABLE_BGP_VNC
|
||||
# define BGP_ROUTE_RFP 4
|
||||
#endif
|
||||
#define BGP_ROUTE_IMPORTED 5 /* from another bgp instance/safi */
|
||||
|
||||
u_short instance;
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
#include "bgpd/bgp_evpn_private.h"
|
||||
#include "bgpd/bgp_evpn_vty.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
||||
@ -594,6 +595,24 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
|
||||
route_match_ip_route_source_prefix_list_compile,
|
||||
route_match_ip_route_source_prefix_list_free};
|
||||
|
||||
/* `match evpn default-route' */
|
||||
|
||||
/* Match function should return 1 if match is success else 0 */
|
||||
static route_map_result_t route_match_evpn_default_route(void *rule,
|
||||
struct prefix *p,
|
||||
route_map_object_t
|
||||
type, void *object)
|
||||
{
|
||||
if (type == RMAP_BGP && is_evpn_prefix_default(p))
|
||||
return RMAP_MATCH;
|
||||
|
||||
return RMAP_NOMATCH;
|
||||
}
|
||||
|
||||
/* Route map commands for default-route matching. */
|
||||
struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
|
||||
"evpn default-route", route_match_evpn_default_route, NULL, NULL};
|
||||
|
||||
/* `match mac address MAC_ACCESS_LIST' */
|
||||
|
||||
/* Match function should return 1 if match is success else return
|
||||
@ -742,8 +761,7 @@ static void route_match_evpn_route_type_free(void *rule)
|
||||
/* Route map commands for evpn route-type matching. */
|
||||
struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
|
||||
"evpn route-type", route_match_evpn_route_type,
|
||||
route_match_evpn_route_type_compile,
|
||||
route_match_evpn_route_type_free};
|
||||
route_match_evpn_route_type_compile, route_match_evpn_route_type_free};
|
||||
|
||||
/* `match local-preference LOCAL-PREF' */
|
||||
|
||||
@ -3079,12 +3097,13 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|
||||
|
||||
/* for type5 command route-maps */
|
||||
FOREACH_AFI_SAFI (afi, safi) {
|
||||
if (bgp->adv_cmd_rmap[afi][safi].name &&
|
||||
strcmp(rmap_name, bgp->adv_cmd_rmap[afi][safi].name) == 0) {
|
||||
if (bgp->adv_cmd_rmap[afi][safi].name
|
||||
&& strcmp(rmap_name, bgp->adv_cmd_rmap[afi][safi].name)
|
||||
== 0) {
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug(
|
||||
"Processing route_map %s update on advertise type5 route command",
|
||||
rmap_name);
|
||||
"Processing route_map %s update on advertise type5 route command",
|
||||
rmap_name);
|
||||
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
|
||||
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
|
||||
}
|
||||
@ -3096,13 +3115,17 @@ static int bgp_route_map_process_update_cb(char *rmap_name)
|
||||
struct listnode *node, *nnode;
|
||||
struct bgp *bgp;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
|
||||
bgp_route_map_process_update(bgp, rmap_name, 1);
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
zlog_debug("%s: calling vnc_routemap_update", __func__);
|
||||
vnc_routemap_update(bgp, __func__);
|
||||
/* zlog_debug("%s: calling vnc_routemap_update", __func__); */
|
||||
vnc_routemap_update(bgp, __func__);
|
||||
#endif
|
||||
}
|
||||
|
||||
vpn_policy_routemap_event(rmap_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3249,6 +3272,29 @@ DEFUN (no_match_evpn_vni,
|
||||
RMAP_EVENT_MATCH_DELETED);
|
||||
}
|
||||
|
||||
DEFUN (match_evpn_default_route,
|
||||
match_evpn_default_route_cmd,
|
||||
"match evpn default-route",
|
||||
MATCH_STR
|
||||
EVPN_HELP_STR
|
||||
"default EVPN type-5 route\n")
|
||||
{
|
||||
return bgp_route_match_add(vty, "evpn default-route", NULL,
|
||||
RMAP_EVENT_MATCH_ADDED);
|
||||
}
|
||||
|
||||
DEFUN (no_match_evpn_default_route,
|
||||
no_match_evpn_default_route_cmd,
|
||||
"no match evpn default-route",
|
||||
NO_STR
|
||||
MATCH_STR
|
||||
EVPN_HELP_STR
|
||||
"default EVPN type-5 route\n")
|
||||
{
|
||||
return bgp_route_match_delete(vty, "evpn default-route", NULL,
|
||||
RMAP_EVENT_MATCH_DELETED);
|
||||
}
|
||||
|
||||
DEFUN (match_peer,
|
||||
match_peer_cmd,
|
||||
"match peer <A.B.C.D|X:X::X:X|WORD>",
|
||||
@ -4628,6 +4674,7 @@ void bgp_route_map_init(void)
|
||||
route_map_install_match(&route_match_mac_address_cmd);
|
||||
route_map_install_match(&route_match_evpn_vni_cmd);
|
||||
route_map_install_match(&route_match_evpn_route_type_cmd);
|
||||
route_map_install_match(&route_match_evpn_default_route_cmd);
|
||||
|
||||
route_map_install_set(&route_set_ip_nexthop_cmd);
|
||||
route_map_install_set(&route_set_local_pref_cmd);
|
||||
@ -4664,6 +4711,8 @@ void bgp_route_map_init(void)
|
||||
install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
|
||||
install_element(RMAP_NODE, &match_evpn_route_type_cmd);
|
||||
install_element(RMAP_NODE, &no_match_evpn_route_type_cmd);
|
||||
install_element(RMAP_NODE, &match_evpn_default_route_cmd);
|
||||
install_element(RMAP_NODE, &no_match_evpn_default_route_cmd);
|
||||
|
||||
install_element(RMAP_NODE, &match_aspath_cmd);
|
||||
install_element(RMAP_NODE, &no_match_aspath_cmd);
|
||||
|
||||
135
bgpd/bgp_rpki.c
135
bgpd/bgp_rpki.c
@ -1,9 +1,12 @@
|
||||
/*
|
||||
* BGP RPKI
|
||||
* Copyright (C) 2013 Michael Mester (m.mester@fu-berlin.de), for FU Berlin
|
||||
* Copyright (C) 2014-2017 Andreas Reuter (andreas.reuter@fu-berlin.de), for FU Berlin
|
||||
* Copyright (C) 2016-2017 Colin Sames (colin.sames@haw-hamburg.de), for HAW Hamburg
|
||||
* Copyright (C) 2017 Marcel Röthke (marcel.roethke@haw-hamburg.de), for HAW Hamburg
|
||||
* Copyright (C) 2014-2017 Andreas Reuter (andreas.reuter@fu-berlin.de), for FU
|
||||
* Berlin
|
||||
* Copyright (C) 2016-2017 Colin Sames (colin.sames@haw-hamburg.de), for HAW
|
||||
* Hamburg
|
||||
* Copyright (C) 2017 Marcel Röthke (marcel.roethke@haw-hamburg.de), for HAW
|
||||
* Hamburg
|
||||
*
|
||||
* This file is part of FRRouting.
|
||||
*
|
||||
@ -77,14 +80,14 @@ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group")
|
||||
#define RPKI_OUTPUT_STRING "Control rpki specific settings\n"
|
||||
|
||||
struct cache {
|
||||
enum { TCP, SSH } type;
|
||||
struct tr_socket *tr_socket;
|
||||
union {
|
||||
enum { TCP, SSH } type;
|
||||
struct tr_socket *tr_socket;
|
||||
union {
|
||||
struct tr_tcp_config *tcp_config;
|
||||
struct tr_ssh_config *ssh_config;
|
||||
} tr_config;
|
||||
struct rtr_socket *rtr_socket;
|
||||
uint8_t preference;
|
||||
} tr_config;
|
||||
struct rtr_socket *rtr_socket;
|
||||
uint8_t preference;
|
||||
};
|
||||
|
||||
enum return_values { SUCCESS = 0, ERROR = -1 };
|
||||
@ -105,27 +108,22 @@ static void overwrite_exit_commands(void);
|
||||
static void free_cache(struct cache *cache);
|
||||
static struct rtr_mgr_group *get_groups(void);
|
||||
#if defined(FOUND_SSH)
|
||||
static int add_ssh_cache(const char *host,
|
||||
const unsigned int port,
|
||||
const char *username,
|
||||
const char *client_privkey_path,
|
||||
static int add_ssh_cache(const char *host, const unsigned int port,
|
||||
const char *username, const char *client_privkey_path,
|
||||
const char *client_pubkey_path,
|
||||
const char *server_pubkey_path,
|
||||
const uint8_t preference);
|
||||
#endif
|
||||
static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
|
||||
static struct cache *find_cache(const uint8_t preference);
|
||||
static int add_tcp_cache(const char *host,
|
||||
const char *port,
|
||||
static int add_tcp_cache(const char *host, const char *port,
|
||||
const uint8_t preference);
|
||||
static void print_record(const struct pfx_record *record, void *data);
|
||||
static int is_synchronized(void);
|
||||
static int is_running(void);
|
||||
static void route_match_free(void *rule);
|
||||
static route_map_result_t route_match(void *rule,
|
||||
struct prefix *prefix,
|
||||
route_map_object_t type,
|
||||
void *object);
|
||||
static route_map_result_t route_match(void *rule, struct prefix *prefix,
|
||||
route_map_object_t type, void *object);
|
||||
static void *route_match_compile(const char *arg);
|
||||
|
||||
static struct rtr_mgr_config *rtr_config;
|
||||
@ -139,9 +137,8 @@ static unsigned int timeout;
|
||||
static unsigned int initial_synchronisation_timeout;
|
||||
|
||||
static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1};
|
||||
static struct route_map_rule_cmd route_match_rpki_cmd = {"rpki", route_match,
|
||||
route_match_compile,
|
||||
route_match_free};
|
||||
static struct route_map_rule_cmd route_match_rpki_cmd = {
|
||||
"rpki", route_match, route_match_compile, route_match_free};
|
||||
|
||||
static void *malloc_wrapper(size_t size)
|
||||
{
|
||||
@ -162,8 +159,7 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
|
||||
struct prefix *prefix);
|
||||
|
||||
static route_map_result_t route_match(void *rule, struct prefix *prefix,
|
||||
route_map_object_t type,
|
||||
void *object)
|
||||
route_map_object_t type, void *object)
|
||||
{
|
||||
int *rpki_status = rule;
|
||||
struct bgp_info *bgp_info;
|
||||
@ -285,7 +281,7 @@ static int bgp_rpki_init(struct thread_master *master)
|
||||
rtr_is_running = 0;
|
||||
|
||||
cache_list = list_new();
|
||||
cache_list->del = (void (*)(void *)) &free_cache;
|
||||
cache_list->del = (void (*)(void *)) & free_cache;
|
||||
|
||||
polling_period = POLLING_PERIOD_DEFAULT;
|
||||
expire_interval = EXPIRE_INTERVAL_DEFAULT;
|
||||
@ -307,9 +303,7 @@ static int bgp_rpki_fini(void)
|
||||
|
||||
static int bgp_rpki_module_init(void)
|
||||
{
|
||||
lrtr_set_alloc_functions(malloc_wrapper,
|
||||
realloc_wrapper,
|
||||
free_wrapper);
|
||||
lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper);
|
||||
|
||||
hook_register(frr_late_init, bgp_rpki_init);
|
||||
hook_register(frr_early_fini, &bgp_rpki_fini);
|
||||
@ -332,8 +326,8 @@ static int start(void)
|
||||
struct rtr_mgr_group *groups = get_groups();
|
||||
|
||||
ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period,
|
||||
expire_interval, retry_interval,
|
||||
NULL, NULL, NULL, NULL);
|
||||
expire_interval, retry_interval, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (ret == RTR_ERROR) {
|
||||
RPKI_DEBUG("Init rtr_mgr failed.");
|
||||
return ERROR;
|
||||
@ -447,8 +441,8 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
|
||||
if (as_segment->type == AS_SEQUENCE) {
|
||||
// Get rightmost asn
|
||||
as_number = as_segment->as[as_segment->length - 1];
|
||||
} else if (as_segment->type == AS_CONFED_SEQUENCE ||
|
||||
as_segment->type == AS_CONFED_SET) {
|
||||
} else if (as_segment->type == AS_CONFED_SEQUENCE
|
||||
|| as_segment->type == AS_CONFED_SET) {
|
||||
// Set own as number
|
||||
as_number = peer->bgp->as;
|
||||
} else {
|
||||
@ -520,16 +514,15 @@ static int add_cache(struct cache *cache)
|
||||
|
||||
listnode_add(cache_list, cache);
|
||||
|
||||
if (rtr_is_running &&
|
||||
rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
|
||||
if (rtr_is_running
|
||||
&& rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int add_tcp_cache(const char *host,
|
||||
const char *port,
|
||||
static int add_tcp_cache(const char *host, const char *port,
|
||||
const uint8_t preference)
|
||||
{
|
||||
struct rtr_socket *rtr_socket;
|
||||
@ -556,10 +549,8 @@ static int add_tcp_cache(const char *host,
|
||||
}
|
||||
|
||||
#if defined(FOUND_SSH)
|
||||
static int add_ssh_cache(const char *host,
|
||||
const unsigned int port,
|
||||
const char *username,
|
||||
const char *client_privkey_path,
|
||||
static int add_ssh_cache(const char *host, const unsigned int port,
|
||||
const char *username, const char *client_privkey_path,
|
||||
const char *client_pubkey_path,
|
||||
const char *server_pubkey_path,
|
||||
const uint8_t preference)
|
||||
@ -577,8 +568,8 @@ static int add_ssh_cache(const char *host,
|
||||
ssh_config->bindaddr = NULL;
|
||||
|
||||
ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
|
||||
ssh_config->client_privkey_path = XSTRDUP(
|
||||
MTYPE_BGP_RPKI_CACHE, client_privkey_path);
|
||||
ssh_config->client_privkey_path =
|
||||
XSTRDUP(MTYPE_BGP_RPKI_CACHE, client_privkey_path);
|
||||
ssh_config->server_hostkey_path =
|
||||
XSTRDUP(MTYPE_BGP_RPKI_CACHE, server_pubkey_path);
|
||||
|
||||
@ -597,16 +588,13 @@ static int add_ssh_cache(const char *host,
|
||||
static void free_cache(struct cache *cache)
|
||||
{
|
||||
if (cache->type == TCP) {
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE,
|
||||
cache->tr_config.tcp_config->host);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE,
|
||||
cache->tr_config.tcp_config->port);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->host);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config->port);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.tcp_config);
|
||||
}
|
||||
#if defined(FOUND_SSH)
|
||||
else {
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE,
|
||||
cache->tr_config.ssh_config->host);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE, cache->tr_config.ssh_config->host);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE,
|
||||
cache->tr_config.ssh_config->username);
|
||||
XFREE(MTYPE_BGP_RPKI_CACHE,
|
||||
@ -644,22 +632,17 @@ static int config_write(struct vty *vty)
|
||||
#endif
|
||||
case TCP:
|
||||
tcp_config = cache->tr_config.tcp_config;
|
||||
vty_out(vty,
|
||||
" rpki cache %s %s ",
|
||||
tcp_config->host,
|
||||
tcp_config->port);
|
||||
vty_out(vty, " rpki cache %s %s ",
|
||||
tcp_config->host, tcp_config->port);
|
||||
break;
|
||||
#if defined(FOUND_SSH)
|
||||
case SSH:
|
||||
ssh_config = cache->tr_config.ssh_config;
|
||||
vty_out(vty,
|
||||
" rpki cache %s %u %s %s %s ",
|
||||
ssh_config->host,
|
||||
ssh_config->port,
|
||||
vty_out(vty, " rpki cache %s %u %s %s %s ",
|
||||
ssh_config->host, ssh_config->port,
|
||||
ssh_config->username,
|
||||
ssh_config->client_privkey_path,
|
||||
ssh_config->server_hostkey_path
|
||||
!= NULL
|
||||
ssh_config->server_hostkey_path != NULL
|
||||
? ssh_config
|
||||
->server_hostkey_path
|
||||
: " ");
|
||||
@ -694,7 +677,8 @@ DEFUN (bgp_rpki_start,
|
||||
"start rpki support\n")
|
||||
{
|
||||
if (listcount(cache_list) == 0)
|
||||
vty_out(vty, "Could not start rpki because no caches are configured\n");
|
||||
vty_out(vty,
|
||||
"Could not start rpki because no caches are configured\n");
|
||||
|
||||
if (!is_running()) {
|
||||
if (start() == ERROR) {
|
||||
@ -746,7 +730,7 @@ DEFPY (rpki_expire_interval,
|
||||
"Set expire interval\n"
|
||||
"Expire interval value\n")
|
||||
{
|
||||
if (tmp >= polling_period) {
|
||||
if ((unsigned int)tmp >= polling_period) {
|
||||
expire_interval = tmp;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -855,9 +839,9 @@ DEFPY (rpki_cache,
|
||||
// use ssh connection
|
||||
if (ssh_uname) {
|
||||
#if defined(FOUND_SSH)
|
||||
return_value = add_ssh_cache(
|
||||
cache, sshport, ssh_uname, ssh_privkey, ssh_pubkey,
|
||||
server_pubkey, preference);
|
||||
return_value =
|
||||
add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey,
|
||||
ssh_pubkey, server_pubkey, preference);
|
||||
#else
|
||||
vty_out(vty,
|
||||
"ssh sockets are not supported. "
|
||||
@ -923,8 +907,7 @@ DEFUN (show_rpki_prefix_table,
|
||||
struct cache *cache;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
|
||||
vty_out(vty,
|
||||
"host: %s port: %s\n",
|
||||
vty_out(vty, "host: %s port: %s\n",
|
||||
cache->tr_config.tcp_config->host,
|
||||
cache->tr_config.tcp_config->port);
|
||||
}
|
||||
@ -947,8 +930,7 @@ DEFUN (show_rpki_cache_server,
|
||||
struct cache *cache;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
|
||||
vty_out(vty,
|
||||
"host: %s port: %s\n",
|
||||
vty_out(vty, "host: %s port: %s\n",
|
||||
cache->tr_config.tcp_config->host,
|
||||
cache->tr_config.tcp_config->port);
|
||||
}
|
||||
@ -973,8 +955,7 @@ DEFUN (show_rpki_cache_connection,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
vty_out(vty, "Connected to group %d\n", group->preference);
|
||||
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node,
|
||||
cache)) {
|
||||
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
|
||||
if (cache->preference == group->preference) {
|
||||
struct tr_tcp_config *tcp_config;
|
||||
#if defined(FOUND_SSH)
|
||||
@ -984,8 +965,7 @@ DEFUN (show_rpki_cache_connection,
|
||||
switch (cache->type) {
|
||||
case TCP:
|
||||
tcp_config =
|
||||
cache->tr_config
|
||||
.tcp_config;
|
||||
cache->tr_config.tcp_config;
|
||||
vty_out(vty,
|
||||
"rpki tcp cache %s %s pref %hhu\n",
|
||||
tcp_config->host,
|
||||
@ -996,8 +976,7 @@ DEFUN (show_rpki_cache_connection,
|
||||
#if defined(FOUND_SSH)
|
||||
case SSH:
|
||||
ssh_config =
|
||||
cache->tr_config
|
||||
.ssh_config;
|
||||
cache->tr_config.ssh_config;
|
||||
vty_out(vty,
|
||||
"rpki ssh cache %s %u pref %hhu\n",
|
||||
ssh_config->host,
|
||||
@ -1142,9 +1121,9 @@ static void overwrite_exit_commands(void)
|
||||
for (i = 0; i < cmd_vector->active; ++i) {
|
||||
struct cmd_element *cmd = vector_lookup(cmd_vector, i);
|
||||
|
||||
if (strcmp(cmd->string, "exit") == 0 ||
|
||||
strcmp(cmd->string, "quit") == 0 ||
|
||||
strcmp(cmd->string, "end") == 0) {
|
||||
if (strcmp(cmd->string, "exit") == 0
|
||||
|| strcmp(cmd->string, "quit") == 0
|
||||
|| strcmp(cmd->string, "end") == 0) {
|
||||
uninstall_element(RPKI_NODE, cmd);
|
||||
}
|
||||
}
|
||||
@ -1156,7 +1135,7 @@ static void overwrite_exit_commands(void)
|
||||
|
||||
static void install_cli_commands(void)
|
||||
{
|
||||
//TODO: make config write work
|
||||
// TODO: make config write work
|
||||
install_node(&rpki_node, &config_write);
|
||||
install_default(RPKI_NODE);
|
||||
overwrite_exit_commands();
|
||||
@ -1212,4 +1191,4 @@ static void install_cli_commands(void)
|
||||
|
||||
FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
|
||||
.description = "Enable RPKI support for FRR.",
|
||||
.init = bgp_rpki_module_init)
|
||||
.init = bgp_rpki_module_init)
|
||||
|
||||
@ -864,8 +864,6 @@ static u_char *bgp4PathAttrTable(struct variable *v, oid name[], size_t *length,
|
||||
return SNMP_INTEGER(-1);
|
||||
break;
|
||||
case BGP4PATHATTRBEST: /* 13 */
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define BGP4_PathAttrBest_false 1
|
||||
#define BGP4_PathAttrBest_true 2
|
||||
if (CHECK_FLAG(binfo->flags, BGP_INFO_SELECTED))
|
||||
|
||||
@ -85,9 +85,8 @@ static void sync_init(struct update_subgroup *subgrp)
|
||||
BGP_ADV_FIFO_INIT(&subgrp->sync->update);
|
||||
BGP_ADV_FIFO_INIT(&subgrp->sync->withdraw);
|
||||
BGP_ADV_FIFO_INIT(&subgrp->sync->withdraw_low);
|
||||
subgrp->hash = hash_create(baa_hash_key,
|
||||
baa_hash_cmp,
|
||||
"BGP SubGroup Hash");
|
||||
subgrp->hash =
|
||||
hash_create(baa_hash_key, baa_hash_cmp, "BGP SubGroup Hash");
|
||||
|
||||
/* We use a larger buffer for subgrp->work in the event that:
|
||||
* - We RX a BGP_UPDATE where the attributes alone are just
|
||||
@ -1545,8 +1544,7 @@ void update_bgp_group_init(struct bgp *bgp)
|
||||
|
||||
AF_FOREACH (afid)
|
||||
bgp->update_groups[afid] =
|
||||
hash_create(updgrp_hash_key_make,
|
||||
updgrp_hash_cmp,
|
||||
hash_create(updgrp_hash_key_make, updgrp_hash_cmp,
|
||||
"BGP Update Group Hash");
|
||||
}
|
||||
|
||||
@ -1877,11 +1875,12 @@ void subgroup_trigger_write(struct update_subgroup *subgrp)
|
||||
* the subgroup output queue into their own output queue. This action
|
||||
* will trigger a write job on the I/O thread.
|
||||
*/
|
||||
SUBGRP_FOREACH_PEER(subgrp, paf)
|
||||
if (paf->peer->status == Established)
|
||||
thread_add_timer_msec(bm->master, bgp_generate_updgrp_packets,
|
||||
paf->peer, 0,
|
||||
&paf->peer->t_generate_updgrp_packets);
|
||||
SUBGRP_FOREACH_PEER (subgrp, paf)
|
||||
if (paf->peer->status == Established)
|
||||
thread_add_timer_msec(
|
||||
bm->master, bgp_generate_updgrp_packets,
|
||||
paf->peer, 0,
|
||||
&paf->peer->t_generate_updgrp_packets);
|
||||
}
|
||||
|
||||
int update_group_clear_update_dbg(struct update_group *updgrp, void *arg)
|
||||
|
||||
@ -287,7 +287,6 @@ struct update_subgroup {
|
||||
*/
|
||||
#define SUBGRP_DECR_STAT(subgrp, stat) SUBGRP_INCR_STAT_BY(subgrp, stat, -1)
|
||||
|
||||
|
||||
typedef int (*updgrp_walkcb)(struct update_group *updgrp, void *ctx);
|
||||
|
||||
/* really a private structure */
|
||||
@ -341,23 +340,23 @@ struct updwalk_context {
|
||||
* Walk all subgroups in an update group.
|
||||
*/
|
||||
#define UPDGRP_FOREACH_SUBGRP(updgrp, subgrp) \
|
||||
LIST_FOREACH(subgrp, &((updgrp)->subgrps), updgrp_train)
|
||||
LIST_FOREACH (subgrp, &((updgrp)->subgrps), updgrp_train)
|
||||
|
||||
#define UPDGRP_FOREACH_SUBGRP_SAFE(updgrp, subgrp, tmp_subgrp) \
|
||||
LIST_FOREACH_SAFE(subgrp, &((updgrp)->subgrps), updgrp_train, \
|
||||
tmp_subgrp)
|
||||
LIST_FOREACH_SAFE (subgrp, &((updgrp)->subgrps), updgrp_train, \
|
||||
tmp_subgrp)
|
||||
|
||||
#define SUBGRP_FOREACH_PEER(subgrp, paf) \
|
||||
LIST_FOREACH(paf, &(subgrp->peers), subgrp_train)
|
||||
LIST_FOREACH (paf, &(subgrp->peers), subgrp_train)
|
||||
|
||||
#define SUBGRP_FOREACH_PEER_SAFE(subgrp, paf, temp_paf) \
|
||||
LIST_FOREACH_SAFE(paf, &(subgrp->peers), subgrp_train, temp_paf)
|
||||
LIST_FOREACH_SAFE (paf, &(subgrp->peers), subgrp_train, temp_paf)
|
||||
|
||||
#define SUBGRP_FOREACH_ADJ(subgrp, adj) \
|
||||
TAILQ_FOREACH(adj, &(subgrp->adjq), subgrp_adj_train)
|
||||
TAILQ_FOREACH (adj, &(subgrp->adjq), subgrp_adj_train)
|
||||
|
||||
#define SUBGRP_FOREACH_ADJ_SAFE(subgrp, adj, adj_temp) \
|
||||
TAILQ_FOREACH_SAFE(adj, &(subgrp->adjq), subgrp_adj_train, adj_temp)
|
||||
TAILQ_FOREACH_SAFE (adj, &(subgrp->adjq), subgrp_adj_train, adj_temp)
|
||||
|
||||
/* Prototypes. */
|
||||
/* bgp_updgrp.c */
|
||||
|
||||
@ -113,6 +113,14 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
|
||||
peer = UPDGRP_PEER(updgrp);
|
||||
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
|
||||
|
||||
if (BGP_DEBUG(update, UPDATE_OUT)) {
|
||||
char buf_prefix[PREFIX_STRLEN];
|
||||
prefix2str(&ctx->rn->p, buf_prefix, sizeof(buf_prefix));
|
||||
zlog_debug("%s: afi=%s, safi=%s, p=%s", __func__, afi2str(afi),
|
||||
safi2str(safi), buf_prefix);
|
||||
}
|
||||
|
||||
|
||||
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
|
||||
|
||||
/*
|
||||
|
||||
@ -733,8 +733,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
|
||||
space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
|
||||
- BGP_MAX_PACKET_SIZE_OVERFLOW;
|
||||
space_needed = BGP_NLRI_LENGTH + addpath_overhead +
|
||||
bgp_packet_mpattr_prefix_size(afi, safi, &rn->p);
|
||||
space_needed =
|
||||
BGP_NLRI_LENGTH + addpath_overhead
|
||||
+ bgp_packet_mpattr_prefix_size(afi, safi, &rn->p);
|
||||
|
||||
/* When remaining space can't include NLRI and it's length. */
|
||||
if (space_remaining < space_needed)
|
||||
@ -778,9 +779,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
space_remaining =
|
||||
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
|
||||
- BGP_MAX_PACKET_SIZE_OVERFLOW;
|
||||
space_needed = BGP_NLRI_LENGTH + addpath_overhead +
|
||||
bgp_packet_mpattr_prefix_size(afi, safi,
|
||||
&rn->p);
|
||||
space_needed = BGP_NLRI_LENGTH + addpath_overhead
|
||||
+ bgp_packet_mpattr_prefix_size(
|
||||
afi, safi, &rn->p);
|
||||
|
||||
/* If the attributes alone do not leave any room for
|
||||
* NLRI then
|
||||
|
||||
942
bgpd/bgp_vty.c
942
bgpd/bgp_vty.c
File diff suppressed because it is too large
Load Diff
@ -71,4 +71,6 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
|
||||
safi_t *safi, struct bgp **bgp);
|
||||
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
safi_t safi, u_char use_json);
|
||||
extern void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
|
||||
afi_t afi);
|
||||
#endif /* _QUAGGA_BGP_VTY_H */
|
||||
|
||||
147
bgpd/bgp_zebra.c
147
bgpd/bgp_zebra.c
@ -54,6 +54,7 @@
|
||||
#include "bgpd/rfapi/vnc_export_bgp.h"
|
||||
#endif
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
|
||||
/* All information about zebra. */
|
||||
struct zclient *zclient = NULL;
|
||||
@ -987,6 +988,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
struct bgp_info *mpinfo_cp = &local_info;
|
||||
route_tag_t tag;
|
||||
mpls_label_t label;
|
||||
int nh_othervrf = 0;
|
||||
|
||||
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
|
||||
* know of this instance.
|
||||
@ -997,6 +999,12 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
if (bgp->main_zebra_update_hold)
|
||||
return;
|
||||
|
||||
/*
|
||||
* vrf leaking support (will have only one nexthop)
|
||||
*/
|
||||
if (info->extra && info->extra->bgp_orig)
|
||||
nh_othervrf = 1;
|
||||
|
||||
/* Make Zebra API structure. */
|
||||
memset(&api, 0, sizeof(api));
|
||||
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
|
||||
@ -1008,6 +1016,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
|
||||
peer = info->peer;
|
||||
|
||||
if (info->type == ZEBRA_ROUTE_BGP
|
||||
&& info->sub_type == BGP_ROUTE_IMPORTED) {
|
||||
|
||||
struct bgp_info *bi;
|
||||
|
||||
/*
|
||||
* Look at parent chain for peer sort
|
||||
*/
|
||||
for (bi = info; bi->extra && bi->extra->parent;
|
||||
bi = bi->extra->parent) {
|
||||
|
||||
peer = ((struct bgp_info *)(bi->extra->parent))->peer;
|
||||
}
|
||||
}
|
||||
|
||||
tag = info->attr->tag;
|
||||
|
||||
/* When we create an aggregate route we must also install a Null0 route
|
||||
@ -1020,20 +1043,20 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
* Currently presence of rmac in attr denotes
|
||||
* this is an EVPN type-2 route
|
||||
*/
|
||||
if (!is_zero_mac(&(info->attr->rmac)))
|
||||
if (info->sub_type == BGP_ROUTE_IMPORTED)
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
|
||||
|
||||
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|
||||
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
}
|
||||
|
||||
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|
||||
|| bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
|
||||
/* Metric is currently based on the best-path only */
|
||||
metric = info->attr->med;
|
||||
@ -1054,15 +1077,44 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
else
|
||||
continue;
|
||||
|
||||
api_nh = &api.nexthops[valid_nh_count];
|
||||
api_nh->vrf_id = nh_othervrf ? info->extra->bgp_orig->vrf_id
|
||||
: bgp->vrf_id;
|
||||
if (nh_family == AF_INET) {
|
||||
struct in_addr *nexthop;
|
||||
|
||||
if (bgp->table_map[afi][safi].name) {
|
||||
if (bgp_debug_zebra(&api.prefix)) {
|
||||
char buf_prefix[PREFIX_STRLEN];
|
||||
prefix2str(&api.prefix, buf_prefix,
|
||||
sizeof(buf_prefix));
|
||||
if (mpinfo->extra) {
|
||||
zlog_debug(
|
||||
"%s: p=%s, bgp_is_valid_label: %d",
|
||||
__func__, buf_prefix,
|
||||
bgp_is_valid_label(
|
||||
&mpinfo->extra
|
||||
->label[0]));
|
||||
} else {
|
||||
zlog_debug(
|
||||
"%s: p=%s, extra is NULL, no label",
|
||||
__func__, buf_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (bgp->table_map[afi][safi].name || nh_othervrf) {
|
||||
/* Copy info and attributes, so the route-map
|
||||
apply doesn't modify the BGP route info. */
|
||||
local_attr = *mpinfo->attr;
|
||||
mpinfo_cp->attr = &local_attr;
|
||||
if (nh_othervrf) {
|
||||
/* allow route-map to modify */
|
||||
local_attr.nexthop =
|
||||
info->extra->nexthop_orig.u
|
||||
.prefix4;
|
||||
}
|
||||
}
|
||||
|
||||
if (bgp->table_map[afi][safi].name) {
|
||||
if (!bgp_table_map_apply(
|
||||
bgp->table_map[afi][safi].map, p,
|
||||
mpinfo_cp))
|
||||
@ -1077,10 +1129,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
}
|
||||
|
||||
nexthop = &mpinfo_cp->attr->nexthop;
|
||||
|
||||
api_nh = &api.nexthops[valid_nh_count];
|
||||
api_nh->gate.ipv4 = *nexthop;
|
||||
api_nh->vrf_id = bgp->vrf_id;
|
||||
|
||||
/* EVPN type-2 routes are
|
||||
programmed as onlink on l3-vni SVI
|
||||
*/
|
||||
@ -1094,6 +1144,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
|
||||
ifindex = 0;
|
||||
|
||||
if (bgp->table_map[afi][safi].name || nh_othervrf) {
|
||||
/* Copy info and attributes, so the route-map
|
||||
apply doesn't modify the BGP route info. */
|
||||
local_attr = *mpinfo->attr;
|
||||
mpinfo_cp->attr = &local_attr;
|
||||
if (nh_othervrf) {
|
||||
/* allow route-map to modify */
|
||||
local_attr.mp_nexthop_global =
|
||||
info->extra->nexthop_orig.u
|
||||
.prefix6;
|
||||
local_attr.mp_nexthop_len =
|
||||
BGP_ATTR_NHLEN_IPV6_GLOBAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (bgp->table_map[afi][safi].name) {
|
||||
/* Copy info and attributes, so the route-map
|
||||
apply doesn't modify the BGP route info. */
|
||||
@ -1135,7 +1200,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
if (ifindex == 0)
|
||||
continue;
|
||||
|
||||
api_nh = &api.nexthops[valid_nh_count];
|
||||
api_nh->gate.ipv6 = *nexthop;
|
||||
api_nh->ifindex = ifindex;
|
||||
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
@ -1229,14 +1293,18 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
|
||||
for (ri = rn->info; ri; ri = ri->next)
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)
|
||||
&& ri->type == ZEBRA_ROUTE_BGP
|
||||
&& ri->sub_type == BGP_ROUTE_NORMAL)
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
|
||||
|
||||
(ri->type == ZEBRA_ROUTE_BGP
|
||||
&& (ri->sub_type == BGP_ROUTE_NORMAL
|
||||
|| ri->sub_type == BGP_ROUTE_IMPORTED)))
|
||||
|
||||
bgp_zebra_announce(rn, &rn->p, ri, bgp, afi,
|
||||
safi);
|
||||
}
|
||||
|
||||
void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info,
|
||||
struct bgp *bgp, safi_t safi)
|
||||
{
|
||||
struct zapi_route api;
|
||||
struct peer *peer;
|
||||
@ -1244,15 +1312,30 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
peer = info->peer;
|
||||
assert(peer);
|
||||
|
||||
if (info->type == ZEBRA_ROUTE_BGP
|
||||
&& info->sub_type == BGP_ROUTE_IMPORTED) {
|
||||
|
||||
struct bgp_info *bi;
|
||||
|
||||
/*
|
||||
* Look at parent chain for peer sort
|
||||
*/
|
||||
for (bi = info; bi->extra && bi->extra->parent;
|
||||
bi = bi->extra->parent) {
|
||||
|
||||
peer = ((struct bgp_info *)(bi->extra->parent))->peer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
|
||||
* know of this instance.
|
||||
*/
|
||||
if (!bgp_install_info_to_zebra(peer->bgp))
|
||||
if (!bgp_install_info_to_zebra(bgp))
|
||||
return;
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
|
||||
api.vrf_id = peer->bgp->vrf_id;
|
||||
api.vrf_id = bgp->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.safi = safi;
|
||||
api.prefix = *p;
|
||||
@ -1261,24 +1344,24 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
* Currently presence of rmac in attr denotes
|
||||
* this is an EVPN type-2 route
|
||||
*/
|
||||
if (!is_zero_mac(&(info->attr->rmac)))
|
||||
if (info->sub_type == BGP_ROUTE_IMPORTED)
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
|
||||
|
||||
if (peer->sort == BGP_PEER_IBGP) {
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
|
||||
}
|
||||
|
||||
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|
||||
|| bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
|| bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
|
||||
if (bgp_debug_zebra(p)) {
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(&api.prefix, buf, sizeof(buf));
|
||||
zlog_debug("Tx route delete VRF %u %s", peer->bgp->vrf_id, buf);
|
||||
zlog_debug("Tx route delete VRF %u %s", bgp->vrf_id, buf);
|
||||
}
|
||||
|
||||
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
|
||||
@ -1484,11 +1567,6 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
|
||||
vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
|
||||
}
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
|
||||
vnc_export_bgp_disable(bgp, afi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bgp_install_info_to_zebra(bgp)) {
|
||||
/* Send distribute delete message to zebra. */
|
||||
@ -1512,6 +1590,17 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
|
||||
{
|
||||
struct bgp_redist *red;
|
||||
|
||||
/*
|
||||
* vnc and vpn->vrf checks must be before red check because
|
||||
* they operate within bgpd irrespective of zebra connection
|
||||
* status. red lookup fails if there is no zebra connection.
|
||||
*/
|
||||
#if ENABLE_BGP_VNC
|
||||
if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
|
||||
vnc_export_bgp_disable(bgp, afi);
|
||||
}
|
||||
#endif
|
||||
|
||||
red = bgp_redist_lookup(bgp, afi, type, instance);
|
||||
if (!red)
|
||||
return CMD_SUCCESS;
|
||||
@ -1726,6 +1815,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
|
||||
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
int filter = 0;
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
vni_t l3vni = 0;
|
||||
struct ethaddr rmac;
|
||||
@ -1739,16 +1829,19 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
|
||||
if (cmd == ZEBRA_L3VNI_ADD) {
|
||||
stream_get(&rmac, s, sizeof(struct ethaddr));
|
||||
originator_ip.s_addr = stream_get_ipv4(s);
|
||||
stream_get(&filter, s, sizeof(int));
|
||||
}
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s",
|
||||
zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s",
|
||||
(cmd == ZEBRA_L3VNI_ADD) ? "add" : "del",
|
||||
vrf_id_to_name(vrf_id), l3vni,
|
||||
prefix_mac2str(&rmac, buf, sizeof(buf)));
|
||||
prefix_mac2str(&rmac, buf, sizeof(buf)),
|
||||
filter ? "prefix-routes-only" : "none");
|
||||
|
||||
if (cmd == ZEBRA_L3VNI_ADD)
|
||||
bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip);
|
||||
bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip,
|
||||
filter);
|
||||
else
|
||||
bgp_evpn_local_l3vni_del(l3vni, vrf_id);
|
||||
|
||||
|
||||
@ -33,7 +33,8 @@ extern void bgp_config_write_redistribute(struct vty *, struct bgp *, afi_t,
|
||||
extern void bgp_zebra_announce(struct bgp_node *, struct prefix *,
|
||||
struct bgp_info *, struct bgp *, afi_t, safi_t);
|
||||
extern void bgp_zebra_announce_table(struct bgp *, afi_t, safi_t);
|
||||
extern void bgp_zebra_withdraw(struct prefix *, struct bgp_info *, safi_t);
|
||||
extern void bgp_zebra_withdraw(struct prefix *, struct bgp_info *,
|
||||
struct bgp *, safi_t);
|
||||
|
||||
extern void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer);
|
||||
extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
|
||||
|
||||
212
bgpd/bgpd.c
212
bgpd/bgpd.c
@ -101,6 +101,43 @@ static void bgp_if_finish(struct bgp *bgp);
|
||||
|
||||
extern struct zclient *zclient;
|
||||
|
||||
/* handle main socket creation or deletion */
|
||||
static int bgp_check_main_socket(bool create, struct bgp *bgp)
|
||||
{
|
||||
static int bgp_server_main_created;
|
||||
struct listnode *bgpnode, *nbgpnode;
|
||||
struct bgp *bgp_temp;
|
||||
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF &&
|
||||
vrf_is_mapped_on_netns(bgp->vrf_id))
|
||||
return 0;
|
||||
if (create == true) {
|
||||
if (bgp_server_main_created)
|
||||
return 0;
|
||||
if (bgp_socket(bgp, bm->port, bm->address) < 0)
|
||||
return BGP_ERR_INVALID_VALUE;
|
||||
bgp_server_main_created = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!bgp_server_main_created)
|
||||
return 0;
|
||||
/* only delete socket on some cases */
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp_temp)) {
|
||||
/* do not count with current bgp */
|
||||
if (bgp_temp == bgp)
|
||||
continue;
|
||||
/* if other instance non VRF, do not delete socket */
|
||||
if (bgp_temp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||
return 0;
|
||||
/* vrf lite, do not delete socket */
|
||||
if (!vrf_is_mapped_on_netns(bgp_temp->vrf_id))
|
||||
return 0;
|
||||
}
|
||||
bgp_close();
|
||||
bgp_server_main_created = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bgp_session_reset(struct peer *peer)
|
||||
{
|
||||
if (peer->doppelganger && (peer->doppelganger->status != Deleted)
|
||||
@ -1042,10 +1079,8 @@ static void peer_free(struct peer *peer)
|
||||
XFREE(MTYPE_TMP, peer->notify.data);
|
||||
memset(&peer->notify, 0, sizeof(struct bgp_notify));
|
||||
|
||||
if (peer->clear_node_queue) {
|
||||
work_queue_free(peer->clear_node_queue);
|
||||
peer->clear_node_queue = NULL;
|
||||
}
|
||||
if (peer->clear_node_queue)
|
||||
work_queue_free_and_null(&peer->clear_node_queue);
|
||||
|
||||
bgp_sync_delete(peer);
|
||||
|
||||
@ -1200,7 +1235,6 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
|
||||
peer_dst->config = peer_src->config;
|
||||
|
||||
peer_dst->local_as = peer_src->local_as;
|
||||
peer_dst->ifindex = peer_src->ifindex;
|
||||
peer_dst->port = peer_src->port;
|
||||
(void)peer_sort(peer_dst);
|
||||
peer_dst->rmap_type = peer_src->rmap_type;
|
||||
@ -2829,6 +2863,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
|
||||
}
|
||||
|
||||
bgp_lock(bgp);
|
||||
bgp->heuristic_coalesce = true;
|
||||
bgp->inst_type = inst_type;
|
||||
bgp->vrf_id = (inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT
|
||||
: VRF_UNKNOWN;
|
||||
@ -2907,6 +2942,11 @@ static struct bgp *bgp_create(as_t *as, const char *name,
|
||||
}
|
||||
#endif /* ENABLE_BGP_VNC */
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
|
||||
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent =
|
||||
MPLS_LABEL_NONE;
|
||||
}
|
||||
if (name) {
|
||||
bgp->name = XSTRDUP(MTYPE_BGP, name);
|
||||
} else {
|
||||
@ -2981,11 +3021,65 @@ struct bgp *bgp_lookup_by_vrf_id(vrf_id_t vrf_id)
|
||||
return (vrf->info) ? (struct bgp *)vrf->info : NULL;
|
||||
}
|
||||
|
||||
/* handle socket creation or deletion, if necessary
|
||||
* this is called for all new BGP instances
|
||||
*/
|
||||
int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
|
||||
bool create)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Create BGP server socket, if listen mode not disabled */
|
||||
if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN))
|
||||
return 0;
|
||||
if (bgp->name && bgp->inst_type == BGP_INSTANCE_TYPE_VRF && vrf) {
|
||||
/*
|
||||
* suppress vrf socket
|
||||
*/
|
||||
if (create == FALSE) {
|
||||
if (vrf_is_mapped_on_netns(vrf->vrf_id))
|
||||
bgp_close_vrf_socket(bgp);
|
||||
else
|
||||
ret = bgp_check_main_socket(create, bgp);
|
||||
return ret;
|
||||
}
|
||||
/* do nothing
|
||||
* if vrf_id did not change
|
||||
*/
|
||||
if (vrf->vrf_id == old_vrf_id)
|
||||
return 0;
|
||||
if (old_vrf_id != VRF_UNKNOWN) {
|
||||
/* look for old socket. close it. */
|
||||
bgp_close_vrf_socket(bgp);
|
||||
}
|
||||
/* if backend is not yet identified ( VRF_UNKNOWN) then
|
||||
* creation will be done later
|
||||
*/
|
||||
if (vrf->vrf_id == VRF_UNKNOWN)
|
||||
return 0;
|
||||
/* if BGP VRF instance requested
|
||||
* if backend is NETNS, create BGP server socket in the NETNS
|
||||
*/
|
||||
if (vrf_is_mapped_on_netns(bgp->vrf_id)) {
|
||||
ret = bgp_socket(bgp, bm->port, bm->address);
|
||||
if (ret < 0)
|
||||
return BGP_ERR_INVALID_VALUE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* if BGP VRF instance requested or VRF lite backend
|
||||
* if BGP non VRF instance, create it
|
||||
* if not already done
|
||||
*/
|
||||
return bgp_check_main_socket(create, bgp);
|
||||
}
|
||||
|
||||
/* Called from VTY commands. */
|
||||
int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
|
||||
enum bgp_instance_type inst_type)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
struct vrf *vrf = NULL;
|
||||
|
||||
/* Multiple instance check. */
|
||||
if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
|
||||
@ -3033,25 +3127,19 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
|
||||
|
||||
bgp->t_rmap_def_originate_eval = NULL;
|
||||
|
||||
/* Create BGP server socket, if first instance. */
|
||||
if (list_isempty(bm->bgp) && !bgp_option_check(BGP_OPT_NO_LISTEN)) {
|
||||
if (bgp_socket(bm->port, bm->address) < 0)
|
||||
return BGP_ERR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
listnode_add(bm->bgp, bgp);
|
||||
|
||||
/* If Default instance or VRF, link to the VRF structure, if present. */
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
|
||||
|| bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
|
||||
struct vrf *vrf;
|
||||
|
||||
vrf = bgp_vrf_lookup_by_instance_type(bgp);
|
||||
if (vrf)
|
||||
bgp_vrf_link(bgp, vrf);
|
||||
}
|
||||
/* BGP server socket already processed if BGP instance
|
||||
* already part of the list
|
||||
*/
|
||||
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, true);
|
||||
listnode_add(bm->bgp, bgp);
|
||||
|
||||
/* Register with Zebra, if needed */
|
||||
if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
|
||||
bgp_zebra_instance_register(bgp);
|
||||
|
||||
@ -3188,8 +3276,6 @@ int bgp_delete(struct bgp *bgp)
|
||||
* routes to be processed still referencing the struct bgp.
|
||||
*/
|
||||
listnode_delete(bm->bgp, bgp);
|
||||
if (list_isempty(bm->bgp))
|
||||
bgp_close();
|
||||
|
||||
/* Deregister from Zebra, if needed */
|
||||
if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
|
||||
@ -3199,6 +3285,7 @@ int bgp_delete(struct bgp *bgp)
|
||||
bgp_if_finish(bgp);
|
||||
|
||||
vrf = bgp_vrf_lookup_by_instance_type(bgp);
|
||||
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false);
|
||||
if (vrf)
|
||||
bgp_vrf_unlink(bgp, vrf);
|
||||
|
||||
@ -3337,11 +3424,12 @@ struct peer *peer_lookup(struct bgp *bgp, union sockunion *su)
|
||||
struct listnode *bgpnode, *nbgpnode;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp)) {
|
||||
/* Skip VRFs, this function will not be invoked without
|
||||
* an instance
|
||||
/* Skip VRFs Lite only, this function will not be
|
||||
* invoked without an instance
|
||||
* when examining VRFs.
|
||||
*/
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|
||||
&& !vrf_is_mapped_on_netns(bgp->vrf_id))
|
||||
continue;
|
||||
|
||||
peer = hash_lookup(bgp->peerhash, &tmp_peer);
|
||||
@ -3985,9 +4073,8 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
|
||||
}
|
||||
|
||||
/* Track if addpath TX is in use */
|
||||
if (flag
|
||||
& (PEER_FLAG_ADDPATH_TX_ALL_PATHS
|
||||
| PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
|
||||
if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS
|
||||
| PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
|
||||
bgp = peer->bgp;
|
||||
addpath_tx_used = 0;
|
||||
|
||||
@ -6800,9 +6887,8 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
|
||||
} else {
|
||||
if (!peer_af_flag_check(peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY)
|
||||
&& (!g_peer
|
||||
|| peer_af_flag_check(g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY))
|
||||
&& (!g_peer || peer_af_flag_check(g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY))
|
||||
&& !peer_af_flag_check(peer, afi, safi,
|
||||
PEER_FLAG_SEND_EXT_COMMUNITY)
|
||||
&& (!g_peer
|
||||
@ -6810,10 +6896,9 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
|
||||
PEER_FLAG_SEND_EXT_COMMUNITY))
|
||||
&& !peer_af_flag_check(peer, afi, safi,
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY)
|
||||
&& (!g_peer
|
||||
|| peer_af_flag_check(
|
||||
g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY))) {
|
||||
&& (!g_peer || peer_af_flag_check(
|
||||
g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY))) {
|
||||
vty_out(vty, " no neighbor %s send-community all\n",
|
||||
addr);
|
||||
} else {
|
||||
@ -6841,10 +6926,9 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
|
||||
|
||||
if (!peer_af_flag_check(peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY)
|
||||
&& (!g_peer
|
||||
|| peer_af_flag_check(
|
||||
g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY))) {
|
||||
&& (!g_peer || peer_af_flag_check(
|
||||
g_peer, afi, safi,
|
||||
PEER_FLAG_SEND_COMMUNITY))) {
|
||||
vty_out(vty,
|
||||
" no neighbor %s send-community\n",
|
||||
addr);
|
||||
@ -7049,6 +7133,20 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
if (safi == SAFI_EVPN)
|
||||
bgp_config_write_evpn_info(vty, bgp, afi, safi);
|
||||
|
||||
if (safi == SAFI_UNICAST) {
|
||||
bgp_vpn_policy_config_write_afi(vty, bgp, afi);
|
||||
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||
BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
|
||||
|
||||
vty_out(vty, " export vpn\n");
|
||||
}
|
||||
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||
BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) {
|
||||
|
||||
vty_out(vty, " import vpn\n");
|
||||
}
|
||||
}
|
||||
|
||||
vty_endframe(vty, " exit-address-family\n");
|
||||
}
|
||||
|
||||
@ -7315,38 +7413,6 @@ int bgp_config_write(struct vty *vty)
|
||||
if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
|
||||
vty_out(vty, " no auto-summary\n");
|
||||
|
||||
/* import route-target */
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
|
||||
ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(
|
||||
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
vty_out(vty, " route-target import %s\n",
|
||||
ecom_str);
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* export route-target */
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
|
||||
ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(
|
||||
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
vty_out(vty, " route-target export %s\n",
|
||||
ecom_str);
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv4 unicast configuration. */
|
||||
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
|
||||
|
||||
@ -7475,16 +7541,14 @@ static void bgp_pthreads_init()
|
||||
.id = PTHREAD_IO,
|
||||
.start = frr_pthread_attr_default.start,
|
||||
.stop = frr_pthread_attr_default.stop,
|
||||
.name = "BGP I/O thread",
|
||||
};
|
||||
struct frr_pthread_attr ka = {
|
||||
.id = PTHREAD_KEEPALIVES,
|
||||
.start = bgp_keepalives_start,
|
||||
.stop = bgp_keepalives_stop,
|
||||
.name = "BGP Keepalives thread",
|
||||
};
|
||||
frr_pthread_new(&io);
|
||||
frr_pthread_new(&ka);
|
||||
frr_pthread_new(&io, "BGP I/O thread");
|
||||
frr_pthread_new(&ka, "BGP Keepalives thread");
|
||||
}
|
||||
|
||||
void bgp_pthreads_run()
|
||||
@ -7591,10 +7655,8 @@ void bgp_terminate(void)
|
||||
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
|
||||
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
|
||||
|
||||
if (bm->process_main_queue) {
|
||||
work_queue_free(bm->process_main_queue);
|
||||
bm->process_main_queue = NULL;
|
||||
}
|
||||
if (bm->process_main_queue)
|
||||
work_queue_free_and_null(&bm->process_main_queue);
|
||||
|
||||
if (bm->t_rmap_update)
|
||||
BGP_TIMER_OFF(bm->t_rmap_update);
|
||||
|
||||
63
bgpd/bgpd.h
63
bgpd/bgpd.h
@ -133,8 +133,6 @@ struct bgp_master {
|
||||
/* timer to dampen route map changes */
|
||||
struct thread *t_rmap_update; /* Handle route map updates */
|
||||
u_int32_t rmap_update_timer; /* Route map update timer */
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
|
||||
|
||||
/* Id space for automatic RD derivation for an EVI/VRF */
|
||||
@ -161,6 +159,12 @@ struct bgp_redist {
|
||||
struct bgp_rmap rmap;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
BGP_VPN_POLICY_DIR_FROMVPN = 0,
|
||||
BGP_VPN_POLICY_DIR_TOVPN = 1,
|
||||
BGP_VPN_POLICY_DIR_MAX = 2
|
||||
} vpn_policy_direction_t;
|
||||
|
||||
/*
|
||||
* Type of 'struct bgp'.
|
||||
* - Default: The default instance
|
||||
@ -249,8 +253,6 @@ struct bgp {
|
||||
*t_startup; /* start-up timer on only once at the beginning */
|
||||
|
||||
u_int32_t v_maxmed_onstartup; /* Duration of max-med on start-up */
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define BGP_MAXMED_ONSTARTUP_UNCONFIGURED 0 /* 0 means off, its the default */
|
||||
u_int32_t maxmed_onstartup_value; /* Max-med value when active on
|
||||
start-up */
|
||||
@ -259,17 +261,13 @@ struct bgp {
|
||||
u_char maxmed_onstartup_over; /* Flag to make it effective only once */
|
||||
|
||||
u_char v_maxmed_admin; /* 1/0 if max-med administrative is on/off */
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define BGP_MAXMED_ADMIN_UNCONFIGURED 0 /* Off by default */
|
||||
u_int32_t maxmed_admin_value; /* Max-med value when administrative in on
|
||||
*/
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define BGP_MAXMED_VALUE_DEFAULT 4294967294 /* Maximum by default */
|
||||
|
||||
u_char maxmed_active; /* 1/0 if max-med is active or not */
|
||||
u_int32_t maxmed_value; /* Max-med value when its active */
|
||||
u_char maxmed_active; /* 1/0 if max-med is active or not */
|
||||
u_int32_t maxmed_value; /* Max-med value when its active */
|
||||
|
||||
/* BGP update delay on startup */
|
||||
struct thread *t_update_delay;
|
||||
@ -319,6 +317,15 @@ struct bgp {
|
||||
/* BGP Per AF flags */
|
||||
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
|
||||
#define BGP_CONFIG_DAMPENING (1 << 0)
|
||||
#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
|
||||
#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 2)
|
||||
|
||||
/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
|
||||
#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
|
||||
#define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST (1 << 2)
|
||||
#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 3)
|
||||
#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 4)
|
||||
|
||||
|
||||
/* Route table for next-hop lookup cache. */
|
||||
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
||||
@ -431,11 +438,11 @@ struct bgp {
|
||||
/* vrf flags */
|
||||
uint32_t vrf_flags;
|
||||
#define BGP_VRF_AUTO (1 << 0)
|
||||
#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN (1 << 1)
|
||||
#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN (1 << 2)
|
||||
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
|
||||
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
|
||||
#define BGP_VRF_RD_CFGD (1 << 5)
|
||||
#define BGP_VRF_IMPORT_RT_CFGD (1 << 1)
|
||||
#define BGP_VRF_EXPORT_RT_CFGD (1 << 2)
|
||||
#define BGP_VRF_RD_CFGD (1 << 3)
|
||||
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
|
||||
|
||||
|
||||
/* unique ID for auto derivation of RD for this vrf */
|
||||
uint16_t vrf_rd_id;
|
||||
@ -455,6 +462,22 @@ struct bgp {
|
||||
/* route map for advertise ipv4/ipv6 unicast (type-5 routes) */
|
||||
struct bgp_rmap adv_cmd_rmap[AFI_MAX][SAFI_MAX];
|
||||
|
||||
/* vpn-policy */
|
||||
struct {
|
||||
struct ecommunity *rtlist[BGP_VPN_POLICY_DIR_MAX];
|
||||
char *rmap_name[BGP_VPN_POLICY_DIR_MAX];
|
||||
struct route_map *rmap[BGP_VPN_POLICY_DIR_MAX];
|
||||
|
||||
/* should be mpls_label_t? */
|
||||
uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
|
||||
uint32_t tovpn_zebra_vrf_label_last_sent;
|
||||
struct prefix_rd tovpn_rd;
|
||||
struct prefix tovpn_nexthop; /* unset => set to 0 */
|
||||
uint32_t flags;
|
||||
#define BGP_VPN_POLICY_TOVPN_RD_SET 0x00000004
|
||||
#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET 0x00000008
|
||||
} vpn_policy[AFI_MAX];
|
||||
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(bgp)
|
||||
@ -679,14 +702,11 @@ struct peer {
|
||||
unsigned short port; /* Destination port for peer */
|
||||
char *host; /* Printable address of the peer. */
|
||||
union sockunion su; /* Sockunion address of the peer. */
|
||||
/* $FRR indent$ */
|
||||
/* clang-format off */
|
||||
#define BGP_PEER_SU_UNSPEC(peer) (peer->su.sa.sa_family == AF_UNSPEC)
|
||||
time_t uptime; /* Last Up/Down time */
|
||||
time_t readtime; /* Last read time */
|
||||
time_t resettime; /* Last reset time */
|
||||
|
||||
ifindex_t ifindex; /* ifindex of the BGP connection. */
|
||||
char *conf_if; /* neighbor interface config name. */
|
||||
struct interface *ifp; /* corresponding interface */
|
||||
char *ifname; /* bind interface name. */
|
||||
@ -898,8 +918,8 @@ struct peer {
|
||||
memory_order_relaxed)
|
||||
|
||||
/* Statistics field */
|
||||
_Atomic uint32_t open_in; /* Open message input count */
|
||||
_Atomic uint32_t open_out; /* Open message output count */
|
||||
_Atomic uint32_t open_in; /* Open message input count */
|
||||
_Atomic uint32_t open_out; /* Open message output count */
|
||||
_Atomic uint32_t update_in; /* Update message input count */
|
||||
_Atomic uint32_t update_out; /* Update message ouput count */
|
||||
_Atomic time_t update_time; /* Update message received time. */
|
||||
@ -1354,6 +1374,9 @@ extern void bgp_instance_up(struct bgp *);
|
||||
extern void bgp_instance_down(struct bgp *);
|
||||
extern int bgp_delete(struct bgp *);
|
||||
|
||||
extern int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf,
|
||||
vrf_id_t old_vrf_id, bool create);
|
||||
|
||||
extern int bgp_flag_set(struct bgp *, int);
|
||||
extern int bgp_flag_unset(struct bgp *, int);
|
||||
extern int bgp_flag_check(struct bgp *, int);
|
||||
|
||||
@ -1636,9 +1636,8 @@ DEFUN (vnc_nve_group_export_no_prefixlist,
|
||||
idx += 2; /* skip afi and keyword */
|
||||
|
||||
if (is_bgp) {
|
||||
if (idx == argc
|
||||
|| strmatch(argv[idx]->arg,
|
||||
rfg->plist_export_bgp_name[afi])) {
|
||||
if (idx == argc || strmatch(argv[idx]->arg,
|
||||
rfg->plist_export_bgp_name[afi])) {
|
||||
if (rfg->plist_export_bgp_name[afi])
|
||||
free(rfg->plist_export_bgp_name[afi]);
|
||||
rfg->plist_export_bgp_name[afi] = NULL;
|
||||
@ -1768,9 +1767,8 @@ DEFUN (vnc_nve_group_export_no_routemap,
|
||||
}
|
||||
|
||||
if (is_bgp) {
|
||||
if (idx == argc
|
||||
|| strmatch(argv[idx]->arg,
|
||||
rfg->routemap_export_bgp_name)) {
|
||||
if (idx == argc || strmatch(argv[idx]->arg,
|
||||
rfg->routemap_export_bgp_name)) {
|
||||
if (rfg->routemap_export_bgp_name)
|
||||
free(rfg->routemap_export_bgp_name);
|
||||
rfg->routemap_export_bgp_name = NULL;
|
||||
@ -1780,9 +1778,8 @@ DEFUN (vnc_nve_group_export_no_routemap,
|
||||
vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6);
|
||||
}
|
||||
} else {
|
||||
if (idx == argc
|
||||
|| strmatch(argv[idx]->arg,
|
||||
rfg->routemap_export_zebra_name)) {
|
||||
if (idx == argc || strmatch(argv[idx]->arg,
|
||||
rfg->routemap_export_zebra_name)) {
|
||||
if (rfg->routemap_export_zebra_name)
|
||||
free(rfg->routemap_export_zebra_name);
|
||||
rfg->routemap_export_zebra_name = NULL;
|
||||
@ -2185,6 +2182,7 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
|
||||
vnc_zlog_debug_verbose("%s done", __func__);
|
||||
}
|
||||
|
||||
#if 0 /* superseded */
|
||||
static void vnc_routemap_event(route_map_event_t type, /* ignored */
|
||||
const char *rmap_name) /* ignored */
|
||||
{
|
||||
@ -2200,6 +2198,7 @@ static void vnc_routemap_event(route_map_event_t type, /* ignored */
|
||||
|
||||
vnc_zlog_debug_verbose("%s: done", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* nve-group
|
||||
@ -2978,7 +2977,8 @@ DEFUN_NOSH (vnc_vrf_policy,
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
|
||||
vty_out(vty, "Can't configure vrf-policy within a BGP VRF instance\n");
|
||||
vty_out(vty,
|
||||
"Can't configure vrf-policy within a BGP VRF instance\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
@ -3675,7 +3675,8 @@ bgp_rfapi_get_ecommunity_by_lni_label(struct bgp *bgp, uint32_t is_import,
|
||||
void bgp_rfapi_cfg_init(void)
|
||||
{
|
||||
/* main bgpd code does not use this hook, but vnc does */
|
||||
route_map_event_hook(vnc_routemap_event);
|
||||
/* superseded by bgp_route_map_process_update_cb() */
|
||||
/* bgp_route_map_event_hook_add(vnc_routemap_event); */
|
||||
|
||||
install_node(&bgp_vnc_defaults_node, NULL);
|
||||
install_node(&bgp_vnc_nve_group_node, NULL);
|
||||
|
||||
@ -383,9 +383,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
|
||||
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: peer=%p, prefix=%s, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
|
||||
__func__, peer, buf,
|
||||
prefix_rd2str(prd, buf2, sizeof(buf2)), afi, safi, bn,
|
||||
(bn ? bn->info : NULL));
|
||||
__func__, peer, buf, prefix_rd2str(prd, buf2, sizeof(buf2)),
|
||||
afi, safi, bn, (bn ? bn->info : NULL));
|
||||
|
||||
for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
|
||||
|
||||
@ -749,9 +748,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
|
||||
if (lifetime && *lifetime != RFAPI_INFINITE_LIFETIME) {
|
||||
uint32_t lt;
|
||||
|
||||
encaptlv =
|
||||
XCALLOC(MTYPE_ENCAP_TLV,
|
||||
sizeof(struct bgp_attr_encap_subtlv) + 4);
|
||||
encaptlv = XCALLOC(MTYPE_ENCAP_TLV,
|
||||
sizeof(struct bgp_attr_encap_subtlv) + 4);
|
||||
assert(encaptlv);
|
||||
encaptlv->type =
|
||||
BGP_VNC_SUBTLV_TYPE_LIFETIME; /* prefix lifetime */
|
||||
@ -795,8 +793,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
|
||||
*/
|
||||
encaptlv = XCALLOC(
|
||||
MTYPE_ENCAP_TLV,
|
||||
sizeof(struct bgp_attr_encap_subtlv)
|
||||
+ 2 + hop->length);
|
||||
sizeof(struct bgp_attr_encap_subtlv) + 2
|
||||
+ hop->length);
|
||||
assert(encaptlv);
|
||||
encaptlv->type =
|
||||
BGP_VNC_SUBTLV_TYPE_RFPOPTION; /* RFP
|
||||
|
||||
@ -1083,9 +1083,8 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
|
||||
} else if (encode == ECOMMUNITY_ENCODE_AS) {
|
||||
as = (*p++ << 8);
|
||||
as |= (*p++);
|
||||
p +=
|
||||
2; /* skip next two, tag/vid
|
||||
always in lowest bytes */
|
||||
p += 2; /* skip next two, tag/vid
|
||||
always in lowest bytes */
|
||||
}
|
||||
if (as == bgp->as) {
|
||||
*tag_id = *p++ << 8;
|
||||
@ -1221,8 +1220,7 @@ static int rfapiVpnBiSamePtUn(struct bgp_info *bi1, struct bgp_info *bi2)
|
||||
|
||||
switch (pfx_un1.family) {
|
||||
case AF_INET:
|
||||
if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4,
|
||||
&pfx_un2.u.prefix4))
|
||||
if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4, &pfx_un2.u.prefix4))
|
||||
return 0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
@ -2235,9 +2233,9 @@ static struct bgp_info *rfapiItBiIndexSearch(
|
||||
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: bi has prd=%s, peer=%p", __func__,
|
||||
prefix_rd2str(&bi_result->extra->vnc.import.rd,
|
||||
buf,
|
||||
sizeof(buf)),
|
||||
prefix_rd2str(&bi_result->extra->vnc
|
||||
.import.rd,
|
||||
buf, sizeof(buf)),
|
||||
bi_result->peer);
|
||||
}
|
||||
#endif
|
||||
@ -4338,7 +4336,7 @@ void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h)
|
||||
h->import_mac = NULL;
|
||||
}
|
||||
|
||||
work_queue_free(h->deferred_close_q);
|
||||
work_queue_free_and_null(&h->deferred_close_q);
|
||||
|
||||
if (h->rfp != NULL)
|
||||
rfp_stop(h->rfp);
|
||||
|
||||
@ -929,17 +929,14 @@ void rfapiMonitorItNodeChanged(
|
||||
char buf_attach_pfx[PREFIX_STRLEN];
|
||||
char buf_target_pfx[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(&m->node->p,
|
||||
buf_attach_pfx,
|
||||
prefix2str(&m->node->p, buf_attach_pfx,
|
||||
sizeof(buf_attach_pfx));
|
||||
prefix2str(&m->p,
|
||||
buf_target_pfx,
|
||||
prefix2str(&m->p, buf_target_pfx,
|
||||
sizeof(buf_target_pfx));
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: update rfd %p attached to pfx %s (targ=%s)",
|
||||
__func__, m->rfd,
|
||||
buf_attach_pfx,
|
||||
buf_target_pfx);
|
||||
buf_attach_pfx, buf_target_pfx);
|
||||
|
||||
/*
|
||||
* update its RIB
|
||||
|
||||
@ -345,7 +345,8 @@ extern void rfapi_un_options_free(struct rfapi_un_option *goner);
|
||||
|
||||
extern void rfapi_vn_options_free(struct rfapi_vn_option *goner);
|
||||
|
||||
extern void vnc_add_vrf_opener(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg);
|
||||
extern void vnc_add_vrf_opener(struct bgp *bgp,
|
||||
struct rfapi_nve_group_cfg *rfg);
|
||||
extern void clear_vnc_vrf_closer(struct rfapi_nve_group_cfg *rfg);
|
||||
/*------------------------------------------
|
||||
* rfapi_extract_l2o
|
||||
|
||||
@ -511,7 +511,8 @@ void rfapiRibClear(struct rfapi_descriptor *rfd)
|
||||
if (pn->info) {
|
||||
if (pn->info != (void *)1) {
|
||||
list_delete_and_null(
|
||||
(struct list **)(&pn->info));
|
||||
(struct list *
|
||||
*)(&pn->info));
|
||||
}
|
||||
pn->info = NULL;
|
||||
/* linklist or 1 deleted */
|
||||
@ -570,10 +571,8 @@ void rfapiRibClear(struct rfapi_descriptor *rfd)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rfd->updated_responses_queue) {
|
||||
work_queue_free(rfd->updated_responses_queue);
|
||||
rfd->updated_responses_queue = NULL;
|
||||
}
|
||||
if (rfd->updated_responses_queue)
|
||||
work_queue_free_and_null(&rfd->updated_responses_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1407,9 +1406,10 @@ callback:
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: move route to recently deleted list, rd=%s",
|
||||
__func__,
|
||||
prefix_rd2str(&ri->rk.rd,
|
||||
buf_rd,
|
||||
sizeof(buf_rd)));
|
||||
prefix_rd2str(
|
||||
&ri->rk.rd,
|
||||
buf_rd,
|
||||
sizeof(buf_rd)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -1163,8 +1163,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
|
||||
* print that on the next line
|
||||
*/
|
||||
|
||||
if (bi->extra
|
||||
&& bi->extra->vnc.import.aux_prefix.family) {
|
||||
if (bi->extra && bi->extra->vnc.import.aux_prefix.family) {
|
||||
const char *sp;
|
||||
|
||||
sp = rfapi_ntop(
|
||||
@ -4630,7 +4629,7 @@ notcfg:
|
||||
************************************************************************/
|
||||
void vnc_add_vrf_opener(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
|
||||
{
|
||||
if (rfg->rfd == NULL) { /* need new rfapi_handle */
|
||||
if (rfg->rfd == NULL) { /* need new rfapi_handle */
|
||||
/* based on rfapi_open */
|
||||
struct rfapi_descriptor *rfd;
|
||||
|
||||
|
||||
@ -53,8 +53,7 @@
|
||||
|
||||
static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
struct rfapi_nve_group_cfg *rfg,
|
||||
struct route_node *rn,
|
||||
struct attr *attr,
|
||||
struct route_node *rn, struct attr *attr,
|
||||
afi_t afi,
|
||||
struct rfapi_descriptor *irfd);
|
||||
|
||||
@ -879,8 +878,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
|
||||
NULL, /* attr, ignored */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
/*
|
||||
* yuck!
|
||||
* - but consistent with rest of function
|
||||
@ -908,8 +908,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
|
||||
NULL, /* attr, ignored */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1035,20 +1036,18 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
|
||||
iattr = bgp_attr_intern(&hattr);
|
||||
bgp_attr_flush(&hattr);
|
||||
|
||||
bgp_update(irfd->peer,
|
||||
&rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
iattr, /* bgp_update copies
|
||||
it */
|
||||
afi, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, /* tag not used for
|
||||
unicast */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
bgp_update(
|
||||
irfd->peer, &rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
iattr, /* bgp_update copies
|
||||
it */
|
||||
afi, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL,
|
||||
/* RD not used for unicast */
|
||||
NULL,
|
||||
/* tag not used for unicast */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
@ -1153,10 +1152,8 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
|
||||
static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
struct rfapi_nve_group_cfg *rfg,
|
||||
struct route_node *rn,
|
||||
struct attr *attr,
|
||||
afi_t afi,
|
||||
struct rfapi_descriptor *irfd)
|
||||
struct route_node *rn, struct attr *attr,
|
||||
afi_t afi, struct rfapi_descriptor *irfd)
|
||||
{
|
||||
struct prefix nhp;
|
||||
struct bgp_info info;
|
||||
@ -1169,23 +1166,26 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
assert(rfg->rfd == NULL);
|
||||
|
||||
if (!rfg->rt_export_list || !rfg->rfapi_import_table) {
|
||||
vnc_zlog_debug_verbose("%s: VRF \"%s\" is missing RT import/export configuration.\n",
|
||||
__func__, rfg->name);
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: VRF \"%s\" is missing RT import/export configuration.\n",
|
||||
__func__, rfg->name);
|
||||
return;
|
||||
}
|
||||
if (!rfg->rd.prefixlen) {
|
||||
vnc_zlog_debug_verbose("%s: VRF \"%s\" is missing RD configuration.\n",
|
||||
__func__, rfg->name);
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: VRF \"%s\" is missing RD configuration.\n",
|
||||
__func__, rfg->name);
|
||||
return;
|
||||
}
|
||||
if (rfg->label > MPLS_LABEL_MAX) {
|
||||
vnc_zlog_debug_verbose("%s: VRF \"%s\" is missing defaul label configuration.\n",
|
||||
__func__, rfg->name);
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: VRF \"%s\" is missing defaul label configuration.\n",
|
||||
__func__, rfg->name);
|
||||
return;
|
||||
}
|
||||
|
||||
irfd = XCALLOC(MTYPE_RFAPI_DESC,
|
||||
sizeof(struct rfapi_descriptor));
|
||||
sizeof(struct rfapi_descriptor));
|
||||
irfd->bgp = bgp;
|
||||
rfg->rfd = irfd;
|
||||
/*
|
||||
@ -1221,11 +1221,9 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
return;
|
||||
|
||||
if (VNC_DEBUG(EXPORT_BGP_DIRECT_ADD)) {
|
||||
vnc_zlog_debug_any("%s: attr follows",
|
||||
__func__);
|
||||
vnc_zlog_debug_any("%s: attr follows", __func__);
|
||||
rfapiPrintAttrPtrs(NULL, attr);
|
||||
vnc_zlog_debug_any("%s: hattr follows",
|
||||
__func__);
|
||||
vnc_zlog_debug_any("%s: hattr follows", __func__);
|
||||
rfapiPrintAttrPtrs(NULL, &hattr);
|
||||
}
|
||||
|
||||
@ -1234,12 +1232,13 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
|
||||
info.peer = irfd->peer;
|
||||
info.attr = &hattr;
|
||||
ret = route_map_apply(rfg->routemap_export_bgp,
|
||||
&rn->p, RMAP_BGP, &info);
|
||||
ret = route_map_apply(rfg->routemap_export_bgp, &rn->p,
|
||||
RMAP_BGP, &info);
|
||||
if (ret == RMAP_DENYMATCH) {
|
||||
bgp_attr_flush(&hattr);
|
||||
vnc_zlog_debug_verbose("%s: route map says DENY, so not calling bgp_update",
|
||||
__func__);
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: route map says DENY, so not calling bgp_update",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1254,13 +1253,11 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
|
||||
bgp_update(irfd->peer, &rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
iattr, /* bgp_update copies it */
|
||||
afi, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
iattr, /* bgp_update copies it */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
|
||||
bgp_attr_unintern(&iattr);
|
||||
|
||||
@ -1340,7 +1337,8 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
|
||||
for (ln = listhead(rfg->nves); ln;
|
||||
ln = listnextnode(ln)) {
|
||||
vnc_direct_add_rn_group_rd(bgp, rfg, rn, &attr,
|
||||
afi, listgetdata(ln));
|
||||
afi,
|
||||
listgetdata(ln));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1361,21 +1359,17 @@ void vnc_direct_bgp_add_group(struct bgp *bgp, struct rfapi_nve_group_cfg *rfg)
|
||||
|
||||
static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
|
||||
struct rfapi_nve_group_cfg *rfg,
|
||||
struct route_node *rn,
|
||||
afi_t afi,
|
||||
struct route_node *rn, afi_t afi,
|
||||
struct rfapi_descriptor *irfd)
|
||||
{
|
||||
if (irfd == NULL)
|
||||
return;
|
||||
bgp_withdraw(irfd->peer, &rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
NULL, /* attr, ignored */
|
||||
afi, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
0, /* addpath_id */
|
||||
NULL, /* attr, ignored */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1414,20 +1408,22 @@ static void vnc_direct_bgp_del_group_afi(struct bgp *bgp,
|
||||
for (rn = route_top(rt); rn; rn = route_next(rn))
|
||||
if (rn->info) {
|
||||
if (rfg->type == RFAPI_GROUP_CFG_VRF)
|
||||
vnc_direct_del_rn_group_rd(bgp, rfg, rn,
|
||||
afi, rfg->rfd);
|
||||
vnc_direct_del_rn_group_rd(bgp, rfg, rn, afi,
|
||||
rfg->rfd);
|
||||
else {
|
||||
struct listnode *ln;
|
||||
|
||||
/*
|
||||
* For each NVE that is assigned to the export nve
|
||||
* For each NVE that is assigned to the export
|
||||
* nve
|
||||
* group, generate
|
||||
* a route with that NVE as its next hop
|
||||
*/
|
||||
for (ln = listhead(rfg->nves); ln;
|
||||
ln = listnextnode(ln))
|
||||
vnc_direct_del_rn_group_rd(bgp, rfg, rn,
|
||||
afi, listgetdata(ln));
|
||||
vnc_direct_del_rn_group_rd(
|
||||
bgp, rfg, rn, afi,
|
||||
listgetdata(ln));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1531,8 +1527,8 @@ static void import_table_to_nve_list_direct_bgp(struct bgp *bgp,
|
||||
if (rfgn->rfg && rfgn->rfg->rfapi_import_table == it) {
|
||||
if (rfgn->rfg->nves)
|
||||
nve_group_to_nve_list(rfgn->rfg, nves, family);
|
||||
else if (rfgn->rfg->rfd &&
|
||||
rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
|
||||
else if (rfgn->rfg->rfd
|
||||
&& rfgn->rfg->type == RFAPI_GROUP_CFG_VRF) {
|
||||
if (!*nves)
|
||||
*nves = list_new();
|
||||
listnode_add(*nves, rfgn->rfg->rfd);
|
||||
@ -1718,7 +1714,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
|
||||
iattr, /* bgp_update copies this attr */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast, EVPN neither */
|
||||
NULL, /* tag not used for unicast, EVPN neither */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
@ -1734,7 +1730,8 @@ static int vncExportWithdrawTimer(struct thread *t)
|
||||
NULL, /* attr, ignored */
|
||||
family2afi(eti->node->p.family), SAFI_UNICAST, eti->type,
|
||||
eti->subtype, NULL, /* RD not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast, EVPN neither */
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast, EVPN neither */
|
||||
|
||||
/*
|
||||
* Free the eti
|
||||
@ -1857,9 +1854,8 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
|
||||
|
||||
prefix2str(&rn->p, prefixstr,
|
||||
sizeof(prefixstr));
|
||||
vnc_zlog_debug_verbose(
|
||||
"%s: checking prefix %s", __func__,
|
||||
prefixstr);
|
||||
vnc_zlog_debug_verbose("%s: checking prefix %s",
|
||||
__func__, prefixstr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1952,20 +1948,20 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
|
||||
"%s: calling bgp_update",
|
||||
__func__);
|
||||
|
||||
bgp_update(ri->peer,
|
||||
&rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
iattr, /* bgp_update copies
|
||||
it */
|
||||
AFI_IP, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT_RH,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, /* tag not used for
|
||||
unicast, EVPN
|
||||
neither */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
bgp_update(
|
||||
ri->peer, &rn->p, /* prefix */
|
||||
0, /* addpath_id */
|
||||
iattr, /* bgp_update copies
|
||||
it */
|
||||
AFI_IP, SAFI_UNICAST,
|
||||
ZEBRA_ROUTE_VNC_DIRECT_RH,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL,
|
||||
/* RD not used for unicast */
|
||||
NULL,
|
||||
/* tag not used for unicast,
|
||||
or EVPN */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
}
|
||||
@ -2053,6 +2049,9 @@ void vnc_direct_bgp_rh_reexport(struct bgp *bgp, afi_t afi)
|
||||
*/
|
||||
void vnc_export_bgp_enable(struct bgp *bgp, afi_t afi)
|
||||
{
|
||||
if (!bgp->rfapi_cfg)
|
||||
return;
|
||||
|
||||
switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
|
||||
case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
|
||||
break;
|
||||
@ -2073,6 +2072,9 @@ void vnc_export_bgp_enable(struct bgp *bgp, afi_t afi)
|
||||
|
||||
void vnc_export_bgp_disable(struct bgp *bgp, afi_t afi)
|
||||
{
|
||||
if (!bgp->rfapi_cfg)
|
||||
return;
|
||||
|
||||
switch (bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_EXPORT_BGP_MODE_BITS) {
|
||||
case BGP_VNC_CONFIG_EXPORT_BGP_MODE_NONE:
|
||||
break;
|
||||
|
||||
@ -2557,7 +2557,7 @@ void vnc_import_bgp_exterior_del_route_interior(
|
||||
if (bi->extra) {
|
||||
prd = &bi->extra->vnc.import.rd;
|
||||
label = decode_label(
|
||||
&bi->extra->label[0]);
|
||||
&bi->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
|
||||
@ -8,12 +8,13 @@ am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CLIPPY_0 = @echo " CLIPPY " $@;
|
||||
am__v_CLIPPY_1 =
|
||||
|
||||
CLIPPY_SUPPRESSIONS = LSAN_OPTIONS="suppressions=$(top_builddir)/tools/lsan-suppressions.txt"
|
||||
CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
|
||||
|
||||
SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h
|
||||
.c_clippy.c:
|
||||
@{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
|
||||
$(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
|
||||
$(AM_V_CLIPPY) $(CLIPPY_SUPPRESSIONS) $(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
|
||||
|
||||
## automake's "ylwrap" is a great piece of GNU software... not.
|
||||
.l.c:
|
||||
|
||||
60
configure.ac
60
configure.ac
@ -185,6 +185,37 @@ CC="${CC% -std=c99}"
|
||||
|
||||
AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"])
|
||||
|
||||
dnl AddressSanitizer support
|
||||
AC_ARG_ENABLE([address-sanitizer], AS_HELP_STRING([--enable-address-sanitizer], \
|
||||
[enabled AddressSanitizer support for detecting a wide variety of \
|
||||
memory allocation and deallocation errors]), \
|
||||
[AC_DEFINE(HAVE_ADDRESS_SANITIZER, 1, [enable AddressSanitizer])
|
||||
CFLAGS="$CFLAGS -fsanitize=address"
|
||||
CXXFLAGS="$CXXFLAGS -fsanitize=address"
|
||||
AC_TRY_COMPILE([],[const int i=0;],[AC_MSG_NOTICE([Address Sanitizer Enabled])],
|
||||
[AC_MSG_ERROR([Address Sanitizer not available])])
|
||||
])
|
||||
|
||||
dnl ThreadSanitizer support
|
||||
AC_ARG_ENABLE([thread-sanitizer], AS_HELP_STRING([--enable-thread-sanitizer], \
|
||||
[enabled ThreadSanitizer support for detecting data races]), \
|
||||
[AC_DEFINE(HAVE_THREAD_SANITIZER, 1, [enable ThreadSanitizer])
|
||||
CFLAGS="$CFLAGS -fsanitize=thread"
|
||||
CXXFLAGS="$CXXFLAGS -fsanitize=thread"
|
||||
AC_TRY_COMPILE([],[const int i=0;],[AC_MSG_NOTICE([Thread Sanitizer Enabled])],
|
||||
[AC_MSG_ERROR([Thread Sanitizer not available])])
|
||||
])
|
||||
|
||||
dnl MemorySanitizer support
|
||||
AC_ARG_ENABLE([memory-sanitizer], AS_HELP_STRING([--enable-memory-sanitizer], \
|
||||
[enabled MemorySanitizer support for detecting uninitialized memory reads]), \
|
||||
[AC_DEFINE(HAVE_THREAD_SANITIZER, 1, [enable MemorySanitizer])
|
||||
CFLAGS="$CFLAGS -fsanitize=memory -fPIE -pie"
|
||||
CXXFLAGS="$CXXFLAGS -fsanitize=memory -fPIE -pie"
|
||||
AC_TRY_COMPILE([],[const int i=0;],[AC_MSG_NOTICE([Memory Sanitizer Enabled])],
|
||||
[AC_MSG_ERROR([Memory Sanitizer not available])])
|
||||
])
|
||||
|
||||
dnl if the user has specified any CFLAGS, override our settings
|
||||
if test "x${enable_dev_build}" = "xyes"; then
|
||||
AC_DEFINE(DEV_BUILD,,Build for development)
|
||||
@ -396,6 +427,8 @@ AC_ARG_ENABLE(rpki,
|
||||
AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
|
||||
AC_ARG_ENABLE([clippy-only],
|
||||
AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
|
||||
AC_ARG_ENABLE([numeric_version],
|
||||
AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)]))
|
||||
|
||||
AS_IF([test "${enable_clippy_only}" != "yes"], [
|
||||
AC_CHECK_HEADERS(json-c/json.h)
|
||||
@ -647,6 +680,14 @@ AC_DEFINE_UNQUOTED(MULTIPATH_NUM, $MPATH_NUM, Maximum number of paths for a rout
|
||||
|
||||
AC_DEFINE_UNQUOTED(VTYSH_PAGER, "$VTYSH_PAGER", [What pager to use])
|
||||
|
||||
dnl ------------------------------------
|
||||
dnl Alpine only accepts numeric versions
|
||||
dnl ------------------------------------
|
||||
if test "x${enable_numeric_version}" != "x" ; then
|
||||
VERSION="`echo ${VERSION} | tr -c -d '[[.0-9]]'`"
|
||||
PACKAGE_VERSION="`echo ${PACKAGE_VERSION} | tr -c -d '[[.0-9]]'`"
|
||||
fi
|
||||
|
||||
dnl -----------------------------------
|
||||
dnl Add extra version string to package
|
||||
dnl name, string and version fields.
|
||||
@ -1872,27 +1913,10 @@ AC_CONFIG_FILES([Makefile
|
||||
redhat/frr.spec
|
||||
debianpkg/Makefile
|
||||
debianpkg/changelog
|
||||
alpine/APKBUILD
|
||||
snapcraft/snapcraft.yaml
|
||||
lib/version.h
|
||||
tests/lib/cli/test_cli.refout
|
||||
doc/defines.texi
|
||||
doc/bgpd.8
|
||||
doc/isisd.8
|
||||
doc/ospf6d.8
|
||||
doc/ospfclient.8
|
||||
doc/ospfd.8
|
||||
doc/ldpd.8
|
||||
doc/ripd.8
|
||||
doc/eigrpd.8
|
||||
doc/ripngd.8
|
||||
doc/pimd.8
|
||||
doc/mtracebis.8
|
||||
doc/nhrpd.8
|
||||
doc/vtysh.1
|
||||
doc/watchfrr.8
|
||||
doc/zebra.8
|
||||
doc/frr.1
|
||||
doc/frr-args.8
|
||||
pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
|
||||
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
||||
pkgsrc/eigrpd.sh])
|
||||
|
||||
@ -71,10 +71,15 @@ adding a new backport.
|
||||
Or change some options:
|
||||
(see `rules` file for available options)
|
||||
|
||||
export WANT_BGP_VNC=1
|
||||
export WANT_CUMULUS_MODE=1
|
||||
debuild -b -uc -us
|
||||
debuild --set-envvar=WANT_BGP_VNC=1 --set-envvar=WANT_CUMULUS_MODE=1 -b -uc -us
|
||||
|
||||
To build with RPKI, download the librtr packages from
|
||||
https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
|
||||
install librtr-dev on the build server and build the packages as
|
||||
debuild --set-envvar=WANT_RPKI=1 -b -uc -us
|
||||
RPKI packages have an additonal dependency of librtr0 which can be
|
||||
found at the same URL
|
||||
|
||||
DONE.
|
||||
|
||||
If all works correctly, then you should end up with the Debian packages under
|
||||
|
||||
@ -16,8 +16,10 @@ WANT_CUMULUS_MODE ?= 0
|
||||
WANT_MULTIPATH ?= 1
|
||||
WANT_SNMP ?= 0
|
||||
|
||||
# NOTES:
|
||||
#
|
||||
# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
|
||||
MULTIPATH ?= 256
|
||||
|
||||
@ -27,6 +29,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -135,18 +140,11 @@ override_dh_auto_configure:
|
||||
fi
|
||||
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/user/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
||||
@ -5,18 +5,6 @@ usr/include/frr/
|
||||
usr/lib/
|
||||
tools/frr etc/init.d/
|
||||
usr/share/doc/frr/
|
||||
usr/share/man/man1/vtysh.1
|
||||
usr/share/man/man1/frr.1
|
||||
usr/share/man/man8
|
||||
usr/share/man/man8/bgpd.8
|
||||
usr/share/man/man8/ospf6d.8
|
||||
usr/share/man/man8/ospfd.8
|
||||
usr/share/man/man8/ripd.8
|
||||
usr/share/man/man8/ripngd.8
|
||||
usr/share/man/man8/zebra.8
|
||||
usr/share/man/man8/isisd.8
|
||||
usr/share/man/man8/watchfrr.8
|
||||
usr/share/man/man8/mtracebis.8
|
||||
usr/share/snmp/mibs/
|
||||
tools/etc/* etc/
|
||||
tools/*.service lib/systemd/system
|
||||
|
||||
@ -15,9 +15,20 @@ WANT_BGP_VNC ?= 1
|
||||
WANT_CUMULUS_MODE ?= 0
|
||||
WANT_MULTIPATH ?= 1
|
||||
WANT_SNMP ?= 0
|
||||
WANT_RPKI ?= 0
|
||||
|
||||
# NOTES:
|
||||
#
|
||||
# If you use WANT_RPKI, then there is a new dependency for librtr0 package
|
||||
# and a build dependency of the librtr-dev package.
|
||||
# While the librtr0 is added to the depenencies automatically, the build
|
||||
# dependency can't be changed dynamically and building will fail if the
|
||||
# librtr-dev isn't installed during package build
|
||||
# Tested versions of both packages can be found at
|
||||
# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
|
||||
#
|
||||
# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
|
||||
MULTIPATH ?= 256
|
||||
|
||||
@ -27,6 +38,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -88,6 +102,12 @@ else
|
||||
USE_CUMULUS=--enable-cumulus=no
|
||||
endif
|
||||
|
||||
ifeq ($(WANT_RPKI), 1)
|
||||
USE_RPKI=--enable-rpki
|
||||
else
|
||||
USE_RPKI=--disable-rpki
|
||||
endif
|
||||
|
||||
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
|
||||
DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
|
||||
endif
|
||||
@ -99,6 +119,13 @@ endif
|
||||
%:
|
||||
dh $@ --with=autoreconf --parallel --dbg-package=frr-dbg --list-missing
|
||||
|
||||
override_dh_gencontrol:
|
||||
ifeq ($(WANT_RPKI), 1)
|
||||
dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)"
|
||||
else
|
||||
dh_gencontrol
|
||||
endif
|
||||
|
||||
override_dh_auto_configure:
|
||||
# Frr needs /proc to check some BSD vs Linux specific stuff.
|
||||
# Else it fails with an obscure error message pointing out that
|
||||
@ -131,22 +158,20 @@ override_dh_auto_configure:
|
||||
$(USE_PIM) \
|
||||
--enable-dependency-tracking \
|
||||
$(USE_BGP_VNC) \
|
||||
$(USE_RPKI) \
|
||||
$(shell dpkg-buildflags --export=configure); \
|
||||
fi
|
||||
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ Priority: optional
|
||||
Maintainer: Nobody <nobody@frrouting.org>
|
||||
Uploaders: Nobody <nobody@frrouting.org>
|
||||
XSBC-Original-Maintainer: <maintainers@frrouting.org>
|
||||
Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr
|
||||
Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://www.frrouting.org/
|
||||
|
||||
|
||||
@ -2,7 +2,5 @@ AUTHORS
|
||||
NEWS
|
||||
README
|
||||
REPORTING-BUGS
|
||||
doc/BGP-TypeCode
|
||||
doc/draft-zebra-00.txt
|
||||
doc/mpls/
|
||||
bgpd/BGP4-MIB.txt
|
||||
doc/user/*.rst
|
||||
doc/figures/*.png
|
||||
|
||||
@ -1 +1 @@
|
||||
doc/frr.info*
|
||||
doc/user/_build/texinfo/frr.info
|
||||
|
||||
@ -1,2 +1 @@
|
||||
usr/share/info
|
||||
doc/*.png usr/share/info
|
||||
doc/user/_build/texinfo/*.png usr/share/info
|
||||
|
||||
@ -5,20 +5,8 @@ usr/include/frr/
|
||||
usr/lib/
|
||||
tools/frr usr/lib/frr
|
||||
usr/share/doc/frr/
|
||||
usr/share/man/man1/vtysh.1
|
||||
usr/share/man/man1/frr.1
|
||||
usr/share/man/man8
|
||||
usr/share/man/man8/bgpd.8
|
||||
usr/share/man/man8/ospf6d.8
|
||||
usr/share/man/man8/ospfd.8
|
||||
usr/share/man/man8/ripd.8
|
||||
usr/share/man/man8/ripngd.8
|
||||
usr/share/man/man8/zebra.8
|
||||
usr/share/man/man8/isisd.8
|
||||
usr/share/man/man8/watchfrr.8
|
||||
usr/share/man/man8/frr-args.8
|
||||
usr/share/man/man8/mtracebis.8
|
||||
usr/share/snmp/mibs/
|
||||
tools/etc/* etc/
|
||||
tools/*.service lib/systemd/system
|
||||
debian/frr.conf usr/lib/tmpfiles.d
|
||||
tools/*.service lib/systemd/system
|
||||
tools/frr-reload usr/lib/frr/
|
||||
debian/frr.conf usr/lib/tmpfiles.d
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
doc/bgpd.8
|
||||
doc/ospf6d.8
|
||||
doc/ospfd.8
|
||||
doc/ripd.8
|
||||
doc/ripngd.8
|
||||
doc/vtysh.1
|
||||
doc/zebra.8
|
||||
doc/isisd.8
|
||||
doc/watchfrr.8
|
||||
doc/manpages/_build/man/frr.1
|
||||
doc/manpages/_build/man/bgpd.8
|
||||
doc/manpages/_build/man/pimd.8
|
||||
doc/manpages/_build/man/eigrpd.8
|
||||
doc/manpages/_build/man/ldpd.8
|
||||
doc/manpages/_build/man/nhrpd.8
|
||||
doc/manpages/_build/man/ospf6d.8
|
||||
doc/manpages/_build/man/ospfd.8
|
||||
doc/manpages/_build/man/ripd.8
|
||||
doc/manpages/_build/man/ripngd.8
|
||||
doc/manpages/_build/man/vtysh.1
|
||||
doc/manpages/_build/man/zebra.8
|
||||
doc/manpages/_build/man/isisd.8
|
||||
doc/manpages/_build/man/watchfrr.8
|
||||
doc/manpages/_build/man/mtracebis.8
|
||||
|
||||
@ -15,9 +15,20 @@ WANT_BGP_VNC ?= 1
|
||||
WANT_CUMULUS_MODE ?= 0
|
||||
WANT_MULTIPATH ?= 1
|
||||
WANT_SNMP ?= 0
|
||||
WANT_RPKI ?= 0
|
||||
|
||||
# NOTES:
|
||||
#
|
||||
# If you use WANT_RPKI, then there is a new dependency for librtr0 package
|
||||
# and a build dependency of the librtr-dev package.
|
||||
# While the librtr0 is added to the depenencies automatically, the build
|
||||
# dependency can't be changed dynamically and building will fail if the
|
||||
# librtr-dev isn't installed during package build
|
||||
# Tested versions of both packages can be found at
|
||||
# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
|
||||
#
|
||||
# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
# Please be aware that 0 is NOT disabled, but treated as unlimited
|
||||
|
||||
MULTIPATH ?= 256
|
||||
|
||||
@ -27,6 +38,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -88,6 +102,12 @@ else
|
||||
USE_CUMULUS=--enable-cumulus=no
|
||||
endif
|
||||
|
||||
ifeq ($(WANT_RPKI), 1)
|
||||
USE_RPKI=--enable-rpki
|
||||
else
|
||||
USE_RPKI=--disable-rpki
|
||||
endif
|
||||
|
||||
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
|
||||
DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
|
||||
endif
|
||||
@ -99,6 +119,13 @@ endif
|
||||
%:
|
||||
dh $@ --with=systemd,autoreconf --parallel --dbg-package=frr-dbg --list-missing
|
||||
|
||||
override_dh_gencontrol:
|
||||
ifeq ($(WANT_RPKI), 1)
|
||||
dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)"
|
||||
else
|
||||
dh_gencontrol
|
||||
endif
|
||||
|
||||
override_dh_auto_configure:
|
||||
# Frr needs /proc to check some BSD vs Linux specific stuff.
|
||||
# Else it fails with an obscure error message pointing out that
|
||||
@ -132,22 +159,17 @@ override_dh_auto_configure:
|
||||
$(USE_PIM) \
|
||||
--enable-dependency-tracking \
|
||||
$(USE_BGP_VNC) \
|
||||
$(USE_RPKI) \
|
||||
$(shell dpkg-buildflags --export=configure); \
|
||||
fi
|
||||
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/user/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
||||
9
doc/.gitignore
vendored
9
doc/.gitignore
vendored
@ -2,13 +2,6 @@ Makefile
|
||||
Makefile.in
|
||||
mdate-sh
|
||||
draft-zebra-00.txt
|
||||
frr.info-*
|
||||
zebra.html
|
||||
defines.texi
|
||||
version.texi
|
||||
texinfo.tex
|
||||
frr.html
|
||||
frr.info
|
||||
*.pdf
|
||||
*.eps
|
||||
frr.ps
|
||||
@ -28,8 +21,6 @@ stamp-vti
|
||||
*.toc
|
||||
*.tp
|
||||
*.vr
|
||||
*.8
|
||||
*.1
|
||||
.arch-inventory
|
||||
.arch-ids
|
||||
*~
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
|
||||
BGP-4[+] UPDATE Attribute TypeCode list
|
||||
|
||||
Value Attribute References
|
||||
=========================================================================
|
||||
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 4456]
|
||||
10 CLUSTER_LIST [RFC 4456]
|
||||
11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)]
|
||||
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]
|
||||
=========================================================================
|
||||
@ -1,96 +0,0 @@
|
||||
Building FRR for OpenWRT/LEDE from Git Source
|
||||
===============================================
|
||||
|
||||
- for the moment because of cross compile problems, master is not supported,
|
||||
only upto 3.0
|
||||
- LDP can't be built because of missing Perl-XML-LibXML in OpenWRT/LEDE tree
|
||||
|
||||
Prepare build environment
|
||||
-------------------------
|
||||
|
||||
https://lede-project.org/docs/guide-developer/install-buildsystem
|
||||
|
||||
for
|
||||
|
||||
Ubuntu 12.04LTS:
|
||||
|
||||
sudo apt-get install build-essential subversion git-core \
|
||||
libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc \
|
||||
libxml-parser-perl mercurial bzr ecj cvs unzip
|
||||
|
||||
Ubuntu 64bit:
|
||||
|
||||
sudo apt-get install build-essential subversion libncurses5-dev zlib1g-dev \
|
||||
gawk gcc-multilib flex git-core gettext libssl-dev
|
||||
|
||||
Debian 8 Jessie:
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext unzip zlib1g-dev file python
|
||||
|
||||
Debian 9 Stretch:
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext zlib1g-dev
|
||||
|
||||
Centos x86-64 (some packages require EPEL):
|
||||
|
||||
yum install subversion binutils bzip2 gcc gcc-c++ gawk gettext flex \
|
||||
ncurses-devel zlib-devel zlib-static make patch unzip glibc glibc-devel \
|
||||
perl-ExtUtils-MakeMaker glibc-static quilt ncurses-libs sed sdcc bison \
|
||||
intltool sharutils wget git-core openssl-devel xz
|
||||
|
||||
Fedora 24 - 64Bit:
|
||||
|
||||
dnf install -y subversion binutils bzip2 gcc gcc-c++ gawk gettext git-core \
|
||||
unzip ncurses-devel ncurses-compat-libs zlib-devel zlib-static make \
|
||||
flex patch perl-ExtUtils-MakeMaker perl-Thread-Queue glibc glibc-devel \
|
||||
glibc-static quilt sed sdcc intltool sharutils bison wget openssl-devel
|
||||
|
||||
|
||||
Get LEDE Sources (from Git)
|
||||
---------------------------
|
||||
|
||||
LEDE and OpenWRT is planned to remerge and won't cover the similar OpenWRT build
|
||||
As normal user:
|
||||
git clone https://git.lede-project.org/source.git lede
|
||||
cd lede
|
||||
./scripts/feeds update -a
|
||||
./scripts/feeds install -a
|
||||
cd feeds/routing
|
||||
git pull origin pull/319/head
|
||||
ln -s ../../../feeds/routing/frr/ ../../package/feeds/routing/
|
||||
cd ../..
|
||||
make menuconfig
|
||||
|
||||
Select the needed target then select needed packages in
|
||||
Network -> Routing and Redirection -> frr, exit and save
|
||||
|
||||
make or make package/frr/compile
|
||||
|
||||
It may be possible that on first build `make package/frr/compile` not to work
|
||||
and it may be needed to run a `make` for the entire build envronment, add V=s
|
||||
for debugging
|
||||
|
||||
Work with sources
|
||||
-----------------
|
||||
|
||||
To update the rc1 version or add other options, the Makefile is found in
|
||||
feeds/routing/frr
|
||||
|
||||
edit:
|
||||
PKG_VERSION:=
|
||||
PKG_SOURCE_VERSION:=<git-hash>
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Edit `/usr/sbin/frr.init` and add/remove the daemons name in section DAEMONS=
|
||||
or don't install unneded packages
|
||||
For example: zebra bgpd ldpd isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||
|
||||
### Enable the serivce
|
||||
- service frr enable
|
||||
|
||||
### Start the service
|
||||
- service frr start
|
||||
348
doc/Makefile.am
348
doc/Makefile.am
@ -1,194 +1,260 @@
|
||||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
# Dia, the version i have at least, doesn't do very good EPS output
|
||||
# (some of the text is scaled strangely). So this will work, but
|
||||
# it is probably better to use something like gimp to convert the
|
||||
# dia exported PNG files to EPS manually.
|
||||
# Pass down make invocation to each subdirectory.
|
||||
#
|
||||
# Here we use 'convert' from the well known 'ImageMagick' package
|
||||
# to do conversion from png to eps/pdf for figures.
|
||||
# PDF form is required for frr.pdf, using PDFTex at least.
|
||||
# Each of these directories contains a Sphinx-generated Makefile that has been
|
||||
# modified to implement all the targets required by Automake, as documented in
|
||||
# the 'Third-Party Makefiles' section of the Automake docs.
|
||||
#
|
||||
# TeX implementation, which we depend on already anyway.
|
||||
#
|
||||
# dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf
|
||||
SUFFIXES = .png .eps .dia .pdf
|
||||
DIATOPNG = dia -t png -e
|
||||
DIATOEPS = dia -t eps -e
|
||||
PNGTOEPS = convert -antialias -contrast -despeckle
|
||||
PNGTOPDF = $(PNGTOEPS)
|
||||
EPSTOPDF = epstopdf
|
||||
# Note the absence of the 'developer' directory here; development docs are
|
||||
# never built as part of a regular build. They are only built when explicitly
|
||||
# asked for. See comment further down.
|
||||
|
||||
VNCFIGURES_PNG =
|
||||
VNCFIGURES_DIA = -vnc-mesh -vnc-frr-route-reflector \
|
||||
-vnc-commercial-route-reflector -vnc-redundant-route-reflectors \
|
||||
-vnc-gw -vnc-gw-rr
|
||||
# Sphinx is not designed to be invoked multiple times against the same toctree.
|
||||
.NOTPARALLEL:
|
||||
|
||||
# TODO: A target that creates an empty text file for each member of
|
||||
# VNCFIGURES_TXT
|
||||
VNCFIGURES_TXT = $(VNCFIGURES:%.png=%.txt)
|
||||
SUBDIRS = manpages user
|
||||
AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} doczdir=${abs_srcdir}
|
||||
|
||||
# The figure sources
|
||||
figures_names_parts = -normal-processing -rs-processing \
|
||||
_topologies_full _topologies_rs \
|
||||
$(VNCFIGURES_DIA)
|
||||
MANPAGE_BUILDDIR = manpages/_build/man
|
||||
|
||||
figures_sources = $(figures_names_parts:%=fig%.dia)
|
||||
figures_png = $(figures_names_parts:%=fig%.png) $(VNCFIGURES_PNG)
|
||||
figures_pdf = $(figures_names_parts:%=fig%.pdf) $(VNCFIGURES_PNG:%.png=%.pdf)
|
||||
figures_eps = $(figures_names_parts:%=fig%.eps) $(VNCFIGURES_PNG:%.png=%.eps)
|
||||
figures_txt = $(figures_names_parts:%=fig%.txt)
|
||||
|
||||
# rather twisted logic because we have to build PDFs of the EPS figures for
|
||||
# PDFTex and yet build one PDF, frr.pdf, from texi source. Which means we
|
||||
# cant rely on a single automatic rule for *.pdf, eg the one automatically
|
||||
# provided by automake. If you are an automake wizard, please feel free to
|
||||
# compact it somehow.
|
||||
|
||||
info_TEXINFOS = frr.texi
|
||||
|
||||
# Have to manually specify the frr.pdf rule in order to allow
|
||||
# us to have a generic automatic .pdf rule to build the figure sources
|
||||
# because it cant just work from the png's directly it seems - contrary
|
||||
# to the documentation...
|
||||
frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) defines.texi
|
||||
$(TEXI2PDF) -o "$@" $< || true
|
||||
|
||||
# don't ask me why the info file is in srcdir
|
||||
$(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi
|
||||
frr.dvi: $(frr_TEXINFOS) defines.texi
|
||||
frr.html: $(frr_TEXINFOS) defines.texi
|
||||
|
||||
frr_TEXINFOS = \
|
||||
appendix.texi \
|
||||
basic.texi \
|
||||
bgpd.texi \
|
||||
isisd.texi \
|
||||
filter.texi \
|
||||
vnc.texi \
|
||||
babeld.texi \
|
||||
install.texi \
|
||||
ipv6.texi \
|
||||
kernel.texi \
|
||||
main.texi \
|
||||
nhrpd.texi \
|
||||
eigrpd.texi \
|
||||
ospf6d.texi \
|
||||
ospfd.texi \
|
||||
overview.texi \
|
||||
protocol.texi \
|
||||
ripd.texi \
|
||||
ripngd.texi \
|
||||
routemap.texi \
|
||||
snmp.texi \
|
||||
vtysh.texi \
|
||||
routeserver.texi \
|
||||
$(figures_png) \
|
||||
snmptrap.texi \
|
||||
ospf_fundamentals.texi \
|
||||
isisd.texi $(figures_txt) \
|
||||
rpki.texi \
|
||||
pimd.texi \
|
||||
#END
|
||||
|
||||
.png.eps:
|
||||
$(PNGTOEPS) $< "$@"
|
||||
|
||||
.png.pdf:
|
||||
$(PNGTOPDF) $< "$@"
|
||||
|
||||
.dia.png:
|
||||
$(DIATOPNG) "$@" $<
|
||||
|
||||
man_MANS = frr.1 frr-args.8
|
||||
# This is a hack, see comment further down.
|
||||
man_MANS = $(MANPAGE_BUILDDIR)/frr.1
|
||||
|
||||
if PIMD
|
||||
man_MANS += pimd.8
|
||||
man_MANS += mtracebis.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/pimd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/mtracebis.8
|
||||
endif
|
||||
|
||||
if BGPD
|
||||
man_MANS += bgpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/bgpd.8
|
||||
endif
|
||||
|
||||
if ISISD
|
||||
man_MANS += isisd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/isisd.8
|
||||
endif
|
||||
|
||||
if OSPF6D
|
||||
man_MANS += ospf6d.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospf6d.8
|
||||
endif
|
||||
|
||||
if OSPFCLIENT
|
||||
man_MANS += ospfclient.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospfclient.8
|
||||
endif
|
||||
|
||||
if OSPFD
|
||||
man_MANS += ospfd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospfd.8
|
||||
endif
|
||||
|
||||
if LDPD
|
||||
man_MANS += ldpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ldpd.8
|
||||
endif
|
||||
|
||||
if RIPD
|
||||
man_MANS += ripd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ripd.8
|
||||
endif
|
||||
|
||||
if RIPNGD
|
||||
man_MANS += ripngd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ripngd.8
|
||||
endif
|
||||
|
||||
if NHRPD
|
||||
man_MANS += nhrpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/nhrpd.8
|
||||
endif
|
||||
|
||||
if VTYSH
|
||||
man_MANS += vtysh.1
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/vtysh.1
|
||||
endif
|
||||
|
||||
if WATCHFRR
|
||||
man_MANS += watchfrr.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/watchfrr.8
|
||||
endif
|
||||
|
||||
if ZEBRA
|
||||
man_MANS += zebra.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/zebra.8
|
||||
endif
|
||||
|
||||
if EIGRPD
|
||||
man_MANS += eigrpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/eigrpd.8
|
||||
endif
|
||||
|
||||
EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
|
||||
\
|
||||
bgpd.8.in \
|
||||
isisd.8.in \
|
||||
ospf6d.8.in \
|
||||
ospfclient.8.in \
|
||||
ospfd.8.in \
|
||||
ldpd.8.in \
|
||||
ripd.8.in \
|
||||
ripngd.8.in \
|
||||
pimd.8.in \
|
||||
mtracebis.8.in \
|
||||
nhrpd.8.in \
|
||||
vtysh.1.in \
|
||||
watchfrr.8.in \
|
||||
zebra.8.in \
|
||||
frr.1.in \
|
||||
eigrpd.8.in \
|
||||
\
|
||||
mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \
|
||||
mpls/opaque_lsa.txt mpls/ospfd.conf \
|
||||
$(figures_sources) $(figures_png) $(figures_txt)
|
||||
# Automake is particular about manpages. It is aware of them and has some
|
||||
# special facilities for handling them, but it assumes that manpages are always
|
||||
# given in groff source and so these facilities are limited to simply
|
||||
# specifying the path to the groff sources in a special variable. There is no
|
||||
# target for building manpages that can be extended, as there are for pdf,
|
||||
# html, dvi, etc. Unfortunately this leaves us with hijacking the
|
||||
# 'install-data' and 'all' targets in the 3rd-party Makefile in manpages/ to
|
||||
# make sure manpages are always built, and then using the special Automake
|
||||
# variable defined above in order to take advantage of automatic installation.
|
||||
#
|
||||
# However, it is conceivable that someone may want to build just the manpages,
|
||||
# so here's an explicit target for that.
|
||||
man:
|
||||
$(MAKE) -C manpages man
|
||||
|
||||
draft-zebra-00.txt: draft-zebra-00.ms
|
||||
groff -T ascii -ms $< > $@
|
||||
# Automake automatically defines targets for various document formats. All of
|
||||
# the child 3rd-party Makefiles are aware of all Automake targets and implement
|
||||
# the ones we are interested in.
|
||||
#
|
||||
# The SUBDIRS variable at the top of this Makefile.am causes the following
|
||||
# implicit Automake targets to only build user documentation, and not developer
|
||||
# documentation:
|
||||
# - info
|
||||
# - html
|
||||
# - pdf
|
||||
#
|
||||
# If you wish to build developer documentation, use these targets:
|
||||
developer-info:
|
||||
$(MAKE) -C developer info
|
||||
|
||||
# Ensure that all of the figures are copied into the html directory
|
||||
html-local: $(HTMLS)
|
||||
if test -d $(HTMLS) ; then \
|
||||
cp -p $(figures_png) $(HTMLS) ; \
|
||||
else \
|
||||
echo "$(HTMLS) is not a directory. Make it so, the rerun make."; \
|
||||
fi
|
||||
developer-pdf:
|
||||
$(MAKE) -C developer latexpdf
|
||||
|
||||
developer-html:
|
||||
$(MAKE) -C developer html
|
||||
|
||||
# If you want to build the developer's docs in other formats, try the
|
||||
# following:
|
||||
#
|
||||
# $ cd developer
|
||||
# $ make help
|
||||
|
||||
# dist tarballs want doc sources
|
||||
EXTRA_DIST = frr-sphinx.mk \
|
||||
manpages/bgpd.rst \
|
||||
manpages/common-options.rst \
|
||||
manpages/conf.py \
|
||||
manpages/defines.rst \
|
||||
manpages/eigrpd.rst \
|
||||
manpages/epilogue.rst \
|
||||
manpages/frr.rst \
|
||||
manpages/index.rst \
|
||||
manpages/isisd.rst \
|
||||
manpages/ldpd.rst \
|
||||
manpages/Makefile \
|
||||
manpages/mtracebis.rst \
|
||||
manpages/nhrpd.rst \
|
||||
manpages/ospf6d.rst \
|
||||
manpages/ospfclient.rst \
|
||||
manpages/ospfd.rst \
|
||||
manpages/pimd.rst \
|
||||
manpages/ripd.rst \
|
||||
manpages/ripngd.rst \
|
||||
manpages/vtysh.rst \
|
||||
manpages/watchfrr.rst \
|
||||
manpages/zebra.rst \
|
||||
developer/bgpd.rst \
|
||||
developer/bgp-typecodes.rst \
|
||||
developer/building-frr-on-alpine.rst \
|
||||
developer/building-frr-on-centos6.rst \
|
||||
developer/building-frr-on-centos7.rst \
|
||||
developer/building-frr-on-debian8.rst \
|
||||
developer/building-frr-on-debian9.rst \
|
||||
developer/building-frr-on-fedora24.rst \
|
||||
developer/building-frr-on-freebsd10.rst \
|
||||
developer/building-frr-on-freebsd11.rst \
|
||||
developer/building-frr-on-freebsd9.rst \
|
||||
developer/building-frr-on-lede-openwrt.rst \
|
||||
developer/building-frr-on-netbsd6.rst \
|
||||
developer/building-frr-on-netbsd7.rst \
|
||||
developer/building-frr-on-omnios.rst \
|
||||
developer/building-frr-on-openbsd6.rst \
|
||||
developer/building-frr-on-ubuntu1204.rst \
|
||||
developer/building-frr-on-ubuntu1404.rst \
|
||||
developer/building-frr-on-ubuntu1604.rst \
|
||||
developer/building.rst \
|
||||
developer/cli.rst \
|
||||
developer/conf.py \
|
||||
developer/draft-zebra-00.ms \
|
||||
developer/hooks.rst \
|
||||
developer/index.rst \
|
||||
developer/ldpd-basic-test-setup.md \
|
||||
developer/library.rst \
|
||||
developer/Makefile \
|
||||
developer/memtypes.rst \
|
||||
developer/modules.rst \
|
||||
developer/next-hop-tracking.rst \
|
||||
developer/ospf-api.rst \
|
||||
developer/ospf.rst \
|
||||
developer/ospf-sr.rst \
|
||||
developer/workflow.rst \
|
||||
developer/zebra.rst \
|
||||
user/appendix.rst \
|
||||
user/babeld.rst \
|
||||
user/basic.rst \
|
||||
user/bgp.rst \
|
||||
user/conf.py \
|
||||
user/eigrpd.rst \
|
||||
user/filter.rst \
|
||||
user/glossary.rst \
|
||||
user/index.rst \
|
||||
user/installation.rst \
|
||||
user/ipv6.rst \
|
||||
user/isisd.rst \
|
||||
user/kernel.rst \
|
||||
user/Makefile \
|
||||
user/nhrpd.rst \
|
||||
user/ospf6d.rst \
|
||||
user/ospfd.rst \
|
||||
user/ospf_fundamentals.rst \
|
||||
user/overview.rst \
|
||||
user/pim.rst \
|
||||
user/ripd.rst \
|
||||
user/ripngd.rst \
|
||||
user/routemap.rst \
|
||||
user/routeserver.rst \
|
||||
user/rpki.rst \
|
||||
user/snmp.rst \
|
||||
user/snmptrap.rst \
|
||||
user/Useful_Sysctl_Settings.md \
|
||||
user/vnc.rst \
|
||||
user/vtysh.rst \
|
||||
user/zebra.rst \
|
||||
mpls/ChangeLog.opaque.txt \
|
||||
mpls/ospfd.conf \
|
||||
mpls/cli_summary.txt \
|
||||
mpls/opaque_lsa.txt \
|
||||
figures/cligraph.png \
|
||||
figures/cligraph.svg \
|
||||
figures/fig-normal-processing.dia \
|
||||
figures/fig-normal-processing.png \
|
||||
figures/fig-normal-processing.txt \
|
||||
figures/fig-rs-processing.dia \
|
||||
figures/fig-rs-processing.png \
|
||||
figures/fig-rs-processing.txt \
|
||||
figures/fig_topologies_full.dia \
|
||||
figures/fig_topologies_full.png \
|
||||
figures/fig_topologies_full.txt \
|
||||
figures/fig_topologies_rs.dia \
|
||||
figures/fig_topologies_rs.png \
|
||||
figures/fig_topologies_rs.txt \
|
||||
figures/fig-vnc-commercial-route-reflector.dia \
|
||||
figures/fig-vnc-commercial-route-reflector.png \
|
||||
figures/fig-vnc-commercial-route-reflector.txt \
|
||||
figures/fig-vnc-frr-route-reflector.dia \
|
||||
figures/fig-vnc-frr-route-reflector.png \
|
||||
figures/fig-vnc-frr-route-reflector.txt \
|
||||
figures/fig-vnc-gw.dia \
|
||||
figures/fig-vnc-gw.png \
|
||||
figures/fig-vnc-gw-rr.dia \
|
||||
figures/fig-vnc-gw-rr.png \
|
||||
figures/fig-vnc-gw-rr.txt \
|
||||
figures/fig-vnc-gw.txt \
|
||||
figures/fig-vnc-mesh.dia \
|
||||
figures/fig-vnc-mesh.png \
|
||||
figures/fig-vnc-mesh.txt \
|
||||
figures/fig-vnc-redundant-route-reflectors.dia \
|
||||
figures/fig-vnc-redundant-route-reflectors.png \
|
||||
figures/fig-vnc-redundant-route-reflectors.txt \
|
||||
figures/frr-icon.svg \
|
||||
figures/frr-logo-icon.png \
|
||||
figures/frr-logo-medium.png \
|
||||
figures/frr-logo.png \
|
||||
figures/frr-logo-small.png \
|
||||
figures/git_branches.png \
|
||||
figures/git_branches.svg \
|
||||
figures/ospf_api_architecture.png \
|
||||
figures/ospf_api_msghdr.png \
|
||||
figures/ospf_api_msgs1.png \
|
||||
figures/ospf_api_msgs2.png
|
||||
|
||||
263
doc/OSPF-API.md
263
doc/OSPF-API.md
@ -1,263 +0,0 @@
|
||||
# OSPF API Documentation
|
||||
|
||||
[TOC]
|
||||
|
||||
## Disclaimer
|
||||
|
||||
The OSPF daemon contains an API for application access to the LSA database. This API was created by Ralph Keller, originally as patch for Zebra. Unfortunately, the page containing documentation of the API is no longer online. This page is an attempt to recreate documentation for the API (with lots of help of the WayBackMachine)
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
This page describes an API that allows external applications to access the link-state database (LSDB) of the OSPF daemon. The implementation is based on the OSPF code from FRRouting (forked from Quagga and formerly Zebra) routing protocol suite and is subject to the GNU General Public License. The OSPF API provides you with the following functionality:
|
||||
|
||||
* Retrieval of the full or partial link-state database of the OSPF daemon. This allows applications to obtain an exact copy of the LSDB including router LSAs, network LSAs and so on. Whenever a new LSA arrives at the OSPF daemon, the API module immediately informs the application by sending a message. This way, the application is always synchronized with the LSDB of the OSPF daemon.
|
||||
* Origination of own opaque LSAs (of type 9, 10, or 11) which are then distributed transparently to other routers within the flooding scope and received by other applications through the OSPF API.
|
||||
|
||||
Opaque LSAs, which are described in RFC 2370 , allow you to distribute application-specific information within a network using the OSPF protocol. The information contained in opaque LSAs is transparent for the routing process but it can be processed by other modules such as traffic engineering (e.g., MPLS-TE).
|
||||
|
||||
## 2. Architecture
|
||||
|
||||
The following picture depicts the architecture of the Quagga/Zebra protocol suite. The OSPF daemon is extended with opaque LSA capabilities and an API for external applications. The OSPF core module executes the OSPF protocol by discovering neighbors and exchanging neighbor state. The opaque module, implemented by Masahiko Endo, provides functions to exchange opaque LSAs between routers. Opaque LSAs can be generated by several modules such as the MPLS-TE module or the API server module. These modules then invoke the opaque module to flood their data to neighbors within the flooding scope.
|
||||
|
||||
The client, which is an application potentially running on a different node than the OSPF daemon, links against the OSPF API client library. This client library establishes a socket connection with the API server module of the OSPF daemon and uses this connection to retrieve LSAs and originate opaque LSAs.
|
||||
|
||||

|
||||
|
||||
The OSPF API server module works like any other internal opaque module (such as the MPLS-TE module), but listens to connections from external applications that want to communicate with the OSPF daemon. The API server module can handle multiple clients concurrently.
|
||||
|
||||
One of the main objectives of the implementation is to make as little changes to the existing Zebra code as possible.
|
||||
|
||||
## 3. Installation & Configuration
|
||||
|
||||
Download FRRouting and unpack
|
||||
|
||||
Configure your frr version (note that --enable-opaque-lsa also enables the ospfapi server and ospfclient).
|
||||
|
||||
```
|
||||
% update-autotools
|
||||
% sh ./configure --enable-opaque-lsa
|
||||
% make
|
||||
|
||||
```
|
||||
|
||||
This should also compile the client library and sample application in ospfclient.
|
||||
|
||||
Make sure that you have enabled opaque LSAs in your configuration. Add the ospf opaque-lsa statement to your ospfd.conf:
|
||||
|
||||
```
|
||||
! -*- ospf -*-
|
||||
!
|
||||
! OSPFd sample configuration file
|
||||
!
|
||||
!
|
||||
hostname xxxxx
|
||||
password xxxxx
|
||||
|
||||
router ospf
|
||||
router-id 10.0.0.1
|
||||
network 10.0.0.1/24 area 1
|
||||
neighbor 10.0.0.2
|
||||
network 10.0.1.2/24 area 1
|
||||
neighbor 10.0.1.1
|
||||
ospf opaque-lsa <============ add this statement!
|
||||
|
||||
```
|
||||
|
||||
## 4. Usage
|
||||
|
||||
In the following we describe how you can use the sample application to originate opaque LSAs. The sample application first registers with the OSPF daemon the opaque type it wants to inject and then waits until the OSPF daemon is ready to accept opaque LSAs of that type. Then the client application originates an opaque LSA, waits 10 seconds and then updates the opaque LSA with new opaque data. After another 20 seconds, the client application deletes the opaque LSA from the LSDB. If the clients terminates unexpectedly, the OSPF API module will remove all the opaque LSAs that the application registered. Since the opaque LSAs are flooded to other routers, we will see the opaque LSAs in all routers according to the flooding scope of the opaque LSA.
|
||||
|
||||
We have a very simple demo setup, just two routers connected with an ATM point-to-point link. Start the modified OSPF daemons on two adjacent routers. First run on msr2:
|
||||
|
||||
```
|
||||
> msr2:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
|
||||
```
|
||||
|
||||
And on the neighboring router msr3:
|
||||
|
||||
|
||||
```
|
||||
> msr3:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
|
||||
```
|
||||
|
||||
Now the two routers form adjacency and start exchanging their databases. Looking at the OSPF daemon of msr2 (or msr3), you see this:
|
||||
|
||||
```
|
||||
ospfd> show ip ospf database
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
Router Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum Link count
|
||||
10.0.0.1 10.0.0.1 55 0x80000003 0xc62f 2
|
||||
10.0.0.2 10.0.0.2 55 0x80000003 0xe3e4 3
|
||||
|
||||
Net Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum
|
||||
10.0.0.2 10.0.0.2 60 0x80000001 0x5fcb
|
||||
|
||||
```
|
||||
|
||||
Now we start the sample main application that originates an opaque LSA.
|
||||
|
||||
|
||||
```
|
||||
> cd ospfapi/apiclient
|
||||
> ./main msr2 10 250 20 0.0.0.0 0.0.0.1
|
||||
|
||||
```
|
||||
|
||||
This originates an opaque LSA of type 10 (area local), with opaque type 250 (experimental), opaque id of 20 (chosen arbitrarily), interface address 0.0.0.0 (which is used only for opaque LSAs type 9), and area 0.0.0.1
|
||||
|
||||
Again looking at the OSPF database you see:
|
||||
|
||||
```
|
||||
ospfd> show ip ospf database
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
Router Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum Link count
|
||||
10.0.0.1 10.0.0.1 437 0x80000003 0xc62f 2
|
||||
10.0.0.2 10.0.0.2 437 0x80000003 0xe3e4 3
|
||||
|
||||
Net Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum
|
||||
10.0.0.2 10.0.0.2 442 0x80000001 0x5fcb
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
Opaque-Type/Id ADV Router Age Seq# CkSum
|
||||
250.0.0.20 10.0.0.1 0 0x80000001 0x58a6 <=== opaque LSA
|
||||
|
||||
```
|
||||
|
||||
You can take a closer look at this opaque LSA:
|
||||
|
||||
```
|
||||
ospfd> show ip ospf database opaque-area
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
LS age: 4
|
||||
Options: 66
|
||||
LS Type: Area-Local Opaque-LSA
|
||||
Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
|
||||
Advertising Router: 10.0.0.1
|
||||
LS Seq Number: 80000001
|
||||
Checksum: 0x58a6
|
||||
Length: 24
|
||||
Opaque-Type 250 (Private/Experimental)
|
||||
Opaque-ID 0x14
|
||||
Opaque-Info: 4 octets of data
|
||||
Added using OSPF API: 4 octets of opaque data
|
||||
Opaque data: 1 0 0 0 <==== counter is 1
|
||||
|
||||
```
|
||||
|
||||
Note that the main application updates the opaque LSA after 10 seconds, then it looks as follows:
|
||||
|
||||
```
|
||||
ospfd> show ip ospf database opaque-area
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
LS age: 1
|
||||
Options: 66
|
||||
LS Type: Area-Local Opaque-LSA
|
||||
Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
|
||||
Advertising Router: 10.0.0.1
|
||||
LS Seq Number: 80000002
|
||||
Checksum: 0x59a3
|
||||
Length: 24
|
||||
Opaque-Type 250 (Private/Experimental)
|
||||
Opaque-ID 0x14
|
||||
Opaque-Info: 4 octets of data
|
||||
Added using OSPF API: 4 octets of opaque data
|
||||
Opaque data: 2 0 0 0 <==== counter is now 2
|
||||
|
||||
```
|
||||
|
||||
Note that the payload of the opaque LSA has changed as you can see above.
|
||||
|
||||
Then, again after another 20 seconds, the opaque LSA is flushed from the LSDB.
|
||||
|
||||
#### Important note:
|
||||
|
||||
In order to originate an opaque LSA, there must be at least one active opaque-capable neighbor. Thus, you cannot originate opaque LSAs of no neighbors are present. If you try to originate even so no neighbor is ready, you will receive a not ready error message. The reason for this restriction is that it might be possible that some routers have an identical opaque LSA from a previous origination in their LSDB that unfortunately could not be flushed due to a crash, and now if the router comes up again and starts originating a new opaque LSA, the new opaque LSA is considered older since it has a lower sequence number and is ignored by other routers (that consider the stalled opaque LSA as more recent). However, if the originating router first synchronizes the database before originating opaque LSAs, it will detect the older opaque LSA and can flush it first.
|
||||
|
||||
|
||||
## 5. Protocol and Message Formats
|
||||
|
||||
If you are developing your own client application and you don't want to make use of the client library (due to the GNU license restriction or whatever reason), you can implement your own client-side message handling. The OSPF API uses two connections between the client and the OSPF API server: One connection is used for a synchronous request /reply protocol and another connection is used for asynchronous notifications (e.g., LSA update, neighbor status change).
|
||||
|
||||
Each message begins with the following header:
|
||||
|
||||

|
||||
|
||||
The message type field can take one of the following values:
|
||||
|
||||
Messages to OSPF deamon | Value
|
||||
----------------------- | -----
|
||||
MSG_REGISTER_OPAQUETYPE | 1
|
||||
MSG_UNREGISTER_OPAQUETYPE | 2
|
||||
MSG_REGISTER_EVENT | 3
|
||||
MSG_SYNC_LSDB | 4
|
||||
MSG_ORIGINATE_REQUEST | 5
|
||||
MSG_DELETE_REQUEST | 6
|
||||
|
||||
Messages from OSPF deamon | Value
|
||||
------------------------- | -----
|
||||
MSG_REPLY | 10
|
||||
MSG_READY_NOTIFY | 11
|
||||
MSG_LSA_UPDATE_NOTIFY | 12
|
||||
MSG_LSA_DELETE_NOTIFY | 13
|
||||
MSG_NEW_IF | 14
|
||||
MSG_DEL_IF | 15
|
||||
MSG_ISM_CHANGE | 16
|
||||
MSG_NSM_CHANGE | 17
|
||||
|
||||
The synchronous requests and replies have the following message formats:
|
||||
|
||||

|
||||
|
||||
The origin field allows to select according to the following types of origins:
|
||||
|
||||
Origin | Value
|
||||
------ | -----
|
||||
NON_SELF_ORIGINATED | 0
|
||||
SELF_ORIGINATED | 1
|
||||
ANY_ORIGIN | 2
|
||||
|
||||
The reply message has on of the following error codes:
|
||||
|
||||
Error code | Value
|
||||
---------- | -----
|
||||
API_OK | 0
|
||||
API_NOSUCHINTERFACE | -1
|
||||
API_NOSUCHAREA | -2
|
||||
API_NOSUCHLSA | -3
|
||||
API_ILLEGALSATYPE | -4
|
||||
API_ILLEGALOPAQUETYPE | -5
|
||||
API_OPAQUETYPEINUSE | -6
|
||||
API_NOMEMORY | -7
|
||||
API_ERROR | -99
|
||||
API_UNDEF | -100
|
||||
|
||||
The asynchronous notifications have the following message formats:
|
||||
|
||||

|
||||
|
||||
## 6. Original Acknowledgments from Ralph Keller
|
||||
|
||||
I would like to thank Masahiko Endo, the author of the opaque LSA extension module, for his great support. His wonderful ASCII graphs explaining the internal workings of this code, and his invaluable input proved to be crucial in designing a useful API for accessing the link state database of the OSPF daemon. Once, he even decided to take the plane from Tokyo to Zurich so that we could actually meet and have face-to-face discussions, which was a lot of fun. Clearly, without Masahiko no API would ever be completed. I also would like to thank Daniel Bauer who wrote an opaque LSA implementation too and was willing to test the OSPF API code in one of his projects.
|
||||
@ -1,257 +0,0 @@
|
||||
@node Packet Binary Dump Format
|
||||
@appendix Packet Binary Dump Format
|
||||
|
||||
FRR can dump routing protocol packet into file with a binary format
|
||||
(@pxref{Dump BGP packets and table}).
|
||||
|
||||
It seems to be better that we share the MRT's header format for
|
||||
backward compatibility with MRT's dump logs. We should also define the
|
||||
binary format excluding the header, because we must support both IP
|
||||
v4 and v6 addresses as socket addresses and / or routing entries.
|
||||
|
||||
In the last meeting, we discussed to have a version field in the
|
||||
header. But Masaki told us that we can define new `type' value rather
|
||||
than having a `version' field, and it seems to be better because we
|
||||
don't need to change header format.
|
||||
|
||||
Here is the common header format. This is same as that of MRT.
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Subtype |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP_ET, the common header format will
|
||||
contain an additional microsecond field (RFC6396 2011).
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Subtype |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Microsecond |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and
|
||||
Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Old State | New State |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Where State is the value defined in RFC1771.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Old State | New State |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
|
||||
and Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Message Packet |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Where BGP Message Packet is the whole contents of the
|
||||
BGP4 message including header portion.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Message Packet |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
|
||||
and Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | Status |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time Last Change |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Family | SAFI | Next-Hop-Len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix Length | Address Prefix [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Attribute Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Attribute [variable length] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | Status |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time Last Change |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Family | SAFI | Next-Hop-Len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix Length | Address Prefix [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Prefix (cont'd) [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Attribute Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Attribute [variable length] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
BGP4 Attribute must not contain MP_UNREACH_NLRI.
|
||||
If BGP Attribute has MP_REACH_NLRI field, it must has
|
||||
zero length NLRI, e.g., MP_REACH_NLRI has only Address
|
||||
Family, SAFI and next-hop values.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT,
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | File Name [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The file specified in "File Name" contains all routing entries,
|
||||
which are in the format of ``subtype == BGP4MP_ENTRY''.
|
||||
|
||||
@example
|
||||
@group
|
||||
Constants:
|
||||
/* type value */
|
||||
#define MSG_PROTOCOL_BGP4MP 16
|
||||
#define MSG_PROTOCOL_BGP4MP_ET 17
|
||||
/* subtype value */
|
||||
#define BGP4MP_STATE_CHANGE 0
|
||||
#define BGP4MP_MESSAGE 1
|
||||
#define BGP4MP_ENTRY 2
|
||||
#define BGP4MP_SNAPSHOT 3
|
||||
@end group
|
||||
@end example
|
||||
212
doc/babeld.texi
212
doc/babeld.texi
@ -1,212 +0,0 @@
|
||||
@c -*-texinfo-*-
|
||||
@c This is part of the FRR Manual.
|
||||
@c @value{COPYRIGHT_STR}
|
||||
@c See file frr.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.
|
||||
|
||||
FRR 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 Command {babel resend-delay <20-655340>} {}
|
||||
Specifies the time after which important messages are resent when
|
||||
avoiding a black-hole. The default is 2000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {babel diversity} {}
|
||||
@deffnx Command {no babel diversity} {}
|
||||
Enable or disable routing using radio frequency diversity. This is
|
||||
highly recommended in networks with many wireless nodes.
|
||||
|
||||
If you enable this, you will probably want to set @code{babel
|
||||
diversity-factor} and @code{babel channel} below.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {babel diversity-factor <1-256>} {}
|
||||
Sets the multiplicative factor used for diversity routing, in units of
|
||||
1/256; lower values cause diversity to play a more important role in
|
||||
route selection. The default it 256, which means that diversity plays
|
||||
no role in route selection; you will probably want to set that to 128
|
||||
or less on nodes with multiple independent radios.
|
||||
@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} is always correct, while
|
||||
@code{babel split-horizon} is an optimisation that should only be used
|
||||
on symmetric and transitive (wired) networks. The default is
|
||||
@code{babel split-horizon} on wired interfaces, and @code{no babel
|
||||
split-horizon} on wireless interfaces. This flag is reset when the
|
||||
wired/wireless status of an interface is changed.
|
||||
@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 {Interface Command} {babel channel <1-254>}
|
||||
@deffnx {Interface Command} {babel channel interfering}
|
||||
@deffnx {Interface Command} {babel channel noninterfering}
|
||||
Set the channel number that diversity routing uses for this interface
|
||||
(see @code{babel diversity} above). Noninterfering interfaces are
|
||||
assumed to only interfere with themselves, interfering interfaces are
|
||||
assumed to interfere with all other channels except noninterfering
|
||||
channels, and interfaces with a channel number interfere with
|
||||
interfering interfaces and interfaces with the same channel number.
|
||||
The default is @samp{babel channel interfering} for wireless
|
||||
interfaces, and @samp{babel channel noninterfering} for wired
|
||||
interfaces. This is reset when the wired/wireless status of an
|
||||
interface is changed.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rxcost <1-65534>}
|
||||
Specifies the base receive cost for this interface. For wireless
|
||||
interfaces, it specifies the multiplier used for computing the ETX
|
||||
reception cost (default 256); for wired interfaces, it specifies the
|
||||
cost that will be advertised to neighbours. This value is reset when
|
||||
the wired/wireless attribute of the interface is changed.
|
||||
|
||||
Do not use this command unless you know what you are doing; in most
|
||||
networks, acting directly on the cost using route maps is a better
|
||||
technique.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-decay <1-256>}
|
||||
This specifies the decay factor for the exponential moving average of
|
||||
RTT samples, in units of 1/256. Higher values discard old samples
|
||||
faster. The default is 42.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-min <1-65535>}
|
||||
This specifies the minimum RTT, in milliseconds, starting from which we
|
||||
increase the cost to a neighbour. The additional cost is linear in (rtt
|
||||
- rtt-min ). The default is 10@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-max <1-65535>}
|
||||
This specifies the maximum RTT, in milliseconds, above which we don't
|
||||
increase the cost to a neighbour. The default is 120@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel max-rtt-penalty <0-65535>}
|
||||
This specifies the maximum cost added to a neighbour because of RTT,
|
||||
i.e. when the RTT is higher or equal than rtt-max. The default is 0,
|
||||
which effectively disables the use of a RTT-based cost.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel enable-timestamps}
|
||||
@deffnx {Interface Command} {no babel enable-timestamps}
|
||||
Enable or disable sending timestamps with each Hello and IHU message in
|
||||
order to compute RTT values. The default is @code{no babel
|
||||
enable-timestamps}.
|
||||
@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
|
||||
|
||||
@deffn {Babel Command} {babel smoothing-half-life <0-65534>}
|
||||
Specifies the time constant, in seconds, of the smoothing algorithm
|
||||
used for implementing hysteresis. Larger values reduce route
|
||||
oscillation at the cost of very slightly increasing convergence time.
|
||||
The value 0 disables hysteresis, and is suitable for wired networks.
|
||||
The default is 4@dmn{s}.
|
||||
@end deffn
|
||||
|
||||
@node Babel redistribution, Show Babel information, Babel configuration, Babel
|
||||
@section Babel redistribution
|
||||
|
||||
@deffn {Babel command} {redistribute @var{<ipv4|ipv6>} @var{kind}}
|
||||
@deffnx {Babel command} {no redistribute @var{<ipv4|ipv6>} @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 route} {}
|
||||
@deffnx {Command} {show babel route A.B.C.D}
|
||||
@deffnx {Command} {show babel route X:X::X:X}
|
||||
@deffnx {Command} {show babel route A.B.C.D/M}
|
||||
@deffnx {Command} {show babel route X:X::X:X/M}
|
||||
@deffnx {Command} {show babel interface} {}
|
||||
@deffnx {Command} {show babel interface @var{ifname}} {}
|
||||
@deffnx {Command} {show babel neighbor} {}
|
||||
@deffnx {Command} {show babel parameters} {}
|
||||
These commands dump various parts of @command{babeld}'s internal state.
|
||||
@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
|
||||
|
||||
642
doc/basic.texi
642
doc/basic.texi
@ -1,642 +0,0 @@
|
||||
@node Basic commands
|
||||
@chapter Basic commands
|
||||
|
||||
There are five routing daemons in use, and there is one manager daemon.
|
||||
These daemons may be located on separate machines from the manager
|
||||
daemon. Each of these daemons will listen on a particular port for
|
||||
incoming VTY connections. The routing daemons are:
|
||||
|
||||
@itemize @bullet
|
||||
@item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd}
|
||||
@item @command{zebra}
|
||||
@end itemize
|
||||
|
||||
The following sections discuss commands common to all the routing
|
||||
daemons.
|
||||
|
||||
@menu
|
||||
* Config Commands:: Commands used in config files
|
||||
* Terminal Mode Commands:: Common commands used in a VTY
|
||||
* Common Invocation Options:: Starting the daemons
|
||||
* Loadable Module Support:: Using extension modules
|
||||
* Virtual Terminal Interfaces:: Interacting with the daemons
|
||||
@end menu
|
||||
|
||||
|
||||
|
||||
@node Config Commands
|
||||
@section Config Commands
|
||||
|
||||
@cindex Configuration files for running the software
|
||||
@c A -not configuration files for installing the software
|
||||
@cindex Files for running configurations
|
||||
@cindex Modifying the herd's behavior
|
||||
@cindex Getting the herd running
|
||||
|
||||
|
||||
@menu
|
||||
* Basic Config Commands:: Some of the generic config commands
|
||||
* Sample Config File:: An example config file
|
||||
@end menu
|
||||
|
||||
|
||||
In a config file, you can write the debugging options, a vty's password,
|
||||
routing daemon configurations, a log file name, and so forth. This
|
||||
information forms the initial command set for a routing beast as it is
|
||||
starting.
|
||||
|
||||
Config files are generally found in:
|
||||
|
||||
@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 @w{}
|
||||
@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf}
|
||||
@end itemize
|
||||
|
||||
The daemon name plus @file{.conf} is the default config file name. You
|
||||
can specify a config file using the @kbd{-f} or @kbd{--config-file}
|
||||
options when starting the daemon.
|
||||
|
||||
|
||||
|
||||
@node Basic Config Commands
|
||||
@subsection Basic Config Commands
|
||||
|
||||
@deffn Command {hostname @var{hostname}} {}
|
||||
Set hostname of the router.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {password @var{password}} {}
|
||||
Set password for vty interface. If there is no password, a vty won't
|
||||
accept connections.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {enable password @var{password}} {}
|
||||
Set enable password.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log trap @var{level}} {}
|
||||
@deffnx Command {no log trap} {}
|
||||
These commands are deprecated and are present only for historical compatibility.
|
||||
The log trap command sets the current logging level for all enabled
|
||||
logging destinations, and it sets the default for all future logging commands
|
||||
that do not specify a level. The normal default
|
||||
logging level is debugging. The @code{no} form of the command resets
|
||||
the default level for future logging commands to debugging, but it does
|
||||
not change the logging level of existing logging destinations.
|
||||
@end deffn
|
||||
|
||||
|
||||
@deffn Command {log stdout} {}
|
||||
@deffnx Command {log stdout @var{level}} {}
|
||||
@deffnx Command {no log stdout} {}
|
||||
Enable logging output to stdout.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to stdout.
|
||||
The @code{level} argument must have one of these values:
|
||||
emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages
|
||||
with severity @code{errors}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log file @var{filename}} {}
|
||||
@deffnx Command {log file @var{filename} @var{level}} {}
|
||||
@deffnx Command {no log file} {}
|
||||
If you want to log into a file, please specify @code{filename} as
|
||||
in this example:
|
||||
@example
|
||||
log file /var/log/frr/bgpd.log informational
|
||||
@end example
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to a file.
|
||||
|
||||
Note: if you do not configure any file logging, and a daemon crashes due
|
||||
to a signal or an assertion failure, it will attempt to save the crash
|
||||
information in a file named /var/tmp/frr.<daemon name>.crashlog.
|
||||
For security reasons, this will not happen if the file exists already, so
|
||||
it is important to delete the file after reporting the crash information.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log syslog} {}
|
||||
@deffnx Command {log syslog @var{level}} {}
|
||||
@deffnx Command {no log syslog} {}
|
||||
Enable logging output to syslog.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to syslog.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log monitor} {}
|
||||
@deffnx Command {log monitor @var{level}} {}
|
||||
@deffnx Command {no log monitor} {}
|
||||
Enable logging output to vty terminals that have enabled logging
|
||||
using the @code{terminal monitor} command.
|
||||
By default, monitor logging is enabled at the debugging level, but this
|
||||
command (or the deprecated @code{log trap} command) can be used to change
|
||||
the monitor logging level.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to terminal monitors.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log facility @var{facility}} {}
|
||||
@deffnx Command {no log facility} {}
|
||||
This command changes the facility used in syslog messages. The default
|
||||
facility is @code{daemon}. The @code{no} form of the command resets
|
||||
the facility to the default @code{daemon} facility.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log record-priority} {}
|
||||
@deffnx Command {no log record-priority} {}
|
||||
To include the severity in all messages logged to a file, to stdout, or to
|
||||
a terminal monitor (i.e. anything except syslog),
|
||||
use the @code{log record-priority} global configuration command.
|
||||
To disable this option, use the @code{no} form of the command. By default,
|
||||
the severity level is not included in logged messages. Note: some
|
||||
versions of syslogd (including Solaris) can be configured to include
|
||||
the facility and level in the messages emitted.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log timestamp precision @var{<0-6>}} {}
|
||||
@deffnx Command {no log timestamp precision} {}
|
||||
This command sets the precision of log message timestamps to the
|
||||
given number of digits after the decimal point. Currently,
|
||||
the value must be in the range 0 to 6 (i.e. the maximum precision
|
||||
is microseconds).
|
||||
To restore the default behavior (1-second accuracy), use the
|
||||
@code{no} form of the command, or set the precision explicitly to 0.
|
||||
|
||||
@example
|
||||
@group
|
||||
log timestamp precision 3
|
||||
@end group
|
||||
@end example
|
||||
|
||||
In this example, the precision is set to provide timestamps with
|
||||
millisecond accuracy.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log commands} {}
|
||||
This command enables the logging of all commands typed by a user to
|
||||
all enabled log destinations. The note that logging includes full
|
||||
command lines, including passwords. Once set, command logging can only
|
||||
be turned off by restarting the daemon.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service password-encryption} {}
|
||||
Encrypt password.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service advanced-vty} {}
|
||||
Enable advanced mode VTY.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service terminal-length @var{<0-512>}} {}
|
||||
Set system wide line configuration. This configuration command applies
|
||||
to all VTY interfaces.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {line vty} {}
|
||||
Enter vty configuration mode.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {banner motd default} {}
|
||||
Set default motd string.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {no banner motd} {}
|
||||
No motd banner string will be printed.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {exec-timeout @var{minute}} {}
|
||||
@deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {}
|
||||
Set VTY connection timeout value. When only one argument is specified
|
||||
it is used for timeout value in minutes. Optional second argument is
|
||||
used for timeout value in seconds. Default timeout value is 10 minutes.
|
||||
When timeout value is zero, it means no timeout.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {no exec-timeout} {}
|
||||
Do not perform timeout at all. This command is as same as
|
||||
@command{exec-timeout 0 0}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {access-class @var{access-list}} {}
|
||||
Restrict vty connections with an access list.
|
||||
@end deffn
|
||||
|
||||
@node Sample Config File
|
||||
@subsection Sample Config File
|
||||
|
||||
|
||||
Below is a sample configuration file for the zebra daemon.
|
||||
|
||||
@example
|
||||
@group
|
||||
!
|
||||
! Zebra configuration file
|
||||
!
|
||||
hostname Router
|
||||
password zebra
|
||||
enable password zebra
|
||||
!
|
||||
log stdout
|
||||
!
|
||||
!
|
||||
@end group
|
||||
@end example
|
||||
|
||||
'!' and '#' are comment characters. If the first character of the word
|
||||
is one of the comment characters then from the rest of the line forward
|
||||
will be ignored as a comment.
|
||||
|
||||
@example
|
||||
password zebra!password
|
||||
@end example
|
||||
|
||||
If a comment character is not the first character of the word, it's a
|
||||
normal character. So in the above example '!' will not be regarded as a
|
||||
comment and the password is set to 'zebra!password'.
|
||||
|
||||
|
||||
|
||||
@node Terminal Mode Commands
|
||||
@section Terminal Mode Commands
|
||||
|
||||
@deffn Command {write terminal} {}
|
||||
Displays the current configuration to the vty interface.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {write file} {}
|
||||
Write current configuration to configuration file.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {configure terminal} {}
|
||||
Change to configuration mode. This command is the first step to
|
||||
configuration.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {terminal length @var{<0-512>}} {}
|
||||
Set terminal display length to @var{<0-512>}. If length is 0, no
|
||||
display control is performed.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {who} {}
|
||||
Show a list of currently connected vty sessions.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {list} {}
|
||||
List all available commands.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {show version} {}
|
||||
Show the current version of @value{PACKAGE_NAME} and its build host information.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {show logging} {}
|
||||
Shows the current configuration of the logging system. This includes
|
||||
the status of all logging destinations.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {logmsg @var{level} @var{message}} {}
|
||||
Send a message to all logging destinations that are enabled for messages
|
||||
of the given severity.
|
||||
@end deffn
|
||||
|
||||
|
||||
|
||||
|
||||
@node Common Invocation Options
|
||||
@section Common Invocation Options
|
||||
@c COMMON_OPTIONS
|
||||
@c OPTIONS section of the man page
|
||||
|
||||
These options apply to all @value{PACKAGE_NAME} daemons.
|
||||
|
||||
@table @samp
|
||||
|
||||
@item -d
|
||||
@itemx --daemon
|
||||
Runs in daemon mode.
|
||||
|
||||
@item -f @var{file}
|
||||
@itemx --config_file=@var{file}
|
||||
Set configuration file name.
|
||||
|
||||
@item -h
|
||||
@itemx --help
|
||||
Display this help and exit.
|
||||
|
||||
@item -i @var{file}
|
||||
@itemx --pid_file=@var{file}
|
||||
|
||||
Upon startup the process identifier of the daemon is written to a file,
|
||||
typically in @file{/var/run}. This file can be used by the init system
|
||||
to implement commands such as @command{@dots{}/init.d/zebra status},
|
||||
@command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra
|
||||
stop}.
|
||||
|
||||
The file name is an run-time option rather than a configure-time option
|
||||
so that multiple routing daemons can be run simultaneously. This is
|
||||
useful when using @value{PACKAGE_NAME} to implement a routing looking glass. One
|
||||
machine can be used to collect differing routing views from differing
|
||||
points in the network.
|
||||
|
||||
@item -A @var{address}
|
||||
@itemx --vty_addr=@var{address}
|
||||
Set the VTY local address to bind to. If set, the VTY socket will only
|
||||
be bound to this address.
|
||||
|
||||
@item -P @var{port}
|
||||
@itemx --vty_port=@var{port}
|
||||
Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not
|
||||
be opened.
|
||||
|
||||
@item -u @var{user}
|
||||
@itemx --vty_addr=@var{user}
|
||||
Set the user and group to run as.
|
||||
|
||||
@item -v
|
||||
@itemx --version
|
||||
Print program version.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
@node Loadable Module Support
|
||||
@section Loadable Module Support
|
||||
|
||||
FRR supports loading extension modules at startup. Loading, reloading or
|
||||
unloading modules at runtime is not supported (yet). To load a module, use
|
||||
the following command line option at daemon startup:
|
||||
|
||||
@table @samp
|
||||
@item -M @var{module:options}
|
||||
@itemx --module @var{module:options}
|
||||
|
||||
Load the specified module, optionally passing options to it. If the module
|
||||
name contains a slash (/), it is assumed to be a full pathname to a file to
|
||||
be loaded. If it does not contain a slash, the
|
||||
@code{@value{INSTALL_PREFIX_MODULES}} directory is searched for a module of
|
||||
the given name; first with the daemon name prepended (e.g. @code{zebra_mod}
|
||||
for @code{mod}), then without the daemon name prepended.
|
||||
|
||||
This option is available on all daemons, though some daemons may not have
|
||||
any modules available to be loaded.
|
||||
@end table
|
||||
|
||||
|
||||
@subsection The SNMP Module
|
||||
|
||||
If SNMP is enabled during compile-time and installed as part of the package,
|
||||
the @code{snmp} module can be loaded for the @command{zebra},
|
||||
@command{bgpd}, @command{ospfd}, @command{ospf6d} and @command{ripd} daemons.
|
||||
|
||||
The module ignores any options passed to it. Refer to @ref{SNMP Support}
|
||||
for information on its usage.
|
||||
|
||||
|
||||
@subsection The FPM Module
|
||||
|
||||
If FPM is enabled during compile-time and installed as part of the package,
|
||||
the @code{fpm} module can be loaded for the @command{zebra} daemon. This
|
||||
provides the Forwarding Plane Manager ("FPM") API.
|
||||
|
||||
The module expects its argument to be either @code{netlink} or
|
||||
@code{protobuf}, specifying the encapsulation to use. @code{netlink} is the
|
||||
default, and @code{protobuf} may not be available if the module was built
|
||||
without protobuf support. Refer to @ref{zebra FIB push interface} for more
|
||||
information.
|
||||
|
||||
|
||||
@node Virtual Terminal Interfaces
|
||||
@section Virtual Terminal Interfaces
|
||||
|
||||
VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line
|
||||
interface (CLI) for user interaction with the routing daemon.
|
||||
|
||||
@menu
|
||||
* VTY Overview:: Basics about VTYs
|
||||
* VTY Modes:: View, Enable, and Other VTY modes
|
||||
* VTY CLI Commands:: Commands for movement, edition, and management
|
||||
@end menu
|
||||
|
||||
|
||||
|
||||
@node VTY Overview
|
||||
@subsection VTY Overview
|
||||
|
||||
|
||||
VTY stands for Virtual TeletYpe interface. It means you can connect to
|
||||
the daemon via the telnet protocol.
|
||||
|
||||
To enable a VTY interface, you have to setup a VTY password. If there
|
||||
is no VTY password, one cannot connect to the VTY interface at all.
|
||||
|
||||
@example
|
||||
@group
|
||||
% telnet localhost 2601
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
|
||||
Hello, this is @value{PACKAGE_NAME} (version @value{PACKAGE_VERSION})
|
||||
@value{COPYRIGHT_STR}
|
||||
|
||||
User Access Verification
|
||||
|
||||
Password: XXXXX
|
||||
Router> ?
|
||||
enable Turn on privileged commands
|
||||
exit Exit current mode and down to previous mode
|
||||
help Description of the interactive help system
|
||||
list Print command list
|
||||
show Show running system information
|
||||
who Display who is on a vty
|
||||
Router> enable
|
||||
Password: XXXXX
|
||||
Router# configure terminal
|
||||
Router(config)# interface eth0
|
||||
Router(config-if)# ip address 10.0.0.1/8
|
||||
Router(config-if)# ^Z
|
||||
Router#
|
||||
@end group
|
||||
@end example
|
||||
|
||||
'?' is very useful for looking up commands.
|
||||
|
||||
@node VTY Modes
|
||||
@subsection VTY Modes
|
||||
|
||||
There are three basic VTY modes:
|
||||
|
||||
@menu
|
||||
* VTY View Mode:: Mode for read-only interaction
|
||||
* VTY Enable Mode:: Mode for read-write interaction
|
||||
* VTY Other Modes:: Special modes (tftp, etc)
|
||||
@end menu
|
||||
|
||||
There are commands that may be restricted to specific VTY modes.
|
||||
|
||||
@node VTY View Mode
|
||||
@subsubsection VTY View Mode
|
||||
@c to be written (gpoul)
|
||||
|
||||
|
||||
This mode is for read-only access to the CLI. One may exit the mode by
|
||||
leaving the system, or by entering @code{enable} mode.
|
||||
|
||||
@node VTY Enable Mode
|
||||
@subsubsection VTY Enable Mode
|
||||
|
||||
@c to be written (gpoul)
|
||||
This mode is for read-write access to the CLI. One may exit the mode by
|
||||
leaving the system, or by escaping to view mode.
|
||||
|
||||
@node VTY Other Modes
|
||||
@subsubsection VTY Other Modes
|
||||
|
||||
|
||||
@c to be written (gpoul)
|
||||
This page is for describing other modes.
|
||||
|
||||
@node VTY CLI Commands
|
||||
@subsection VTY CLI Commands
|
||||
|
||||
Commands that you may use at the command-line are described in the following
|
||||
three subsubsections.
|
||||
|
||||
@menu
|
||||
* CLI Movement Commands:: Commands for moving the cursor about
|
||||
* CLI Editing Commands:: Commands for changing text
|
||||
* CLI Advanced Commands:: Other commands, session management and so on
|
||||
@end menu
|
||||
|
||||
@node CLI Movement Commands
|
||||
@subsubsection CLI Movement Commands
|
||||
|
||||
These commands are used for moving the CLI cursor. The @key{C} character
|
||||
means press the Control Key.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-f
|
||||
@itemx @key{RIGHT}
|
||||
@kindex C-f
|
||||
@kindex @key{RIGHT}
|
||||
Move forward one character.
|
||||
|
||||
@item C-b
|
||||
@itemx @key{LEFT}
|
||||
@kindex C-b
|
||||
@kindex @key{LEFT}
|
||||
Move backward one character.
|
||||
|
||||
@item M-f
|
||||
@kindex M-f
|
||||
Move forward one word.
|
||||
|
||||
@item M-b
|
||||
@kindex M-b
|
||||
Move backward one word.
|
||||
|
||||
@item C-a
|
||||
@kindex C-a
|
||||
Move to the beginning of the line.
|
||||
|
||||
@item C-e
|
||||
@kindex C-e
|
||||
Move to the end of the line.
|
||||
|
||||
@end table
|
||||
|
||||
@node CLI Editing Commands
|
||||
@subsubsection CLI Editing Commands
|
||||
|
||||
These commands are used for editing text on a line. The @key{C}
|
||||
character means press the Control Key.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-h
|
||||
@itemx @key{DEL}
|
||||
@kindex C-h
|
||||
@kindex @key{DEL}
|
||||
Delete the character before point.
|
||||
|
||||
@item C-d
|
||||
@kindex C-d
|
||||
Delete the character after point.
|
||||
|
||||
@item M-d
|
||||
@kindex M-d
|
||||
Forward kill word.
|
||||
|
||||
@item C-w
|
||||
@kindex C-w
|
||||
Backward kill word.
|
||||
|
||||
@item C-k
|
||||
@kindex C-k
|
||||
Kill to the end of the line.
|
||||
|
||||
@item C-u
|
||||
@kindex C-u
|
||||
Kill line from the beginning, erasing input.
|
||||
|
||||
@item C-t
|
||||
@kindex C-t
|
||||
Transpose character.
|
||||
|
||||
@end table
|
||||
|
||||
@node CLI Advanced Commands
|
||||
@subsubsection CLI Advanced Commands
|
||||
|
||||
There are several additional CLI commands for command line completions,
|
||||
insta-help, and VTY session management.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-c
|
||||
@kindex C-c
|
||||
Interrupt current input and moves to the next line.
|
||||
|
||||
@item C-z
|
||||
@kindex C-z
|
||||
End current configuration session and move to top node.
|
||||
|
||||
|
||||
@item C-n
|
||||
@itemx @key{DOWN}
|
||||
@kindex C-n
|
||||
@kindex @key{DOWN}
|
||||
Move down to next line in the history buffer.
|
||||
|
||||
@item C-p
|
||||
@itemx @key{UP}
|
||||
@kindex C-p
|
||||
@kindex @key{UP}
|
||||
Move up to previous line in the history buffer.
|
||||
|
||||
@item TAB
|
||||
@kindex @key{TAB}
|
||||
Use command line completion by typing @key{TAB}.
|
||||
|
||||
@item ?
|
||||
@kindex @key{?}
|
||||
You can use command line help by typing @code{help} at the beginning of
|
||||
the line. Typing @kbd{?} at any point in the line will show possible
|
||||
completions.
|
||||
|
||||
@end table
|
||||
132
doc/bgpd.8.in
132
doc/bgpd.8.in
@ -1,132 +0,0 @@
|
||||
.TH BGPD 8 "25 November 2004" "@PACKAGE_FULLNAME@ BGPD daemon" "Version @PACKAGE_VERSION@"
|
||||
.SH NAME
|
||||
bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with @PACKAGE_FULLNAME@.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B bgpd
|
||||
[
|
||||
.B \-dhrSv
|
||||
] [
|
||||
.B \-f
|
||||
.I config-file
|
||||
] [
|
||||
.B \-i
|
||||
.I pid-file
|
||||
] [
|
||||
.B \-p
|
||||
.I bgp-port-number
|
||||
] [
|
||||
.B \-P
|
||||
.I port-number
|
||||
] [
|
||||
.B \-A
|
||||
.I vty-address
|
||||
] [
|
||||
.B \-u
|
||||
.I user
|
||||
] [
|
||||
.B \-g
|
||||
.I group
|
||||
] [
|
||||
.B \-M
|
||||
.I module:options
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B bgpd
|
||||
is a routing component that works with the
|
||||
.B @PACKAGE_FULLNAME@
|
||||
routing engine.
|
||||
.SH OPTIONS
|
||||
Options available for the
|
||||
.B bgpd
|
||||
command:
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-daemon\fR
|
||||
Runs in daemon mode, forking and exiting from tty.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
|
||||
Specifies the config file to use for startup. If not specified this
|
||||
option will default to \fB\fI@CFG_SYSCONF@/bgpd.conf\fR.
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR
|
||||
Specify the group to run as. Default is \fI@enable_group@\fR.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
A brief message.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
|
||||
When bgpd starts its process identifier is written to
|
||||
\fB\fIpid-file\fR. The init system uses the recorded PID to stop or
|
||||
restart bgpd. The default is \fB\fI@CFG_STATE@/bgpd.pid\fR.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-bgp_port \fR\fIbgp-port-number\fR
|
||||
Set the port that bgpd will listen to for bgp data.
|
||||
.TP
|
||||
\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR
|
||||
Specify the port that the bgpd VTY will listen on. This defaults to
|
||||
2605, as specified in \fI/etc/services\fR.
|
||||
.TP
|
||||
\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR
|
||||
Specify the address that the bgpd VTY will listen on. Default is all
|
||||
interfaces.
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-user \fR\fIuser\fR
|
||||
Specify the user to run as. Default is \fI@enable_user@\fR.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-retain\fR
|
||||
When the program terminates, retain routes added by \fBbgpd\fR.
|
||||
.TP
|
||||
\fB\-S\fR, \fB\-\-skip_runas\fR
|
||||
Skip setting the process effective user and group.
|
||||
.TP
|
||||
\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR
|
||||
Load a module at startup. May be specified more than once.
|
||||
The \fBsnmp\fR module may be available for
|
||||
\fBbgpd\fR, if the package was built with SNMP support.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Print the version and exit.
|
||||
.SH FILES
|
||||
.TP
|
||||
.BI @CFG_SBIN@/bgpd
|
||||
The default location of the
|
||||
.B bgpd
|
||||
binary.
|
||||
.TP
|
||||
.BI @CFG_SYSCONF@/bgpd.conf
|
||||
The default location of the
|
||||
.B bgpd
|
||||
config file.
|
||||
.TP
|
||||
.BI $(PWD)/bgpd.log
|
||||
If the
|
||||
.B bgpd
|
||||
process is config'd to output logs to a file, then you will find this
|
||||
file in the directory where you started \fBbgpd\fR.
|
||||
.SH WARNING
|
||||
This man page is intended to be a quick reference for command line
|
||||
options. The definitive document is the Info file \fB@PACKAGE_NAME@\fR.
|
||||
.SH DIAGNOSTICS
|
||||
The bgpd process may log to standard output, to a VTY, to a log
|
||||
file, or through syslog to the system logs. \fBbgpd\fR supports many
|
||||
debugging options, see the Info file, or the source for details.
|
||||
.SH "SEE ALSO"
|
||||
.BR ripd (8),
|
||||
.BR ripngd (8),
|
||||
.BR ospfd (8),
|
||||
.BR ospf6d (8),
|
||||
.BR isisd (8),
|
||||
.BR nhrpd (8),
|
||||
.BR zebra (8),
|
||||
.BR vtysh (1)
|
||||
.SH BUGS
|
||||
.B bgpd
|
||||
eats bugs for breakfast. If you have food for the maintainers try
|
||||
.BI @PACKAGE_BUGREPORT@
|
||||
.SH AUTHORS
|
||||
See
|
||||
.BI http://www.zebra.org
|
||||
and
|
||||
.BI @PACKAGE_URL@
|
||||
or the Info file for an accurate list of authors.
|
||||
|
||||
2142
doc/bgpd.texi
2142
doc/bgpd.texi
File diff suppressed because it is too large
Load Diff
557
doc/cli.md
557
doc/cli.md
@ -1,557 +0,0 @@
|
||||
FRR Command Line Interface
|
||||
==========================
|
||||
|
||||
Definition Grammar
|
||||
------------------
|
||||
|
||||
This is a reference for the syntax used when defining new CLI commands. An
|
||||
example definition is:
|
||||
|
||||
```
|
||||
DEFUN (command_name,
|
||||
command_name_cmd,
|
||||
--> "example <command|line [interface]> DEFINITION...",
|
||||
<..doc strings..>)
|
||||
```
|
||||
|
||||
The arrowed part is the definition string.
|
||||
|
||||
Explicit syntax rules in Flex and Bison may be found in lib/command_lex.l and
|
||||
lib/command_parse.y, respectively. If you can read BNF and regex those will be
|
||||
more useful than this document.
|
||||
|
||||
If the parser is throwing syntax or other errors and you can't figure out why,
|
||||
it's unlikely to be a bug in the parser. If the error message is not useful,
|
||||
please file a bug for a better error message. If all else fails, read the token
|
||||
definitions in the lexer source and the Bison BNF in the parser source.
|
||||
|
||||
Characters allowed in each token type:
|
||||
|
||||
Tokens
|
||||
------
|
||||
* `WORD` -- A token that begins with +, -, or a lowercase letter. It is
|
||||
an unchanging part of the command and will only match itself.
|
||||
Example: "show ip bgp", every token is a WORD.
|
||||
* `IPV4` -- 'A.B.C.D', matches an IPv4 address.
|
||||
* `IPV6` -- 'X:X::X:X', matches an IPv6 address.
|
||||
* `IPV4_PREFIX` -- 'A.B.C.D/M', matches an IPv4 prefix in CIDR notation.
|
||||
* `IPV6_PREFIX` -- 'X:X::X:X/M', matches an IPv6 prefix in CIDR notation.
|
||||
* `MAC` -- 'M:A:C', matches a 48-bit mac address
|
||||
* `MAC_PREFIX` -- 'M:A:C/M', matches a 48-bit mac address with a mask
|
||||
* `VARIABLE` -- Begins with a capital letter. Matches any input.
|
||||
* `RANGE` -- Numeric range delimited by parentheses, e.g. (-100 - 100) or
|
||||
(10-20). Will only match numbers in the range.
|
||||
|
||||
Rules
|
||||
-----
|
||||
* `<angle|brackets>` -- Contain sequences of tokens separated by pipes and
|
||||
provide mutual exclusion. Sequences may contain
|
||||
`<mutual|exclusion>` but not as the first token.
|
||||
Disallowed: `"example <<a|b> c|d>"`
|
||||
Allowed: `"example <a c|b c|d>"`
|
||||
* `[square brackets]` -- Contains sequences of tokens that are optional (can be
|
||||
omitted). `[<a|b>]` can be shortened to `[a|b]`.
|
||||
* `{curly|braces}` -- similar to angle brackets, but instead of mutual
|
||||
exclusion, curly braces indicate that one or more of the
|
||||
pipe-separated sequences may be provided in any order.
|
||||
* `VARIADICS...` -- Any token which accepts input (so anything except WORD)
|
||||
and that occurs as the last token of a line may be
|
||||
followed by an ellipsis, which indicates that input
|
||||
matching the token may be repeated an unlimited number
|
||||
of times.
|
||||
* `$name` -- Specify a variable name for the preceding token. See
|
||||
"Variable Names" below.
|
||||
|
||||
Some general notes:
|
||||
|
||||
* Options are allowed at the beginning of the command. The developer is
|
||||
entreated to use these extremely sparingly. They are most useful for
|
||||
implementing the 'no' form of configuration commands. Please think carefully
|
||||
before using them for anything else. There is usually a better solution, even
|
||||
if it is just separating out the command definition into separate ones.
|
||||
|
||||
* The developer should judiciously apply separation of concerns when defining
|
||||
CLI. CLI definitions for two unrelated or vaguely related commands or
|
||||
configuration items should be defined in separate commands. Clarity is
|
||||
preferred over LOC (within reason).
|
||||
|
||||
* The maximum number of space-separated tokens that can be entered is presently
|
||||
limited to 256. Please keep this limit in mind when implementing new CLI.
|
||||
|
||||
Variable Names
|
||||
--------------
|
||||
The parser tries to fill the "varname" field on each token. This can happen
|
||||
either manually or automatically. Manual specifications work by appending
|
||||
`"$name"` after the input specifier:
|
||||
|
||||
```
|
||||
foo bar$cmd WORD$name A.B.C.D$ip
|
||||
```
|
||||
|
||||
Note that you can also assign variable names to fixed input tokens, this can
|
||||
be useful if multiple commands share code. You can also use "$name" after a
|
||||
multiple-choice option:
|
||||
|
||||
```
|
||||
foo bar <A.B.C.D|X:X::X:X>$addr [optionA|optionB]$mode
|
||||
```
|
||||
|
||||
The variable name is in this case assigned to the last token in each of the
|
||||
branches.
|
||||
|
||||
Automatic assignment of variable names works by applying the following rules:
|
||||
|
||||
- manual names always have priority
|
||||
- a "[no]" at the beginning receives "no" as varname on the "no" token
|
||||
- VARIABLE tokens whose text is not "WORD" or "NAME" receive a cleaned lowercase
|
||||
version of the token text as varname, e.g. "ROUTE-MAP" becomes "route_map".
|
||||
- other variable tokens (i.e. everything except "fixed") receive the text of
|
||||
the preceding fixed token as varname, if one can be found. E.g.:
|
||||
"ip route A.B.C.D/M INTERFACE" assigns "route" to the "A.B.C.D/M" token.
|
||||
|
||||
These rules should make it possible to avoid manual varname assignment in 90%
|
||||
of the cases.
|
||||
|
||||
DEFPY
|
||||
-----
|
||||
|
||||
`DEFPY(...)` is an enhanced version of `DEFUN()` which is preprocessed by
|
||||
` python/clidef.py`. The python script parses the command definition string,
|
||||
extracts variable names and types, and generates a C wrapper function that
|
||||
parses the variables and passes them on. This means that in the CLI function
|
||||
body, you will receive additional parameters with appropriate types.
|
||||
|
||||
This is best explained by an example:
|
||||
|
||||
```
|
||||
DEFPY(func, func_cmd, "[no] foo bar A.B.C.D (0-99)$num", "...help...")
|
||||
|
||||
=>
|
||||
|
||||
func(self, vty, argc, argv, /* standard CLI arguments */
|
||||
|
||||
const char *no, /* unparsed "no" */
|
||||
struct in_addr bar, /* parsed IP address */
|
||||
const char *bar_str, /* unparsed IP address */
|
||||
long num, /* parsed num */
|
||||
const char *num_str) /* unparsed num */
|
||||
```
|
||||
|
||||
Note that as documented in the previous section, "bar" is automatically
|
||||
applied as variable name for "A.B.C.D". The python code then detects this
|
||||
is an IP address argument and generates code to parse it into a
|
||||
`struct in_addr`, passing it in `bar`. The raw value is passed in `bar_str`.
|
||||
The range/number argument works in the same way with the explicitly given
|
||||
variable name.
|
||||
|
||||
### Type rules
|
||||
|
||||
| Token(s) | Type | Value if omitted by user |
|
||||
|--------------------------|-------------|--------------------------|
|
||||
| `A.B.C.D` | `struct in_addr` | 0.0.0.0 |
|
||||
| `X:X::X:X` | `struct in6_addr` | :: |
|
||||
| `A.B.C.D + X:X::X:X` | `const union sockunion *` | NULL |
|
||||
| `A.B.C.D/M` | `const struct prefix_ipv4 *` | NULL |
|
||||
| `X:X::X:X/M` | `const struct prefix_ipv6 *` | NULL |
|
||||
| `A.B.C.D/M + X:X::X:X/M` | `const struct prefix *` | NULL |
|
||||
| `(0-9)` | `long` | 0 |
|
||||
| `VARIABLE` | `const char *` | NULL |
|
||||
| `word` | `const char *` | NULL |
|
||||
| _all other_ | `const char *` | NULL |
|
||||
|
||||
Note the following details:
|
||||
|
||||
* not all parameters are pointers, some are passed as values.
|
||||
* when the type is not `const char *`, there will be an extra `_str` argument
|
||||
with type `const char *`.
|
||||
* you can give a variable name not only to `VARIABLE` tokens but also to
|
||||
`word` tokens (e.g. constant words). This is useful if some parts of a
|
||||
command are optional. The type will be `const char *`.
|
||||
* `[no]` will be passed as `const char *no`.
|
||||
* pointers will be NULL when the argument is optional and the user did not
|
||||
use it.
|
||||
* if a parameter is not a pointer, but is optional and the user didn't use it,
|
||||
the default value will be passed. Check the `_str` argument if you need to
|
||||
determine whether the parameter was omitted.
|
||||
* if the definition contains multiple parameters with the same variable name,
|
||||
they will be collapsed into a single function parameter. The python code
|
||||
will detect if the types are compatible (i.e. IPv4 + IPv6 variantes) and
|
||||
choose a corresponding C type.
|
||||
* the standard DEFUN parameters (self, vty, argc, argv) are still present and
|
||||
can be used. A DEFUN can simply be **edited into a DEFPY without further
|
||||
changes and it will still work**; this allows easy forward migration.
|
||||
* a file may contain both DEFUN and DEFPY statements.
|
||||
|
||||
### Getting a parameter dump
|
||||
|
||||
The clidef.py script can be called to get a list of DEFUNs/DEFPYs with
|
||||
the parameter name/type list:
|
||||
|
||||
```
|
||||
lib/clippy python/clidef.py --all-defun --show lib/plist.c > /dev/null
|
||||
```
|
||||
|
||||
The generated code is printed to stdout, the info dump to stderr. The
|
||||
`--all-defun` argument will make it process DEFUN blocks as well as DEFPYs,
|
||||
which is useful prior to converting some DEFUNs. **The dump does not list
|
||||
the `_str` arguments** to keep the output shorter.
|
||||
|
||||
Note that the clidef.py script cannot be run with python directly, it needs
|
||||
to be run with _clippy_ since the latter makes the CLI parser available.
|
||||
|
||||
### Include & Makefile requirements
|
||||
|
||||
A source file that uses DEFPY needs to include the `_clippy.c` file **before
|
||||
all DEFPY statements**:
|
||||
|
||||
```
|
||||
/* GPL header */
|
||||
#include ...
|
||||
|
||||
...
|
||||
|
||||
#include "daemon/filename_clippy.c"
|
||||
|
||||
DEFPY(...)
|
||||
DEFPY(...)
|
||||
|
||||
install_element(...)
|
||||
```
|
||||
|
||||
This dependency needs to be marked in Makefile.am: (there is no ordering
|
||||
requirement)
|
||||
|
||||
```
|
||||
include ../common.am
|
||||
|
||||
# ...
|
||||
|
||||
# if linked into a LTLIBRARY (.la/.so):
|
||||
filename.lo: filename_clippy.c
|
||||
|
||||
# if linked into an executable or static library (.a):
|
||||
filename.o: filename_clippy.c
|
||||
```
|
||||
|
||||
Doc Strings
|
||||
-----------
|
||||
Each token in a command definition should be documented with a brief doc
|
||||
string that informs a user of the meaning and/or purpose of the subsequent
|
||||
command tree. These strings are provided as the last parameter to DEFUN macros,
|
||||
concatenated together and separated by an escaped newline ('\n'). These are
|
||||
best explained by example.
|
||||
|
||||
```
|
||||
DEFUN (config_terminal,
|
||||
config_terminal_cmd,
|
||||
"configure terminal",
|
||||
"Configuration from vty interface\n"
|
||||
"Configuration terminal\n")
|
||||
```
|
||||
|
||||
The last parameter is split into two lines for readability. Two newline
|
||||
delimited doc strings are present, one for each token in the command. The
|
||||
second string documents the functionality of the 'terminal' command in the
|
||||
'configure' tree.
|
||||
|
||||
Note that the first string, for 'configure' does not contain documentation for
|
||||
'terminal'. This is because the CLI is best envisioned as a tree, with tokens
|
||||
defining branches. An imaginary 'start' token is the root of every command in a
|
||||
CLI node. Each subsequent written token descends into a subtree, so the
|
||||
documentation for that token ideally summarizes all the functionality contained
|
||||
in the subtree.
|
||||
|
||||
A consequence of this structure is that the developer must be careful to use
|
||||
the same doc strings when defining multiple commands that are part of the same
|
||||
tree. Commands which share prefixes must share the same doc strings for those
|
||||
prefixes. On startup the parser will generate warnings if it notices
|
||||
inconsistent doc strings. Behavior is undefined; the same token may show up
|
||||
twice in completions, with different doc strings, or it may show up once with a
|
||||
random doc string. Parser warnings should be heeded and fixed to avoid
|
||||
confusing users.
|
||||
|
||||
The number of doc strings provided must be equal to the amount of tokens
|
||||
present in the command definition, read left to right, ignoring any special
|
||||
constructs.
|
||||
|
||||
In the examples below, each arrowed token needs a doc string.
|
||||
|
||||
```
|
||||
"show ip bgp"
|
||||
^ ^ ^
|
||||
|
||||
"command <foo|bar> [example]"
|
||||
^ ^ ^ ^
|
||||
```
|
||||
|
||||
Data Structures
|
||||
---------------
|
||||
On startup, the CLI parser sequentially parses each command string definition
|
||||
and constructs a directed graph with each token forming a node. This graph is
|
||||
the basis of the entire CLI system. It is used to match user input in order to
|
||||
generate command completions and match commands to functions.
|
||||
|
||||
There is one graph per CLI node (not the same as a graph node in the CLI
|
||||
graph). The CLI node struct keeps a reference to its graph (see lib/command.h).
|
||||
|
||||
While most of the graph maintains the form of a tree, special constructs
|
||||
outlined in the Rules section introduce some quirks. <>, [] and {} form
|
||||
self-contained 'subgraphs'. Each subgraph is a tree except that all of the
|
||||
'leaves' actually share a child node. This helps with minimizing graph size and
|
||||
debugging.
|
||||
|
||||
As an example, the subgraph generated by <foo|bar> looks like this:
|
||||
|
||||
.
|
||||
.
|
||||
|
|
||||
+----+---+
|
||||
+--- -+ FORK +----+
|
||||
| +--------+ |
|
||||
+--v---+ +--v---+
|
||||
| foo | | bar |
|
||||
+--+---+ +--+---+
|
||||
| +------+ |
|
||||
+------> JOIN <-----+
|
||||
+---+--+
|
||||
|
|
||||
.
|
||||
.
|
||||
|
||||
FORK and JOIN nodes are plumbing nodes that don't correspond to user input.
|
||||
They're necessary in order to deduplicate these constructs where applicable.
|
||||
|
||||
Options follow the same form, except that there is an edge from the FORK node
|
||||
to the JOIN node.
|
||||
|
||||
Keywords follow the same form, except that there is an edge from JOIN to FORK.
|
||||
Because of this the CLI graph cannot be called acyclic. There is special logic
|
||||
in the input matching code that keeps a stack of paths already taken through
|
||||
the node in order to disallow following the same path more than once.
|
||||
|
||||
Variadics are a bit special; they have an edge back to themselves, which allows
|
||||
repeating the same input indefinitely.
|
||||
|
||||
The leaves of the graph are nodes that have no out edges. These nodes are
|
||||
special; their data section does not contain a token, as most nodes do, or
|
||||
NULL, as in FORK/JOIN nodes, but instead has a pointer to a cmd_element. All
|
||||
paths through the graph that terminate on a leaf are guaranteed to be defined
|
||||
by that command. When a user enters a complete command, the command matcher
|
||||
tokenizes the input and executes a DFS on the CLI graph. If it is
|
||||
simultaneously able to exhaust all input (one input token per graph node), and
|
||||
then find exactly one leaf connected to the last node it reaches, then the
|
||||
input has matched the corresponding command and the command is executed. If it
|
||||
finds more than one node, then the command is ambiguous (more on this in
|
||||
deduplication). If it cannot exhaust all input, the command is unknown. If it
|
||||
exhausts all input but does not find an edge node, the command is incomplete.
|
||||
|
||||
The parser uses an incremental strategy to build the CLI graph for a node. Each
|
||||
command is parsed into its own graph, and then this graph is merged into the
|
||||
overall graph. During this merge step, the parser makes a best-effort attempt
|
||||
to remove duplicate nodes. If it finds a node in the overall graph that is
|
||||
equal to a node in the corresponding position in the command graph, it will
|
||||
intelligently merge the properties from the node in the command graph into the
|
||||
already-existing node. Subgraphs are also checked for isomorphism and merged
|
||||
where possible. The definition of whether two nodes are 'equal' is based on the
|
||||
equality of some set of token properties; read the parser source for the most
|
||||
up-to-date definition of equality.
|
||||
|
||||
When the parser is unable to deduplicate some complicated constructs, this
|
||||
can result in two identical paths through separate parts of the graph. If
|
||||
this occurs and the user enters input that matches these paths, they will
|
||||
receive an 'ambiguous command' error and will be unable to execute the command.
|
||||
Most of the time the parser can detect and warn about duplicate commands, but
|
||||
it will not always be able to do this. Hence care should be taken before
|
||||
defining a new command to ensure it is not defined elsewhere.
|
||||
|
||||
|
||||
Command handlers
|
||||
----------------
|
||||
The block that follows a CLI definition is executed when a user enters input
|
||||
that matches the definition. Its function signature looks like this:
|
||||
|
||||
int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
|
||||
|
||||
The first argument is the command definition struct. The last argument is an
|
||||
ordered array of tokens that correspond to the path taken through the graph,
|
||||
and the argument just prior to that is the length of the array.
|
||||
|
||||
The arrangement of the token array has changed from the prior incarnation of
|
||||
the CLI system. In the old system, missing arguments were padded with NULLs so
|
||||
that the same parts of a command would show up at the same indices regardless
|
||||
of what was entered. The new system does not perform such padding and therefore
|
||||
it is generally _incorrect_ to assume consistent indices in this array. As a
|
||||
simple example:
|
||||
|
||||
Command definition:
|
||||
```
|
||||
command [foo] <bar|baz>
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
command foo bar
|
||||
```
|
||||
|
||||
Array:
|
||||
```
|
||||
[0] -> command
|
||||
[1] -> foo
|
||||
[2] -> bar
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
command baz
|
||||
```
|
||||
|
||||
Array:
|
||||
```
|
||||
[0] -> command
|
||||
[1] -> baz
|
||||
```
|
||||
|
||||
|
||||
|
||||
Command abbreviation & matching priority
|
||||
----------------------------------------
|
||||
As in the prior implementation, it is possible for users to elide parts of
|
||||
tokens when the CLI matcher does not need them to make an unambiguous match.
|
||||
This is best explained by example.
|
||||
|
||||
Command definitions:
|
||||
```
|
||||
command dog cow
|
||||
command dog crow
|
||||
```
|
||||
|
||||
User input:
|
||||
```
|
||||
c d c -> ambiguous command
|
||||
c d co -> match "command dog cow"
|
||||
```
|
||||
|
||||
In the new implementation, this functionality has improved. Where previously
|
||||
the parser would stop at the first ambiguous token, it will now look ahead and
|
||||
attempt to disambiguate based on tokens later on in the input string.
|
||||
|
||||
Command definitions:
|
||||
```
|
||||
show ip bgp A.B.C.D
|
||||
show ipv6 bgp X:X::X:X
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
s i b 4.3.2.1 -> match "show ip bgp A.B.C.D"
|
||||
s i b ::e0 -> match "show ipv6 bgp X:X::X:X"
|
||||
```
|
||||
|
||||
Previously both of these commands would be ambiguous since 'i' does not
|
||||
explicitly select either 'ip' or 'ipv6'. However, since the user later provides
|
||||
a token that matches only one of the commands (an IPv4 or IPv6 address) the
|
||||
parser is able to look ahead and select the appropriate command. This has some
|
||||
implications for parsing the argv*[] that is passed to the command handler.
|
||||
|
||||
Now consider a command definition such as:
|
||||
```
|
||||
command <foo|VAR>
|
||||
```
|
||||
|
||||
'foo' only matches the string 'foo', but 'VAR' matches any input, including
|
||||
'foo'. Who wins? In situations like this the matcher will always choose the
|
||||
'better' match, so 'foo' will win.
|
||||
|
||||
Consider also:
|
||||
```
|
||||
show <ip|ipv6> foo
|
||||
```
|
||||
|
||||
User input:
|
||||
```
|
||||
show ip foo
|
||||
```
|
||||
|
||||
'ip' partially matches 'ipv6' but exactly matches 'ip', so 'ip' will win.
|
||||
|
||||
|
||||
struct cmd_token
|
||||
----------------
|
||||
|
||||
```
|
||||
/* Command token struct. */
|
||||
struct cmd_token
|
||||
{
|
||||
enum cmd_token_type type; // token type
|
||||
u_char attr; // token attributes
|
||||
bool allowrepeat; // matcher allowed to match token repetitively?
|
||||
|
||||
char *text; // token text
|
||||
char *desc; // token description
|
||||
long long min, max; // for ranges
|
||||
char *arg; // user input that matches this token
|
||||
char *varname; // variable name
|
||||
};
|
||||
```
|
||||
|
||||
This struct is used in the CLI graph to match input against. It is also used to
|
||||
pass user input to command handler functions, as it is frequently useful for
|
||||
handlers to have access to that information. When a command is matched, the
|
||||
sequence of cmd_tokens that form the matching path are duplicated and placed in
|
||||
order into argv*[]. Before this happens the ->arg field is set to point at the
|
||||
snippet of user input that matched it.
|
||||
|
||||
For most nontrivial commands the handler function will need to determine which
|
||||
of the possible matching inputs was entered. Previously this was done by
|
||||
looking at the first few characters of input. This is now considered an
|
||||
anti-pattern and should be avoided. Instead, the ->type or ->text fields for
|
||||
this logic. The ->type field can be used when the possible inputs differ in
|
||||
type. When the possible types are the same, use the ->text field. This field
|
||||
has the full text of the corresponding token in the definition string and using
|
||||
it makes for much more readable code. An example is helpful.
|
||||
|
||||
Command definition:
|
||||
```
|
||||
command <(1-10)|foo|BAR>
|
||||
```
|
||||
|
||||
In this example, the user may enter any one of:
|
||||
* an integer between 1 and 10
|
||||
* "foo"
|
||||
* anything at all
|
||||
|
||||
If the user enters "command f", then:
|
||||
|
||||
```
|
||||
argv[1]->type == WORD_TKN
|
||||
argv[1]->arg == "f"
|
||||
argv[1]->text == "foo"
|
||||
```
|
||||
|
||||
Range tokens have some special treatment; a token with ->type == RANGE_TKN will
|
||||
have the ->min and ->max fields set to the bounding values of the range.
|
||||
|
||||
|
||||
Permutations
|
||||
------------
|
||||
Finally, it is sometimes useful to check all the possible combinations of input
|
||||
that would match an arbitrary definition string. There is a tool in tools/
|
||||
called 'permutations' that reads CLI definition strings on stdin and prints out
|
||||
all matching input permutations. It also dumps a text representation of the
|
||||
graph, which is more useful for debugging than anything else. It looks like
|
||||
this:
|
||||
|
||||
```
|
||||
$ ./permutations "show [ip] bgp [<view|vrf> WORD]"
|
||||
|
||||
show ip bgp view WORD
|
||||
show ip bgp vrf WORD
|
||||
show ip bgp
|
||||
show bgp view WORD
|
||||
show bgp vrf WORD
|
||||
show bgp
|
||||
```
|
||||
|
||||
This functionality is also built into VTY/VTYSH; the 'list permutations'
|
||||
command will list all possible matching input permutations in the current CLI
|
||||
node.
|
||||
@ -1,21 +0,0 @@
|
||||
@c -*- texinfo -*-
|
||||
@c @configure_input@
|
||||
|
||||
@c Set variables
|
||||
@set PACKAGE_NAME @PACKAGE_NAME@
|
||||
@set PACKAGE_TARNAME @PACKAGE_TARNAME@
|
||||
@set PACKAGE_STRING @PACKAGE_STRING@
|
||||
@set PACKAGE_URL @PACKAGE_URL@
|
||||
@set PACKAGE_VERSION @PACKAGE_VERSION@
|
||||
@set AUTHORS Kunihiro Ishiguro, et al.
|
||||
@set COPYRIGHT_YEAR 1999-2005
|
||||
@set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS}
|
||||
|
||||
@c These may vary with installation environment.
|
||||
@set INSTALL_PREFIX_ETC @CFG_SYSCONF@
|
||||
@set INSTALL_PREFIX_SBIN @CFG_SBIN@
|
||||
@set INSTALL_PREFIX_STATE @CFG_STATE@
|
||||
@set INSTALL_PREFIX_MODULES @CFG_MODULE@
|
||||
@set INSTALL_USER @enable_user@
|
||||
@set INSTALL_GROUP @enable_group@
|
||||
@set INSTALL_VTY_GROUP @enable_vty_group@
|
||||
@ -1,119 +0,0 @@
|
||||
# Module and Hook support (developer docs)
|
||||
|
||||
## What it does
|
||||
|
||||
It uses `dlopen()` to load DSOs at startup.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
* can't load, unload, or reload during runtime. This just needs some work
|
||||
and can probably be done in the future.
|
||||
* doesn't fix any of the "things need to be changed in the code in the library"
|
||||
issues. Most prominently, you can't add a CLI node because CLI nodes are
|
||||
listed in the library...
|
||||
* if your module crashes, the daemon crashes. Should be obvious.
|
||||
* **does not provide a stable API or ABI**. Your module must match a version
|
||||
of FRR and you may have to update it frequently to match changes.
|
||||
* **does not create a license boundary**. Your module will need to link
|
||||
libzebra and include header files from the daemons, meaning it will be
|
||||
GPL-encumbered.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Look for `moduledir` in `configure.ac`, default is normally
|
||||
`/usr/lib64/frr/modules` but depends on `--libdir` / `--prefix`.
|
||||
|
||||
The daemon's name is prepended when looking for a module, e.g. "snmp" tries
|
||||
to find "zebra_snmp" first when used in zebra. This is just to make it nicer
|
||||
for the user, with the snmp module having the same name everywhere.
|
||||
|
||||
Modules can be packaged separately from FRR. The SNMP and FPM modules are
|
||||
good candidates for this because they have dependencies (net-snmp / protobuf)
|
||||
that are not FRR dependencies. However, any distro packages should have an
|
||||
"exact-match" dependency onto the FRR package. Using a module from a
|
||||
different FRR version will probably blow up nicely.
|
||||
|
||||
For snapcraft (and during development), modules can be loaded with full path
|
||||
(e.g. -M `$SNAP/lib/frr/modules/zebra_snmp.so`). Note that libtool puts output
|
||||
files in the .libs directory, so during development you have to use
|
||||
`./zebra -M .libs/zebra_snmp.so`.
|
||||
|
||||
|
||||
## Creating a module
|
||||
|
||||
... best to look at the existing SNMP or FPM modules.
|
||||
|
||||
Basic boilerplate:
|
||||
|
||||
```
|
||||
#include "hook.h"
|
||||
#include "module.h"
|
||||
|
||||
static int
|
||||
module_init (void)
|
||||
{
|
||||
hook_register(frr_late_init, module_late_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FRR_MODULE_SETUP(
|
||||
.name = "my module",
|
||||
.version = "0.0",
|
||||
.description = "my module",
|
||||
.init = module_init,
|
||||
)
|
||||
```
|
||||
|
||||
The `frr_late_init` hook will be called after the daemon has finished its
|
||||
other startup and is about to enter the main event loop; this is the best
|
||||
place for most initialisation.
|
||||
|
||||
|
||||
## Compiler & Linker magic
|
||||
|
||||
There's a `THIS_MODULE` (like in the Linux kernel), which uses `visibility`
|
||||
attributes to restrict it to the current module. If you get a linker error
|
||||
with `_frrmod_this_module`, there is some linker SNAFU. This shouldn't be
|
||||
possible, though one way to get it would be to not include libzebra (which
|
||||
provides a fallback definition for the symbol).
|
||||
|
||||
libzebra and the daemons each have their own `THIS_MODULE`, as do all loadable
|
||||
modules. In any other libraries (e.g. `libfrrsnmp`), `THIS_MODULE` will use
|
||||
the definition in libzebra; same applies if the main executable doesn't use
|
||||
`FRR_DAEMON_INFO` (e.g. all testcases).
|
||||
|
||||
The deciding factor here is "what dynamic linker unit are you using the symbol
|
||||
from." If you're in a library function and want to know who called you, you
|
||||
can't use `THIS_MODULE` (because that'll just tell you you're in the library).
|
||||
Put a macro around your function that adds `THIS_MODULE` in the *caller's
|
||||
code calling your function*.
|
||||
|
||||
The idea is to use this in the future for module unloading. Hooks already
|
||||
remember which module they were installed by, as groundwork for a function
|
||||
that removes all of a module's installed hooks.
|
||||
|
||||
There's also the `frr_module` symbol in modules, pretty much a standard entry
|
||||
point for loadable modules.
|
||||
|
||||
|
||||
## Hooks
|
||||
|
||||
Hooks are just points in the code where you can register your callback to
|
||||
be called. The parameter list is specific to the hook point. Since there is
|
||||
no stable API, the hook code has some extra type safety checks making sure
|
||||
you get a compiler warning when the hook parameter list doesn't match your
|
||||
callback. Don't ignore these warnings.
|
||||
|
||||
|
||||
## Relation to MTYPE macros
|
||||
|
||||
The MTYPE macros, while primarily designed to decouple MTYPEs from the library
|
||||
and beautify the code, also work very nicely with loadable modules -- both
|
||||
constructors and destructors are executed when loading/unloading modules.
|
||||
|
||||
This means there is absolutely no change required to MTYPEs, you can just use
|
||||
them in a module and they will even clean up themselves when we implement
|
||||
module unloading and an unload happens. In fact, it's impossible to create
|
||||
a bug where unloading fails to de-register a MTYPE.
|
||||
1
doc/developer/Makefile
Normal file
1
doc/developer/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../frr-sphinx.mk
|
||||
28
doc/developer/bgp-typecodes.rst
Normal file
28
doc/developer/bgp-typecodes.rst
Normal file
@ -0,0 +1,28 @@
|
||||
BGP-4[+] UPDATE Attribute Preprocessor Constants
|
||||
================================================
|
||||
|
||||
This is a list of preprocessor constants that map to BGP attributes defined by
|
||||
various BGP RFCs. In the code these are defined as BGP_ATTR_<ATTR>.
|
||||
|
||||
+-------+------------------+------------------------------------------+
|
||||
| Value | Attribute | References |
|
||||
+=======+==================+==========================================+
|
||||
| 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 4456] |
|
||||
| 10 | CLUSTER_LIST | [RFC 4456] |
|
||||
| 11 | DPA | [draft-ietf-idr-bgp-dpa-05.txt(expired)] |
|
||||
| 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] |
|
||||
+-------+------------------+------------------------------------------+
|
||||
11
doc/developer/bgpd.rst
Normal file
11
doc/developer/bgpd.rst
Normal file
@ -0,0 +1,11 @@
|
||||
.. _bgpd:
|
||||
|
||||
****
|
||||
BGPD
|
||||
****
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
next-hop-tracking
|
||||
bgp-typecodes
|
||||
59
doc/developer/building-frr-on-alpine.rst
Normal file
59
doc/developer/building-frr-on-alpine.rst
Normal file
@ -0,0 +1,59 @@
|
||||
Building FRR dev packages on Alpine Linux from Git Source
|
||||
=========================================================
|
||||
|
||||
For building Alpine Linux dev packages, we use docker.
|
||||
|
||||
Install docker 17.05 or later
|
||||
-----------------------------
|
||||
|
||||
Depending on your host, there are different ways of installing docker. Refer
|
||||
to the documentation here for instructions on how to install a free version of
|
||||
docker: https://www.docker.com/community-edition
|
||||
|
||||
Work with sources
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
|
||||
Build apk packages
|
||||
------------------
|
||||
|
||||
::
|
||||
|
||||
./docker/alpine/build.sh
|
||||
|
||||
This will put the apk packages in:
|
||||
|
||||
::
|
||||
|
||||
./docker/pkgs/apk/x86_64/
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To add the packages to a docker image, create a Dockerfile in ./docker/pkgs:
|
||||
|
||||
::
|
||||
|
||||
FROM alpine:3.7
|
||||
RUN mkdir -p /pkgs
|
||||
ADD apk/ /pkgs/
|
||||
RUN apk add --no-cache --allow-untrusted /pkgs/x86_64/*.apk
|
||||
|
||||
And build a docker image:
|
||||
|
||||
::
|
||||
|
||||
docker build --rm --force-rm -t alpine-dev-pkgs:latest docker/pkgs
|
||||
|
||||
And run the image:
|
||||
|
||||
::
|
||||
|
||||
docker run -it --rm alpine-dev-pkgs:latest /bin/sh
|
||||
|
||||
Currently, we only package the raw daemons and example files, so, you'll
|
||||
need to run the daemons by hand (or, better, orchestrate in the Dockerfile).
|
||||
@ -1,46 +1,67 @@
|
||||
Building FRR on CentOS 6 from Git Source
|
||||
CentOS 6
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
Instructions are tested with `CentOS 6.8` on `x86_64` platform
|
||||
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
|
||||
|
||||
Warning:
|
||||
--------
|
||||
``CentOS 6`` is very old and not fully supported by the FRR community
|
||||
anymore. Building FRR takes multiple manual steps to update the build
|
||||
system with newer packages than what's available from the archives.
|
||||
However, the built packages can still be installed afterwards on
|
||||
a standard ``CentOS 6`` without any special packages.
|
||||
|
||||
Support for CentOS 6 is now on a best-effort base by the community.
|
||||
|
||||
CentOS 6 restrictions:
|
||||
----------------------
|
||||
|
||||
- PIMd is not supported on `CentOS 6`. Upgrade to `CentOS 7` if PIMd is
|
||||
needed
|
||||
- MPLS is not supported on `CentOS 6`. MPLS requires Linux Kernel 4.5 or
|
||||
higher (LDP can be built, but may have limited use without MPLS)
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||
with (IFLA_INFO_SLAVE_KIND does not exist in the kernel headers, you
|
||||
can use a newer kernel + headers to get this functionality)
|
||||
- frr_reload.py will not work, as this requires Python 2.7, and CentOS 6
|
||||
only has 2.6. You can install Python 2.7 via IUS, but it won't work
|
||||
properly unless you compile and install the ipaddr package for it.
|
||||
- PIMd is not supported on ``CentOS 6``. Upgrade to ``CentOS 7`` if
|
||||
PIMd is needed
|
||||
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
|
||||
or higher (LDP can be built, but may have limited use without MPLS)
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
|
||||
you can use a newer kernel + headers to get this functionality)
|
||||
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
|
||||
6 only has 2.6. You can install Python 2.7 via IUS, but it won't work
|
||||
properly unless you compile and install the ipaddr package for it.
|
||||
- Building the package requires Sphinx >= 1.1. Only a non-standard
|
||||
package provides a newer sphinx and requires manual installation
|
||||
(see below)
|
||||
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo yum install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel flex epel-release perl-XML-LibXML \
|
||||
c-ares-devel
|
||||
|
||||
Install newer version of bison (CentOS 6 package source is too old) from
|
||||
Install newer version of bison (CentOS 6 package source is too old) from
|
||||
CentOS 7
|
||||
|
||||
::
|
||||
|
||||
sudo yum install rpm-build
|
||||
curl -O http://vault.centos.org/7.0.1406/os/Source/SPackages/bison-2.7-4.el7.src.rpm
|
||||
rpmbuild --rebuild ./bison-2.7-4.el7.src.rpm
|
||||
sudo yum install ./rpmbuild/RPMS/x86_64/bison-2.7-4.el6.x86_64.rpm
|
||||
rm -rf rpmbuild
|
||||
|
||||
Install newer version of autoconf and automake (Package versions are too old)
|
||||
Install newer version of autoconf and automake (Package versions are too
|
||||
old)
|
||||
|
||||
::
|
||||
|
||||
curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
||||
tar xvf autoconf-2.69.tar.gz
|
||||
@ -49,7 +70,7 @@ Install newer version of autoconf and automake (Package versions are too old)
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
|
||||
curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
|
||||
tar xvf automake-1.15.tar.gz
|
||||
cd automake-1.15
|
||||
@ -58,35 +79,69 @@ Install newer version of autoconf and automake (Package versions are too old)
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
Install `Python 2.7` in parallel to default 2.6.
|
||||
Make sure you've install EPEL (`epel-release` as above). Then install current
|
||||
`python27`, `python27-devel` and `pytest`
|
||||
Install ``Python 2.7`` in parallel to default 2.6. Make sure you've
|
||||
install EPEL (``epel-release`` as above). Then install current
|
||||
``python27``, ``python27-devel`` and ``pytest``
|
||||
|
||||
::
|
||||
|
||||
sudo rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
|
||||
sudo rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
|
||||
sudo yum install python27 python27-pip python27-devel
|
||||
sudo pip2.7 install pytest
|
||||
|
||||
Please note that `CentOS 6` needs to keep python pointing to version 2.6
|
||||
for `yum` to keep working, so don't create a symlink for python2.7 to python
|
||||
Please note that ``CentOS 6`` needs to keep python pointing to version
|
||||
2.6 for ``yum`` to keep working, so don't create a symlink for python2.7
|
||||
to python
|
||||
|
||||
Install newer ``Sphinx-Build`` based on ``Python 2.7``
|
||||
|
||||
Create a new repo ``/etc/yum.repos.d/puias6.repo`` with the following contents:
|
||||
|
||||
::
|
||||
|
||||
### Name: RPM Repository for RHEL 6 - PUIAS (used for Sphinx-Build)
|
||||
### URL: http://springdale.math.ias.edu/data/puias/computational
|
||||
[puias-computational]
|
||||
name = RPM Repository for RHEL 6 - Sphinx-Build
|
||||
baseurl = http://springdale.math.ias.edu/data/puias/computational/$releasever/$basearch
|
||||
#mirrorlist =
|
||||
enabled = 1
|
||||
protect = 0
|
||||
gpgkey =
|
||||
gpgcheck = 0
|
||||
|
||||
Update rpm database & Install newer sphinx
|
||||
|
||||
::
|
||||
|
||||
sudo yum update
|
||||
sudo yum install python27-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
(You may prefer different options on configure statement. These are just
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -116,11 +171,15 @@ an example.)
|
||||
--enable-babeld \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check PYTHON=/usr/bin/python2.7
|
||||
sudo make install
|
||||
make SPHINXBUILD=sphinx-build2.7
|
||||
make check PYTHON=/usr/bin/python2.7 SPHINXBUILD=sphinx-build2.7
|
||||
sudo make SPHINXBUILD=sphinx-build2.7 install
|
||||
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
### Create empty FRR configuration files
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -138,20 +197,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and set the following values (ignore the other
|
||||
Edit ``/etc/sysctl.conf`` and set the following values (ignore the other
|
||||
settings)
|
||||
|
||||
::
|
||||
|
||||
# Controls IP packet forwarding
|
||||
net.ipv4.ip_forward = 1
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
@ -161,14 +228,28 @@ settings)
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
### Add init.d startup files
|
||||
Add init.d startup files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 755 redhat/frr.init /etc/init.d/frr
|
||||
sudo chkconfig --add frr
|
||||
|
||||
### Enable frr daemon at startup
|
||||
Enable frr daemon at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo chkconfig frr on
|
||||
|
||||
### Start FRR manually (or reboot)
|
||||
Start FRR manually (or reboot)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo /etc/init.d/frr start
|
||||
@ -1,44 +1,53 @@
|
||||
Building FRR on CentOS 7 from Git Source
|
||||
CentOS 7
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
CentOS 7 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `CentOS 7` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
|
||||
- MPLS is not supported on ``CentOS 7`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo yum install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel bison flex pytest c-ares-devel \
|
||||
perl-XML-LibXML python-devel
|
||||
perl-XML-LibXML python-devel systemd-devel python-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
(You may prefer different options on configure statement. These are just
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -59,6 +68,7 @@ an example.)
|
||||
--enable-group=frr \
|
||||
--enable-vty-group=frrvt \
|
||||
--enable-rtadv \
|
||||
--enable-systemd=yes \
|
||||
--disable-exampledir \
|
||||
--enable-watchfrr \
|
||||
--disable-ldpd \
|
||||
@ -72,7 +82,11 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -91,20 +105,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the
|
||||
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
|
||||
following content:
|
||||
|
||||
::
|
||||
|
||||
# Sysctl for routing
|
||||
#
|
||||
# Routing: We need to forward packets
|
||||
@ -113,17 +135,35 @@ following content:
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
### Install frr Service and redhat init files
|
||||
Install frr Service and redhat init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
||||
|
||||
### Register the systemd files
|
||||
Register the systemd files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl preset frr.service
|
||||
|
||||
### Enable required frr at startup
|
||||
|
||||
Enable required frr at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl enable frr
|
||||
|
||||
### Reboot or start FRR manually
|
||||
Reboot or start FRR manually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start frr
|
||||
@ -1,33 +1,40 @@
|
||||
Building FRR on Debian 8 from Git Source
|
||||
Debian 8
|
||||
========================================
|
||||
|
||||
Debian 8 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `Debian 8` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
- MPLS is not supported on ``Debian 8`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install git autoconf automake libtool make gawk \
|
||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
||||
python-pip libc-ares-dev python3-dev
|
||||
python-pip libc-ares-dev python3-dev python3-sphinx
|
||||
|
||||
Install newer pytest (>3.0) from pip
|
||||
Install newer pytest (>3.0) from pip
|
||||
|
||||
sudo pip install pytest
|
||||
::
|
||||
|
||||
sudo pip install pytest
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo addgroup --system --gid 92 frr
|
||||
sudo addgroup --system --gid 85 frrvty
|
||||
@ -35,10 +42,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /bin/false frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -63,12 +74,15 @@ an example.)
|
||||
--enable-fpm \
|
||||
--enable-ldpd \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
@ -84,11 +98,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -97,35 +114,43 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
### Troubleshooting
|
||||
Troubleshooting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
**Local state directory**
|
||||
|
||||
The local state directory must exist and have the correct permissions applied
|
||||
for the frrouting daemons to start. In the above ./configure example the
|
||||
local state directory is set to /var/run/frr (--localstatedir=/var/run/frr)
|
||||
Debian considers /var/run/frr to be temporary and this is removed after a
|
||||
reboot.
|
||||
The local state directory must exist and have the correct permissions
|
||||
applied for the frrouting daemons to start. In the above ./configure
|
||||
example the local state directory is set to /var/run/frr
|
||||
(--localstatedir=/var/run/frr) Debian considers /var/run/frr to be
|
||||
temporary and this is removed after a reboot.
|
||||
|
||||
When using a different local state directory you need to create the new
|
||||
directory and change the ownership to the frr user, for example:
|
||||
|
||||
::
|
||||
|
||||
mkdir /var/opt/frr
|
||||
chown frr /var/opt/frr
|
||||
|
||||
**Shared library error**
|
||||
|
||||
If you try and start any of the frrouting daemons you may see the below error
|
||||
due to the frrouting shared library directory not being found:
|
||||
If you try and start any of the frrouting daemons you may see the below
|
||||
error due to the frrouting shared library directory not being found:
|
||||
|
||||
::
|
||||
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open shared object file: No such file or directory
|
||||
|
||||
The fix is to add the following line to /etc/ld.so.conf which will continue to
|
||||
reference the library directory after the system reboots. To load the library
|
||||
directory path immediately run the ldconfig command after adding the line to
|
||||
the file eg:
|
||||
The fix is to add the following line to /etc/ld.so.conf which will
|
||||
continue to reference the library directory after the system reboots. To
|
||||
load the library directory path immediately run the ldconfig command
|
||||
after adding the line to the file eg:
|
||||
|
||||
::
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
||||
@ -1,4 +1,4 @@
|
||||
Building FRR on Debian 9 from Git Source
|
||||
Debian 9
|
||||
========================================
|
||||
|
||||
Install required packages
|
||||
@ -6,17 +6,22 @@ Install required packages
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install git autoconf automake libtool make \
|
||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
||||
python-pip libc-ares-dev python3-dev python-pytest
|
||||
python-pip libc-ares-dev python3-dev python-pytest python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo addgroup --system --gid 92 frr
|
||||
sudo addgroup --system --gid 85 frrvty
|
||||
@ -24,10 +29,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /bin/false frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
git checkout stable/3.0
|
||||
@ -53,12 +62,15 @@ an example.)
|
||||
--enable-fpm \
|
||||
--enable-ldpd \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 755 -o frr -g frr -d /var/opt/frr
|
||||
@ -75,11 +87,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -88,21 +103,29 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
### Troubleshooting
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
**Shared library error**
|
||||
Shared library error
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you try and start any of the frrouting daemons you may see the below error
|
||||
due to the frrouting shared library directory not being found:
|
||||
If you try and start any of the frrouting daemons you may see the below
|
||||
error due to the frrouting shared library directory not being found:
|
||||
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open shared object file: No such file or directory
|
||||
::
|
||||
|
||||
The fix is to add the following line to /etc/ld.so.conf which will continue to
|
||||
reference the library directory after the system reboots. To load the library
|
||||
directory path immediately run the ldconfig command after adding the line to
|
||||
the file eg:
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open
|
||||
shared object file: No such file or directory
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
||||
The fix is to add the following line to /etc/ld.so.conf which will
|
||||
continue to reference the library directory after the system reboots. To
|
||||
load the library directory path immediately run the ldconfig command
|
||||
after adding the line to the file eg:
|
||||
|
||||
::
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
||||
@ -1,37 +1,46 @@
|
||||
Building FRR on Fedora 24 from Git Source
|
||||
Fedora 24
|
||||
=========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo dnf install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel perl-XML-LibXML pytest bison flex \
|
||||
c-ares-devel python3-devel
|
||||
c-ares-devel python3-devel python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
(You may prefer different options on configure statement. These are just
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -60,12 +69,16 @@ an example.)
|
||||
--enable-eigrpd \
|
||||
--enable-babeld \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -85,21 +98,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding (and MPLS)
|
||||
Enable IP & IPv6 forwarding (and MPLS)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the
|
||||
following content:
|
||||
(Please make sure to list all interfaces with required MPLS similar
|
||||
to `net.mpls.conf.eth0.input=1`)
|
||||
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
|
||||
following content: (Please make sure to list all interfaces with
|
||||
required MPLS similar to ``net.mpls.conf.eth0.input=1``)
|
||||
|
||||
::
|
||||
|
||||
# Sysctl for routing
|
||||
#
|
||||
@ -115,9 +135,14 @@ to `net.mpls.conf.eth0.input=1`)
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
Create a new file `/etc/modules-load.d/mpls.conf` with the following content:
|
||||
Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
|
||||
content:
|
||||
|
||||
::
|
||||
|
||||
# Load MPLS Kernel Modules
|
||||
mpls-router
|
||||
@ -125,14 +150,28 @@ Create a new file `/etc/modules-load.d/mpls.conf` with the following content:
|
||||
|
||||
And load the kernel modules on the running system:
|
||||
|
||||
::
|
||||
|
||||
sudo modprobe mpls-router mpls-iptunnel
|
||||
|
||||
### Install frr Service and redhat init files
|
||||
Install frr Service and redhat init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
||||
|
||||
### Enable required frr at startup
|
||||
|
||||
Enable required frr at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl enable frr
|
||||
|
||||
### Reboot or start FRR manually
|
||||
Reboot or start FRR manually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start frr
|
||||
@ -1,46 +1,53 @@
|
||||
Building FRR on FreeBSD 10 from Git Source
|
||||
FreeBSD 10
|
||||
==========================================
|
||||
|
||||
FreeBSD 10 restrictions:
|
||||
------------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
||||
bison flex py27-pytest c-ares python3
|
||||
bison flex py27-pytest c-ares python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
|
||||
-d /usr/local/etc/frr -s /usr/sbin/nologin
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -63,12 +70,16 @@ an example)
|
||||
--enable-rtadv \
|
||||
--enable-fpm \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
gmake
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -83,12 +94,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
@ -1,37 +1,42 @@
|
||||
Building FRR on FreeBSD 11 from Git Source
|
||||
FreeBSD 11
|
||||
==========================================
|
||||
|
||||
FreeBSD 11 restrictions:
|
||||
------------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
||||
bison flex py27-pytest c-ares python3
|
||||
bison flex py27-pytest c-ares python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
@ -41,6 +46,8 @@ using any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -63,12 +70,16 @@ an example)
|
||||
--enable-rtadv \
|
||||
--enable-fpm \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
gmake
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -83,12 +94,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
@ -1,32 +1,39 @@
|
||||
Building FRR on FreeBSD 9 from Git Source
|
||||
FreeBSD 9
|
||||
=========================================
|
||||
|
||||
FreeBSD 9 restrictions:
|
||||
-----------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install -y git autoconf automake libtool gmake gawk \
|
||||
pkgconf texinfo json-c bison flex py27-pytest c-ares \
|
||||
python3
|
||||
python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
For building with clang (instead of gcc), upgrade clang from 3.4 default to 3.6 *This is needed to build FreeBSD packages as well - for packages clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during compile)
|
||||
For building with clang (instead of gcc), upgrade clang from 3.4 default
|
||||
to 3.6 *This is needed to build FreeBSD packages as well - for packages
|
||||
clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during
|
||||
compile)
|
||||
|
||||
::
|
||||
|
||||
pkg install clang36
|
||||
pkg delete clang34
|
||||
@ -39,7 +46,10 @@ Get FRR, compile it and install it (from Git)
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
@ -49,6 +59,8 @@ using any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -71,12 +83,16 @@ an example)
|
||||
--enable-rtadv \
|
||||
--enable-fpm \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
gmake
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -91,12 +107,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
108
doc/developer/building-frr-on-lede-openwrt.rst
Normal file
108
doc/developer/building-frr-on-lede-openwrt.rst
Normal file
@ -0,0 +1,108 @@
|
||||
OpenWRT/LEDE
|
||||
=============================================
|
||||
|
||||
- for the moment because of cross compile problems, master is not
|
||||
supported, only up to 3.0
|
||||
- LDP can't be built because of missing Perl-XML-LibXML in OpenWRT/LEDE
|
||||
tree
|
||||
|
||||
Prepare build environment
|
||||
-------------------------
|
||||
|
||||
https://lede-project.org/docs/guide-developer/install-buildsystem
|
||||
|
||||
for
|
||||
|
||||
Ubuntu 12.04LTS:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential subversion git-core \
|
||||
libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc \
|
||||
libxml-parser-perl mercurial bzr ecj cvs unzip python3-sphinx
|
||||
|
||||
Ubuntu 64bit:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential subversion libncurses5-dev zlib1g-dev \
|
||||
gawk gcc-multilib flex git-core gettext libssl-dev python3-sphinx
|
||||
|
||||
Debian 8 Jessie:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext unzip zlib1g-dev file python python3-sphinx
|
||||
|
||||
Debian 9 Stretch:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext zlib1g-dev python3-sphinx
|
||||
|
||||
Centos x86-64 (some packages require EPEL):
|
||||
|
||||
::
|
||||
|
||||
yum install subversion binutils bzip2 gcc gcc-c++ gawk gettext flex \
|
||||
ncurses-devel zlib-devel zlib-static make patch unzip glibc glibc-devel \
|
||||
perl-ExtUtils-MakeMaker glibc-static quilt ncurses-libs sed sdcc bison \
|
||||
intltool sharutils wget git-core openssl-devel xz python-sphinx
|
||||
|
||||
Fedora 24 - 64Bit:
|
||||
|
||||
::
|
||||
|
||||
dnf install -y subversion binutils bzip2 gcc gcc-c++ gawk gettext git-core \
|
||||
unzip ncurses-devel ncurses-compat-libs zlib-devel zlib-static make \
|
||||
flex patch perl-ExtUtils-MakeMaker perl-Thread-Queue glibc glibc-devel \
|
||||
glibc-static quilt sed sdcc intltool sharutils bison wget openssl-devel \
|
||||
python3-sphinx
|
||||
|
||||
Get LEDE Sources (from Git)
|
||||
---------------------------
|
||||
|
||||
LEDE and OpenWRT is planned to remerge and won't cover the similar
|
||||
OpenWRT build As normal user: git clone
|
||||
https://git.lede-project.org/source.git lede cd lede ./scripts/feeds
|
||||
update -a ./scripts/feeds install -a cd feeds/routing git pull origin
|
||||
pull/319/head ln -s ../../../feeds/routing/frr/
|
||||
../../package/feeds/routing/ cd ../.. make menuconfig
|
||||
|
||||
Select the needed target then select needed packages in Network ->
|
||||
Routing and Redirection -> frr, exit and save
|
||||
|
||||
::
|
||||
|
||||
make or make package/frr/compile
|
||||
|
||||
It may be possible that on first build ``make package/frr/compile`` not
|
||||
to work and it may be needed to run a ``make`` for the entire build
|
||||
envronment, add V=s for debugging
|
||||
|
||||
Work with sources
|
||||
-----------------
|
||||
|
||||
To update the rc1 version or add other options, the Makefile is found in
|
||||
feeds/routing/frr
|
||||
|
||||
edit: PKG\_VERSION:= PKG\_SOURCE\_VERSION:=
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
|
||||
DAEMONS= or don't install unneded packages For example: zebra bgpd ldpd
|
||||
isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||
|
||||
Enable the serivce
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- service frr enable
|
||||
|
||||
Start the service
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
- service frr start
|
||||
@ -1,50 +1,66 @@
|
||||
Building FRR on NetBSD 6 from Git Source
|
||||
NetBSD 6
|
||||
========================================
|
||||
|
||||
NetBSD 6 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``NetBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Configure Package location:
|
||||
|
||||
::
|
||||
|
||||
PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
||||
export PKG_PATH
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo pkg_add git autoconf automake libtool gmake gawk openssl \
|
||||
pkg-config json-c python27 py27-test python35
|
||||
pkg-config json-c python27 py27-test python35 py-sphinx
|
||||
|
||||
Install SSL Root Certificates (for git https access):
|
||||
|
||||
::
|
||||
|
||||
sudo pkg_add mozilla-rootcerts
|
||||
sudo touch /etc/openssl/openssl.cnf
|
||||
sudo mozilla-rootcerts install
|
||||
|
||||
Select default Python and py.test
|
||||
|
||||
::
|
||||
|
||||
sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
|
||||
sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
------------------------------------------------
|
||||
---------------------------------------------
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -g 93 frrvty
|
||||
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
||||
-d /nonexistent -s /sbin/nologin frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
(You may prefer different options on configure statement. These are just
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -67,12 +83,16 @@ an example)
|
||||
--enable-rtadv \
|
||||
--enable-fpm \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
gmake
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /usr/pkg/etc/frr
|
||||
sudo touch /usr/pkg/etc/frr/zebra.conf
|
||||
@ -88,23 +108,35 @@ an example)
|
||||
sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
||||
sudo chmod 640 /usr/pkg/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
|
||||
Install rc.d init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
### Install rc.d init files
|
||||
cp pkgsrc/*.sh /etc/rc.d/
|
||||
chmod 555 /etc/rc.d/*.sh
|
||||
|
||||
### Enable FRR processes
|
||||
Enable FRR processes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(Enable the required processes only)
|
||||
|
||||
::
|
||||
|
||||
echo "zebra=YES" >> /etc/rc.conf
|
||||
echo "bgpd=YES" >> /etc/rc.conf
|
||||
echo "ospfd=YES" >> /etc/rc.conf
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user