Merge branch 'master' into stylechecker

This commit is contained in:
Quentin Young 2018-03-27 15:21:15 -04:00
commit 42732e05a9
No known key found for this signature in database
GPG Key ID: DAF48E0F57E0834F
612 changed files with 37049 additions and 26607 deletions

3
.gitignore vendored
View File

@ -82,3 +82,6 @@ GPATH
*.lo
compile_commands.json
.dirstamp
# clippy generated source
*_clippy.c

View File

@ -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)
![git branches continually merging to the left from 3 lanes; float-right](doc/git_branches.svg
"git branch mechanics")
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 its 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 dont 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 doesnt
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 Authors 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 shouldnt 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

View File

@ -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
View File

@ -0,0 +1 @@
/APKBUILD

37
alpine/APKBUILD.in Normal file
View 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
View File

@ -16,4 +16,3 @@ TAGS
.arch-ids
*~
*.loT
*clippy.c

View File

@ -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");
}

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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) {

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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))

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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 *);

View File

@ -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,

View File

@ -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");

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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))

View File

@ -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)

View File

@ -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 */

View File

@ -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) {
/*

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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])

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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/

View File

@ -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

View File

@ -1 +1 @@
doc/frr.info*
doc/user/_build/texinfo/frr.info

View File

@ -1,2 +1 @@
usr/share/info
doc/*.png usr/share/info
doc/user/_build/texinfo/*.png usr/share/info

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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
*~

View File

@ -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]
=========================================================================

View File

@ -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

View File

@ -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

View File

@ -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.
![image](ospf_api_architecture.png)
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:
![image](ospf_api_msghdr.png)
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:
![image](ospf_api_msgs1.png)
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:
![image](ospf_api_msgs2.png)
## 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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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@

View File

@ -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
View File

@ -0,0 +1 @@
include ../frr-sphinx.mk

View 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
View File

@ -0,0 +1,11 @@
.. _bgpd:
****
BGPD
****
.. toctree::
:maxdepth: 2
next-hop-tracking
bgp-typecodes

View 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).

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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