-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 it’s supported
-by all FRRouting platform OSes or provide a way to build without the library
-(potentially without the new feature) on the other platforms.
-
-Documentation should be written in Tex (.texi) or Markdown (.md) format with a
-preference for Markdown.
-
-
-## Mailing lists
-
-Italicized lists are private.
-
-| Topic | List |
-|--------------------------------|------------------------------|
-| Development | dev@lists.frrouting.org |
-| Users & Operators | frog@lists.frrouting.org |
-| Announcements | announce@lists.frrouting.org |
-| _Security_ | security@lists.frrouting.org |
-| _Technical Steering Committee_ | tsc@lists.frrouting.org |
-
-The Development list is used to discuss and document general issues
-related to project development and governance. The public Slack
-instance, frrouting.slack.com, and weekly technical meetings provide a
-higher bandwidth channel for discussions. The results of such
-discussions must be reflected in updates, as appropriate, to code (i.e.,
-merges), [github](https://github.com/FRRouting/frr/issues) tracked
-issues, and for governance or process changes, updates to the
-Development list and either this file or information posted at
-[https://frrouting.org/](https://frrouting.org/).
-
-
-### Changelog
-
-The changelog will be the base for the release notes. A changelog entry for
-your changes is usually not required and will be added based on your commit
-messages by the maintainers. However, you are free to include an update to
-the changelog with some better description. The changelog will be the base
-for the release notes.
-
-
-## Submitting Patches and Enhancements
-
-### Pre-submission Checklist
-
-* Format code (see [Developer's Guidelines](#developers-guidelines))
-* Verify and acknowledge license (see [License for contributions](#license-for-contributions))
-* Ensure you have properly signed off (see [Signing Off](#signing-off))
-* Test building with various configurations:
- * `buildtest.sh`
-* Verify building source distribution:
- * `make dist` (and try rebuilding from the resulting tar file)
-* Run unit tests:
- * `make test`
-* Document Regression Runs and plans for continued maintenance of the feature
-
-### License for contributions
-
-FRRouting is under a “GPLv2 or later” license. Any code submitted must be
-released under the same license (preferred) or any license which allows
-redistribution under this GPLv2 license (eg MIT License).
-
-### Signing Off
-
-Code submitted to FRRouting must be signed off. We have the same requirements
-for using the signed-off-by process as the Linux kernel. In short, you must
-include a signed-off-by tag in every patch.
-
-`Signed-off-by:` this is a developer's certification that he or she has the
-right to submit the patch for inclusion into the project. It is an agreement to
-the Developer's Certificate of Origin (below). Code without a proper signoff
-can not and will not be merged.
-
-If you are unfamiliar with this process, you should read the [official policy
-at kernel.org](https://www.kernel.org/doc/html/latest/process/submitting-patches.html) and
-you might find this article about [participating in the Linux community on the
-Linux Foundation
-website](http://www.linuxfoundation.org/content/how-participate-linux-community-0)
-to be a helpful resource.
-
-In short, when you sign off on a commit, you assert your agreement to all of
-the following:
-
-> Developer's Certificate of Origin 1.1
->
-> By making a contribution to this project, I certify that:
->
-> (a) The contribution was created in whole or in part by me and I
-> have the right to submit it under the open source license
-> indicated in the file; or
->
-> (b) The contribution is based upon previous work that, to the best
-> of my knowledge, is covered under an appropriate open source
-> license and I have the right under that license to submit that
-> work with modifications, whether created in whole or in part
-> by me, under the same open source license (unless I am
-> permitted to submit under a different license), as indicated
-> in the file; or
->
-> (c) The contribution was provided directly to me by some other
-> person who certified (a), (b) or (c) and I have not modified
-> it.
->
-> (d) I understand and agree that this project and the contribution
-> are public and that a record of the contribution (including all
-> personal information I submit with it, including my sign-off) is
-> maintained indefinitely and may be redistributed consistent with
-> this project or the open source license(s) involved.
-
-### What do I submit my changes against?
-
-We've documented where we would like to have the different fixes applied at
-https://github.com/FRRouting/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F
-If you are unsure where your submission goes, look at that document or ask a
-project maintainer.
-
-### Github pull requests
-
-The preferred method of submitting changes is a Github pull request. Code
-submitted by pull request will be automatically tested by one or more CI
-systems. Once the automated tests succeed, other developers will review your
-code for quality and correctness. After any concerns are resolved, your code
-will be merged into the branch it was submitted against.
-
-### Patch submission via mailing list
-
-As an alternative submission method, a patch can be mailed to the development
-mailing list. Patches received on the mailing list will be picked up by
-Patchwork and tested against the latest development branch.
-
-The recommended way to send the patch (or series of NN patches) to the list is
-by using `git send-email` as follows (assuming they are the N most recent
-commit(s) in your git history:
-
-```
-git send-email -NN --annotate --to=dev@lists.frrouting.org
-```
-
-If your commits do not already contain a `Signed-off-by` line, then use the
-following command to add it (after making sure you agree to the Developer
-Certificate of Origin as outlined above):
-
-```
-git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
-```
-
-Submitting multi-commit patches as a Github pull request is **strongly
-encouraged** and increases the probability of your patch getting reviewed and
-merged in a timely manner.
-
-
-## After submitting your changes
-
-* Watch for Continuous Integration (CI) Test results
- * You should automatically receive an email with the test results within
- less than 2 hrs of the submission. If you don’t get the email, then check
- status on the github pull request (if submitted by pull request) or on
- Patchwork at
- [https://patchwork.frrouting.org](https://patchwork.frrouting.org) (if
- submitted as patch to mailing list).
- * Please notify the development mailing list if you think something doesn’t
- work.
-* If the tests failed:
- * In general, expect the community to ignore the submission until the tests
- pass.
- * It is up to you to fix and resubmit.
- * This includes fixing existing unit (“make test”) tests if your
- changes broke or changed them.
- * It also includes fixing distribution packages for the failing
- platforms (ie if new libraries are required).
- * Feel free to ask for help on the development list.
- * Go back to the submission process and repeat until the tests pass.
-* If the tests pass:
- * Wait for reviewers. Someone will review your code or be assigned to
- review your code.
- * Respond to any comments or concerns the reviewer has.
- * After all comments and concerns are addressed, expect your patch to be
- merged.
-* Watch out for questions on the mailing list. At this time there will be a
- manual code review and further (longer) tests by various community members.
-* Your submission is done once it is merged to the master branch.
-
-
-## Developer's Guidelines
-
-### Commit messages
-
-Commit messages should be formatted in the same way as Linux kernel commit
-messages. The format is roughly
-
-```
-dir: short summary
-
-extended summary
-```
-
-`dir` should be the top level source directory under which the change was made.
-For example, a change in bgpd/rfapi would be formatted as:
-
-`bgpd: short summary`
-
-The first line should be no longer than 50 characters. Subsequent lines should
-be wrapped to 72 characters.
-
-### Source file header
-
-New files need to have a Copyright header (see [License for
-contributions](#license-for-contributions) above) added to the file. Preferred
-form of the header is as follows:
-
-```
-/*
- * Title/Function of file
- * Copyright (C) YEAR Author’s Name
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-```
-
-### Adding copyright claims to existing files
-
-When adding copyright claims for modifications to an existing file, please
-preface the claim with "Portions: " on a line before it and indent the
-"Copyright ..." string. If such a case already exists, add your indented claim
-immediately after. E.g.:
-
-```
-Portions:
- Copyright (C) 2010 Entity A ....
- Copyright (C) 2016 Your name [optional brief change description]
-```
-
-### Code formatting
-
-FRR uses Linux kernel style except where noted below. Code which does not
-comply with these style guidelines will not be accepted.
-
-To assist with compliance, in the project root there is a .clang-format
-configuration file which can be used with the `clang-format` tool from the LLVM
-project. In the `tools/` directory there is a Python script named `indent.py`
-that wraps clang-format and handles some edge cases specific to FRR. If you are
-submitting a new file, it is recommended to run that script over the new file
-after ensuring that the latest stable release of `clang-format` is in your
-PATH.
-
-**Whitespace changes in untouched parts of the code are not acceptable in
-patches that change actual code.** To change/fix formatting issues, please
-create a separate patch that only does formatting changes and nothing else.
-
-#### Style documentation
-Kernel and BSD styles are documented externally:
-
-* [https://www.kernel.org/doc/html/latest/process/coding-style.html](https://www.kernel.org/doc/html/latest/process/coding-style.html)
-* [http://man.openbsd.org/style](http://man.openbsd.org/style)
-
-For GNU coding style, use `indent` with the following invocation:
-
-```
-indent -nut -nfc1 file_for_submission.c
-```
-
-#### Exceptions
-
-FRR project code comes from a variety of sources, so there are some stylistic
-exceptions in place. They are organized here by branch.
-
-**For `master`:**
-
-BSD coding style applies to:
-
-* `ldpd/`
-
-`babeld` uses, approximately, the following style:
-
-* K&R style braces
-* Indents are 4 spaces
-* Function return types are on their own line
-
-
-**For `stable/3.0` and `stable/2.0`:**
-
-GNU coding style apply to the following parts:
-
-* `lib/`
-* `zebra/`
-* `bgpd/`
-* `ospfd/`
-* `ospf6d/`
-* `isisd/`
-* `ripd/`
-* `ripngd/`
-* `vtysh/`
-
-BSD coding style applies to:
-
-* `ldpd/`
-
-
-### Documentation
-
-FRRouting is a large and complex software project developed by many different
-people over a long period of time. Without adequate documentation, it can be
-exceedingly difficult to understand code segments, APIs and other interfaces.
-In the interest of keeping the project healthy and maintainable, you should
-make every effort to document your code so that other people can understand
-what it does without needing to closely read the code itself.
-
-Some specific guidelines that contributors should follow are:
-
-* Functions exposed in header files should have descriptive comments above
- their signatures in the header file. At a minimum, a function comment should
- contain information about the return value, parameters, and a general summary
- of the function's purpose. Documentation on parameter values can be omitted
- if it is (very) obvious what they are used for.
-
- Function comments must follow the style for multiline comments laid out in
- the kernel style guide.
-
-Example:
-
-```
-/*
- * Determines whether or not a string is cool.
- *
- * @param text - the string to check for coolness
- * @param is_clccfc - whether capslock is cruise control for cool
- * @return 7 if the text is cool, 0 otherwise
- */
-int check_coolness(const char *text, bool is_clccfc);
-```
-
-The Javadoc-style annotations are not required, but you should still strive to
-make it equally clear what parameters and return values are used for.
-
-* Static functions should have descriptive comments in the same form as above
- if what they do is not immediately obvious. Use good engineering judgement
- when deciding whether a comment is necessary. If you are unsure, document
- your code.
-
-* Global variables, static or not, should have a comment describing their use.
-
-* **For new code in `lib/`, these guidelines are hard requirements.**
-
-
-If you are contributing code that adds significant user-visible functionality
-or introduces a new API, please document it in `doc/`. Markdown and LaTeX are
-acceptable formats, although Markdown is currently preferred for new
-documentation. This may change in the near future.
-
-Finally, if you come across some code that is undocumented and feel like going
-above and beyond, document it! We absolutely appreciate and accept patches that
-document previously undocumented code.
-
-### Compile-time conditional code
-
-Many users access FRR via binary packages from 3rd party sources; compile-time
-code puts inclusion/exclusion in the hands of the package maintainer. Please
-think very carefully before making code conditional at compile time, as it
-increases regression testing, maintenance burdens, and user confusion. In
-particular, please avoid gratuitous `--enable-…` switches to the configure
-script - in general, code should be of high quality and in working condition,
-or it shouldn’t be in FRR at all.
-
-When code must be compile-time conditional, try have the compiler make it
-conditional rather than the C pre-processor so that it will still be checked by
-the compiler, even if disabled. For example,
-
-```
-if (SOME_SYMBOL)
- frobnicate();
-```
-
-is preferred to
-
-```
-#ifdef SOME_SYMBOL
-frobnicate ();
-#endif /* SOME_SYMBOL */
-```
-
-Note that the former approach requires ensuring that `SOME_SYMBOL` will be
-defined (watch your `AC_DEFINE`s).
-
-### Debug-guards in code
-
-Debugging statements are an important methodology to allow developers to fix
-issues found in the code after it has been released. The caveat here is that
-the developer must remember that people will be using the code at scale and in
-ways that can be unexpected for the original implementor. As such debugs
-**MUST** be guarded in such a way that they can be turned off. FRR has the
-ability to turn on/off debugs from the CLI and it is expected that the
-developer will use this convention to allow control of their debugs.
-
-### CLI changes
-
-CLI's are a complicated ugly beast. Additions or changes to the CLI should use
-a DEFUN to encapsulate one setting as much as is possible. Additionally as new
-DEFUN's are added to the system, documentation should be provided for the new
-commands.
-
-### Backwards Compatibility
-
-As a general principle, changes to CLI and code in the lib/ directory should be
-made in a backwards compatible fashion. This means that changes that are purely
-stylistic in nature should be avoided, e.g., renaming an existing macro or
-library function name without any functional change. When adding new parameters
-to common functions, it is also good to consider if this too should be done in
-a backward compatible fashion, e.g., by preserving the old form in addition to
-adding the new form.
-
-This is not to say that minor or even major functional changes to CLI and
-common code should be avoided, but rather that the benefit gained from a change
-should be weighed against the added cost/complexity to existing code. Also,
-that when making such changes, it is good to preserve compatibility when
-possible to do so without introducing maintenance overhead/cost. It is also
-important to keep in mind, existing code includes code that may reside in
-private repositories (and is yet to be submitted) or code that has yet to be
-migrated from Quagga to FRR.
-
-That said, compatibility measures can (and should) be removed when either:
-
-* they become a significant burden, e.g. when data structures change and the
- compatibility measure would need a complex adaptation layer or becomes
- flat-out impossible
-* some measure of time (dependent on the specific case) has passed, so that the
- compatibility grace period is considered expired.
-
-In all cases, compatibility pieces should be marked with compiler/preprocessor
-annotations to print warnings at compile time, pointing to the appropriate
-update path. A `-Werror` build should fail if compatibility bits are used.
-
-### Release Process/Schedule
-
-FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
-
-* MAJOR - Significant new features or multiple minor features
- A example of a MAJOR feature is a New Routing Protocol
-* MINOR - Smaller Features
- A example of a MINOR feature is the addition of the BGP Shutdown feature.
-* BUGFIX - Fixes for actual bugs and/or security issues.
-
-We will pull a new development branch for the next release every 4 months.
-The current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR
-release is made at the time of branch pull based on what has been received
-the previous 4 months. The branch name will be dev/MAJOR.MINOR. At
-this point in time the master branch configure.ac and packaging systems
-will be updated to reflect the next possible release name to allow
-for easy distinguishing. Additionally the new dev branch will have
-these files updated too.
-
-After one month the development branch will be renamed to
-stable/MAJOR.MINOR. This process is not held up unless a crash or
-security issue has been found and needs to be addressed. Issues
-being fixed will not cause a delay.
-
-Bug fix releases are at 1 month intervals until next MAJOR.MINOR is
-pulled. Then at that time as needed for issues filed.
-
-Security issues are fixed for 1 year minimum on old releases and
-normal bug fixes for the current and previous release
-
-### 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
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"
+ 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"
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) {
mask_ecom_global_admin(&eval_tmp, eval);
irt = lookup_vrf_import_rt(&eval_tmp);
- if (irt && irt->vrfs)
- if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
- /* Already mapped. */
- return;
+ if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+ /* Already mapped. */
+ return;
- if (!irt) {
+ if (!irt)
irt = vrf_import_rt_new(&eval_tmp);
- assert(irt);
- }
/* Add VRF to the list for this RT. */
listnode_add(irt->vrfs, bgp_vrf);
u_char rlen;
struct prefix p;
- /* Check peer status. */
- if (peer->status != Established) {
- zlog_err("%u:%s - EVPN update received in state %d",
- peer->bgp->vrf_id, peer->host, peer->status);
- return -1;
- }
-
/* Start processing the NLRI - there may be multiple in the MP_REACH */
pnt = packet->nlri;
lim = pnt + packet->length;
bgp->vrf_prd.family = AF_UNSPEC;
bgp->vrf_prd.prefixlen = 64;
sprintf(buf, "%s:%hu", inet_ntoa(bgp->router_id), bgp->vrf_rd_id);
- str2prefix_rd(buf, &bgp->vrf_prd);
+ (void)str2prefix_rd(buf, &bgp->vrf_prd);
}
/*
return 0;
}
- if (peer->bgp && peer->bgp->vrf_id == VRF_UNKNOWN) {
+ 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",
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;
#include "queue.h"
#include "filter.h"
#include "mpls.h"
-#include "lib/json.h"
-#include "lib/zclient.h"
+#include "json.h"
+#include "zclient.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
int addpath_encoded;
u_int32_t addpath_id;
- /* Check peer status. */
- if (peer->status != Established)
- return 0;
-
/* Make prefix_rd */
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
struct bgp_node *bn;
const char *debugmsg;
- if (debug) {
- const char *s = "";
-
- if (info_vrf->attr && info_vrf->attr->ecommunity) {
- s = ecommunity_ecom2str(info_vrf->attr->ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- }
+ if (debug && info_vrf->attr->ecommunity) {
+ char *s = ecommunity_ecom2str(info_vrf->attr->ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: info_vrf->type=%d, EC{%s}", __func__,
info_vrf->type, s);
+ XFREE(MTYPE_ECOMMUNITY_STR, s);
}
if (!bgp_vpn)
}
}
- if (debug) {
- const char *s = "";
+ if (debug && static_attr.ecommunity) {
+ char *s = ecommunity_ecom2str(static_attr.ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- if (static_attr.ecommunity) {
- s = ecommunity_ecom2str(static_attr.ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- }
zlog_debug("%s: post route map static_attr.ecommunity{%s}",
__func__, s);
+ XFREE(MTYPE_ECOMMUNITY_STR, s);
}
/*
static_attr.ecommunity = new_ecom;
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
- if (debug) {
- const char *s = "";
+ if (debug && static_attr.ecommunity) {
+ char *s = ecommunity_ecom2str(static_attr.ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- if (static_attr.ecommunity) {
- s = ecommunity_ecom2str(static_attr.ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- }
zlog_debug("%s: post merge static_attr.ecommunity{%s}",
__func__, s);
+ XFREE(MTYPE_ECOMMUNITY_STR, s);
}
/* Nexthop */
&static_attr); /* hashed refcounted everything */
bgp_attr_flush(&static_attr); /* free locally-allocated parts */
- if (debug) {
- const char *s = "";
+ if (debug && new_attr->ecommunity) {
+ char *s = ecommunity_ecom2str(new_attr->ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- if (new_attr->ecommunity) {
- s = ecommunity_ecom2str(new_attr->ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- }
zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s);
+ XFREE(MTYPE_ECOMMUNITY_STR, s);
}
/* Now new_attr is an allocated interned attr */
safi_t safi = SAFI_MPLS_VPN;
/*
- * Walk vpn table, delete bi with parent == bgp_vrf
* Walk vpn table, delete bi with bgp_orig == bgp_vrf
*/
for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
struct prefix *p = &info_vpn->net->p;
afi_t afi = family2afi(p->family);
- struct bgp_redist *red;
struct attr static_attr = {0};
struct attr *new_attr = NULL;
struct bgp_node *bn;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
- if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg, &red)) {
+ if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
/*
* route map handling
- * For now, we apply two route maps: the "redist" route map and the
- * vpn-policy route map. Once we finalize CLI syntax, one of these
- * route maps will probably go away.
*/
- if (red->rmap.map) {
- struct bgp_info info;
- route_map_result_t ret;
-
- memset(&info, 0, sizeof(info));
- info.peer = bgp_vrf->peer_self;
- info.attr = &static_attr;
- ret = route_map_apply(red->rmap.map, p, RMAP_BGP, &info);
- if (RMAP_DENYMATCH == ret) {
- bgp_attr_flush(&static_attr); /* free any added parts */
- if (debug)
- zlog_debug(
- "%s: vrf %s redist route map \"%s\" says DENY, skipping",
- __func__, bgp_vrf->name,
- red->rmap.name);
- return;
- }
- }
if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
struct bgp_info info;
route_map_result_t ret;
void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
struct bgp_info *info_vpn) /* route */
{
- struct prefix *p = &info_vpn->net->p;
- afi_t afi = family2afi(p->family);
+ struct prefix *p;
+ afi_t afi;
safi_t safi = SAFI_UNICAST;
struct bgp *bgp;
struct listnode *mnode, *mnnode;
- struct bgp_redist *red;
struct bgp_node *bn;
struct bgp_info *bi;
const char *debugmsg;
if (debug)
zlog_debug("%s: start (info_vpn=%p)", __func__, info_vpn);
+ if (!info_vpn->net) {
+#if ENABLE_BGP_VNC
+ /* BGP_ROUTE_RFP routes do not have info_vpn->net set (yet) */
+ if (info_vpn->type == ZEBRA_ROUTE_BGP &&
+ info_vpn->sub_type == BGP_ROUTE_RFP) {
+
+ return;
+ }
+#endif
+ if (debug)
+ zlog_debug("%s: info_vpn->net unexpectedly NULL, no prefix, bailing",
+ __func__);
+ return;
+ }
+
+ p = &info_vpn->net->p;
+ afi = family2afi(p->family);
/* Loop over VRFs */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
- if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg, &red)) {
+ if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__,
debugmsg);
__func__);
}
- /*
- * vpn -> vrf leaking currently can have two route-maps:
- * 1. the vpn-policy tovpn route-map
- * 2. the (per-afi) redistribute vpn route-map
- */
- char *mapname_vpn_policy =
- bgp->vpn_policy[afi]
- .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
- struct bgp_redist *red = NULL;
-
- if (vpn_leak_from_vpn_active(bgp, afi, NULL, &red)
- && ((mapname_vpn_policy
- && !strcmp(rmap_name, mapname_vpn_policy))
- || (red && red->rmap.name
- && !strcmp(red->rmap.name, rmap_name)))) {
+ char *mapname = bgp->vpn_policy[afi]
+ .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN];
- if (debug)
- zlog_debug(
- "%s: rmap \"%s\" matches vrf-policy fromvpn"
- " for as %d afi %s",
+ if (vpn_leak_from_vpn_active(bgp, afi, NULL) &&
+ mapname &&
+ !strcmp(rmap_name, mapname)) {
+
+ if (debug) {
+ zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s",
__func__, rmap_name, bgp->as,
afi2str(afi));
+ }
vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
- if (!rmap)
+ if (!rmap) {
bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN] =
NULL;
+ }
vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
bgp_get_default(), bgp);
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)) {
}
static inline int vpn_leak_from_vpn_active(struct bgp *bgp_vrf, afi_t afi,
- const char **pmsg,
- struct bgp_redist **pred)
+ const char **pmsg)
{
- struct bgp_redist *red;
-
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
- && bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+ && bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
if (pmsg)
*pmsg = "destination bgp instance neither vrf nor default";
return 0;
}
- /* Hijack zebra redist bits for this route type */
- red = bgp_redist_lookup(bgp_vrf, afi, ZEBRA_ROUTE_BGP_VPN, 0);
- if (red) {
- if (pred)
- *pred = red;
- } else {
+ /* 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 = "redist not set";
+ *pmsg = "import not set";
return 0;
}
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
afi_t afi, struct bgp *bgp_vpn,
struct bgp *bgp_vrf)
{
- if (direction == BGP_VPN_POLICY_DIR_FROMVPN)
+ 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)
+ }
+ 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,
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]
+ 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);
}
- if (direction == BGP_VPN_POLICY_DIR_TOVPN)
- vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
}
extern void vpn_policy_routemap_event(const char *rmap_name);
{
char *name = NULL;
+ if (!peer)
+ return NULL;
+
if ((peer->bgp->vrf_id == VRF_DEFAULT) && !peer->ifname
&& !peer->conf_if)
return NULL;
&& peer->su.sa.sa_family != AF_INET6)
return NULL; // unexpected
- if (!peer)
- return name;
/* For IPv6 peering, interface (unnumbered or link-local with interface)
* takes precedence over VRF. For IPv4 peering, explicit interface or
* VRF are the situations to bind.
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 {
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)
{
|| old_select->sub_type == BGP_ROUTE_AGGREGATE
|| old_select->sub_type == BGP_ROUTE_IMPORTED))
- bgp_zebra_withdraw(p, old_select, safi);
+ bgp_zebra_withdraw(p, old_select, bgp, safi);
}
}
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.
/* 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);
}
}
}
}
-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;
|| 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);
}
}
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)
*/
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 **)&(
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 **)&(
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;
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;
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Use addpath to advertise the bestpath per each neighboring AS\n")
-
-DEFUN_NOSH (vpn_policy_afi,
- vpn_policy_afi_cmd,
- "vpn-policy <ipv4|ipv6>",
- "Enter vpn-policy command mode\n"
- BGP_AFI_HELP_STR)
+static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
+ struct ecommunity **list)
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF
- && bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+ struct ecommunity *ecom = NULL;
+ struct ecommunity *ecomadd;
- vty_out(vty,
- "vpn-policy supported only in core or vrf instances.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ for (; argc; --argc, ++argv) {
- afi_t afi;
- int idx = 0;
+ ecomadd = ecommunity_str2com(argv[0]->arg,
+ ECOMMUNITY_ROUTE_TARGET, 0);
+ if (!ecomadd) {
+ vty_out(vty, "Malformed community-list value\n");
+ if (ecom)
+ ecommunity_free(&ecom);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
- if (afi == AFI_IP)
- vty->node = BGP_VPNPOLICY_IPV4_NODE;
- else
- vty->node = BGP_VPNPOLICY_IPV6_NODE;
- return CMD_SUCCESS;
+ if (ecom) {
+ ecommunity_merge(ecom, ecomadd);
+ ecommunity_free(&ecomadd);
+ } else {
+ ecom = ecomadd;
+ }
+ }
+
+ if (*list) {
+ ecommunity_free(&*list);
}
- return CMD_WARNING_CONFIG_FAILED;
+ *list = ecom;
+
+ return CMD_SUCCESS;
}
-static int vpn_policy_afis(struct vty *vty, int *doafi)
+static int vpn_policy_getafi(struct vty *vty, int *doafi)
{
switch (vty->node) {
- case BGP_VPNPOLICY_IPV4_NODE:
+ case BGP_IPV4_NODE:
doafi[AFI_IP] = 1;
break;
- case BGP_VPNPOLICY_IPV6_NODE:
+ case BGP_IPV6_NODE:
doafi[AFI_IP6] = 1;
break;
default:
vty_out(vty,
- "%% context error: valid only in vpn-policy block\n");
+ "%% context error: valid only in address-family <ipv4|ipv6> unicast block\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
-static int argv_find_and_parse_vpn_policy_dirs(struct vty *vty,
- struct cmd_token **argv,
- int argc, int *idx, int *dodir)
-{
- if (argv_find(argv, argc, "fromvpn", idx)) {
- dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
- } else if (argv_find(argv, argc, "tovpn", idx)) {
- dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
- } else if (argv_find(argv, argc, "both", idx)) {
- dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
- dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
- } else {
- vty_out(vty, "%% direction parse error\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (vpn_policy_rd,
- vpn_policy_rd_cmd,
- "rd ASN:NN_OR_IP-ADDRESS:NN",
+DEFPY (af_rd_vpn_export,
+ af_rd_vpn_export_cmd,
+ "[no] rd vpn export ASN:NN_OR_IP-ADDRESS:NN$rd_str",
+ NO_STR
"Specify route distinguisher\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n"
"Route Distinguisher (<as-number>:<number> | <ip-address>:<number>)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
int doafi[AFI_MAX] = {0};
afi_t afi;
+ int idx = 0;
+ int yes = 1;
- ret = str2prefix_rd(argv[1]->arg, &prd);
- if (!ret) {
- vty_out(vty, "%% Malformed rd\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
+
+ if (yes) {
+ ret = str2prefix_rd(rd_str, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed rd\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
- ret = vpn_policy_afis(vty, doafi);
+ ret = vpn_policy_getafi(vty, doafi);
if (ret != CMD_SUCCESS)
return ret;
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
- bgp->vpn_policy[afi].tovpn_rd = prd;
- SET_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_RD_SET);
+ if (yes) {
+ bgp->vpn_policy[afi].tovpn_rd = prd;
+ SET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+ } else {
+ UNSET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET);
+ }
/* post-change: re-export vpn routes */
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_no_rd,
- vpn_policy_no_rd_cmd,
- "no rd",
+ALIAS (af_rd_vpn_export,
+ af_no_rd_vpn_export_cmd,
+ "no rd vpn export",
NO_STR
- "Specify route distinguisher\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int ret;
- int doafi[AFI_MAX] = {0};
- afi_t afi;
-
- ret = vpn_policy_afis(vty, doafi);
- if (ret != CMD_SUCCESS)
- return ret;
-
-
- for (afi = 0; afi < AFI_MAX; ++afi) {
- if (!doafi[afi])
- continue;
-
- /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
- */
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
-
- UNSET_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_RD_SET);
-
- /* post-change: re-export vpn routes */
- vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
- }
-
- return CMD_SUCCESS;
-}
+ "Specify route distinguisher\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n")
-DEFUN (vpn_policy_label,
- vpn_policy_label_cmd,
- "label (0-1048575)",
+DEFPY (af_label_vpn_export,
+ af_label_vpn_export_cmd,
+ "[no] label vpn export (0-1048575)$label_val",
+ NO_STR
"label value for VRF\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n"
"Label Value <0-1048575>\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- mpls_label_t label;
+ mpls_label_t label = MPLS_LABEL_NONE;
int doafi[AFI_MAX] = {0};
afi_t afi;
int ret;
+ int idx = 0;
+ int yes = 1;
- label = strtoul(argv[1]->arg, NULL, 10);
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
- ret = vpn_policy_afis(vty, doafi);
+ if (yes)
+ label = label_val; /* rely on parser to force unsigned */
+
+ ret = vpn_policy_getafi(vty, doafi);
if (ret != CMD_SUCCESS)
return ret;
if (!doafi[afi])
continue;
- /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
+ /*
+ * pre-change: un-export vpn routes (vpn->vrf routes unaffected)
*/
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_no_label,
- vpn_policy_no_label_cmd,
- "no label",
- "Negate a command or set its defaults\n"
- "label value for VRF\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int doafi[AFI_MAX] = {0};
- afi_t afi;
- int ret;
-
- ret = vpn_policy_afis(vty, doafi);
- if (ret != CMD_SUCCESS)
- return ret;
-
- for (afi = 0; afi < AFI_MAX; ++afi) {
- if (!doafi[afi])
- continue;
-
- /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
- */
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
-
- bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
-
- /* post-change: re-export vpn routes */
- vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
- }
-
- return CMD_SUCCESS;
-}
+ALIAS (af_label_vpn_export,
+ af_no_label_vpn_export_cmd,
+ "no label vpn export",
+ NO_STR
+ "label value for VRF\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n")
-DEFPY (vpn_policy_nexthop,
- vpn_policy_nexthop_cmd,
- "nexthop <A.B.C.D|X:X::X:X>$nexthop",
+DEFPY (af_nexthop_vpn_export,
+ af_nexthop_vpn_export_cmd,
+ "[no] nexthop vpn export <A.B.C.D|X:X::X:X>$nexthop_str",
+ NO_STR
"Specify next hop to use for VRF advertised prefixes\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n"
"IPv4 prefix\n"
"IPv6 prefix\n")
{
afi_t afi;
int ret;
struct prefix p;
+ int idx = 0;
+ int yes = 1;
- if (!sockunion2hostprefix(nexthop, &p))
- return CMD_WARNING_CONFIG_FAILED;
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
+
+ if (yes) {
+ if (!sockunion2hostprefix(nexthop_str, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- ret = vpn_policy_afis(vty, doafi);
+ ret = vpn_policy_getafi(vty, doafi);
if (ret != CMD_SUCCESS)
return ret;
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
- bgp->vpn_policy[afi].tovpn_nexthop = p;
- SET_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
+ if (yes) {
+ bgp->vpn_policy[afi].tovpn_nexthop = p;
+ SET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
+ } else {
+ UNSET_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
+ }
/* post-change: re-export vpn routes */
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_no_nexthop,
- vpn_policy_no_nexthop_cmd,
- "no nexthop",
+ALIAS (af_nexthop_vpn_export,
+ af_no_nexthop_vpn_export_cmd,
+ "no nexthop vpn export",
NO_STR
- "Specify next hop to use for VRF advertised prefixes\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int doafi[AFI_MAX] = {0};
- afi_t afi;
- int ret;
-
- ret = vpn_policy_afis(vty, doafi);
- if (ret != CMD_SUCCESS)
- return ret;
-
- for (afi = 0; afi < AFI_MAX; ++afi) {
- if (!doafi[afi])
- continue;
-
- /* pre-change: un-export vpn routes (vpn->vrf routes unaffected)
- */
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
-
- UNSET_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_NEXTHOP_SET);
-
- /* post-change: re-export vpn routes */
- vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
- }
-
- return CMD_SUCCESS;
-}
+ "Specify next hop to use for VRF advertised prefixes\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from current address-family to vpn\n")
-static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
- struct ecommunity **list)
+static int vpn_policy_getdirs(struct vty *vty, const char *dstr, int *dodir)
{
- struct ecommunity *ecom = NULL;
- struct ecommunity *ecomadd;
-
- for (; argc; --argc, ++argv) {
-
- ecomadd = ecommunity_str2com(argv[0]->arg,
- ECOMMUNITY_ROUTE_TARGET, 0);
- if (!ecomadd) {
- vty_out(vty, "Malformed community-list value\n");
- if (ecom)
- ecommunity_free(&ecom);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (ecom) {
- ecommunity_merge(ecom, ecomadd);
- ecommunity_free(&ecomadd);
- } else {
- ecom = ecomadd;
- }
- }
-
- if (*list) {
- ecommunity_free(&*list);
+ if (!strcmp(dstr, "import")) {
+ dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
+ } else if (!strcmp(dstr, "export")) {
+ dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
+ } else if (!strcmp(dstr, "both")) {
+ dodir[BGP_VPN_POLICY_DIR_FROMVPN] = 1;
+ dodir[BGP_VPN_POLICY_DIR_TOVPN] = 1;
+ } else {
+ vty_out(vty, "%% direction parse error\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- *list = ecom;
-
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_rt,
- vpn_policy_rt_cmd,
- "rt <fromvpn|tovpn|both> RTLIST...",
+DEFPY (af_rt_vpn_imexport,
+ af_rt_vpn_imexport_cmd,
+ "[no] <rt|route-target> vpn <import|export|both>$direction_str RTLIST...",
+ NO_STR
"Specify route target list\n"
- "fromvpn: match any\n"
- "tovpn: set\n"
- "both fromvpn: match any and tovpn: set\n"
+ "Specify route target list\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from vpn to current address-family: match any\n"
+ "For routes leaked from current address-family to vpn: set\n"
+ "both import: match any and export: set\n"
"Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
vpn_policy_direction_t dir;
afi_t afi;
int idx = 0;
+ int yes = 1;
+
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
- ret = vpn_policy_afis(vty, doafi);
+ ret = vpn_policy_getafi(vty, doafi);
if (ret != CMD_SUCCESS)
return ret;
- ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ ret = vpn_policy_getdirs(vty, direction_str, dodir);
if (ret != CMD_SUCCESS)
return ret;
- ret = set_ecom_list(vty, argc - 2, argv + 2, &ecom);
- if (ret != CMD_SUCCESS) {
- return ret;
+ if (yes) {
+ if (!argv_find(argv, argc, "RTLIST", &idx)) {
+ vty_out(vty, "%% Missing RTLIST\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ ret = set_ecom_list(vty, argc - idx, argv + idx, &ecom);
+ if (ret != CMD_SUCCESS) {
+ return ret;
+ }
}
for (afi = 0; afi < AFI_MAX; ++afi) {
vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
- if (bgp->vpn_policy[afi].rtlist[dir])
- ecommunity_free(
- &bgp->vpn_policy[afi].rtlist[dir]);
- bgp->vpn_policy[afi].rtlist[dir] = ecommunity_dup(ecom);
+ if (yes) {
+ if (bgp->vpn_policy[afi].rtlist[dir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[dir]);
+ bgp->vpn_policy[afi].rtlist[dir] =
+ ecommunity_dup(ecom);
+ } else {
+ if (bgp->vpn_policy[afi].rtlist[dir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[dir]);
+ bgp->vpn_policy[afi].rtlist[dir] = NULL;
+ }
vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
}
}
- ecommunity_free(&ecom);
+ if (ecom)
+ ecommunity_free(&ecom);
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_no_rt,
- vpn_policy_no_rt_cmd,
- "no rt <fromvpn|tovpn|both>",
+ALIAS (af_rt_vpn_imexport,
+ af_no_rt_vpn_imexport_cmd,
+ "no <rt|route-target> vpn <import|export|both>$direction_str",
NO_STR
"Specify route target list\n"
- "fromvpn: match any\n"
- "tovpn: set\n"
- "both fromvpn: match any and tovpn: set\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int ret;
- int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
- int doafi[AFI_MAX] = {0};
- vpn_policy_direction_t dir;
- afi_t afi;
- int idx = 0;
-
- ret = vpn_policy_afis(vty, doafi);
- if (ret != CMD_SUCCESS)
- return ret;
-
- ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
- if (ret != CMD_SUCCESS)
- return ret;
-
- for (afi = 0; afi < AFI_MAX; ++afi) {
- if (!doafi[afi])
- continue;
- for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
- if (!dodir[dir])
- continue;
-
- vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
-
- if (bgp->vpn_policy[afi].rtlist[dir])
- ecommunity_free(
- &bgp->vpn_policy[afi].rtlist[dir]);
- bgp->vpn_policy[afi].rtlist[dir] = NULL;
-
- vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (vpn_policy_route_map,
- vpn_policy_route_map_cmd,
- "route-map <fromvpn|tovpn> WORD",
+ "Specify route target list\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from vpn to current address-family\n"
+ "For routes leaked from current address-family to vpn\n"
+ "both import and export\n")
+
+DEFPY (af_route_map_vpn_imexport,
+ af_route_map_vpn_imexport_cmd,
+/* future: "route-map <vpn|evpn|vrf NAME> <import|export> RMAP" */
+ "[no] route-map vpn <import|export>$direction_str RMAP$rmap_str",
+ NO_STR
"Specify route map\n"
- "fromvpn: core vpn -> this vrf\n"
- "tovpn: this vrf -> core vpn\n"
+ "Between current address-family and vpn\n"
+ "For routes leaked from vpn to current address-family\n"
+ "For routes leaked from current address-family to vpn\n"
"name of route-map\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int doafi[AFI_MAX] = {0};
vpn_policy_direction_t dir;
afi_t afi;
- int map_name_arg = 2;
int idx = 0;
+ int yes = 1;
+
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
- ret = vpn_policy_afis(vty, doafi);
+ ret = vpn_policy_getafi(vty, doafi);
if (ret != CMD_SUCCESS)
return ret;
- ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
+ ret = vpn_policy_getdirs(vty, direction_str, dodir);
if (ret != CMD_SUCCESS)
return ret;
vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
- if (bgp->vpn_policy[afi].rmap_name[dir])
- XFREE(MTYPE_ROUTE_MAP_NAME,
- bgp->vpn_policy[afi].rmap_name[dir]);
- bgp->vpn_policy[afi].rmap_name[dir] = XSTRDUP(
- MTYPE_ROUTE_MAP_NAME, argv[map_name_arg]->arg);
- bgp->vpn_policy[afi].rmap[dir] =
- route_map_lookup_by_name(
- argv[map_name_arg]->arg);
+ if (yes) {
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] = XSTRDUP(
+ MTYPE_ROUTE_MAP_NAME, rmap_str);
+ bgp->vpn_policy[afi].rmap[dir] =
+ route_map_lookup_by_name(rmap_str);
+ } else {
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] = NULL;
+ bgp->vpn_policy[afi].rmap[dir] = NULL;
+ }
vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
}
return CMD_SUCCESS;
}
-DEFUN (vpn_policy_no_route_map,
- vpn_policy_no_route_map_cmd,
- "no route-map <fromvpn|tovpn>",
+ALIAS (af_route_map_vpn_imexport,
+ af_no_route_map_vpn_imexport_cmd,
+ "no route-map vpn <import|export>$direction_str",
NO_STR
"Specify route map\n"
- "fromvpn: core vpn -> this vrf\n"
- "tovpn: this vrf -> core vpn\n")
+ "Between current address-family and vpn\n"
+ "For routes leaked from vpn to current address-family\n"
+ "For routes leaked from current address-family to vpn\n")
+
+/* This command is valid only in a bgp vrf instance or the default instance */
+DEFPY (bgp_imexport_vpn,
+ bgp_imexport_vpn_cmd,
+ "[no] <import|export>$direction_str vpn",
+ NO_STR
+ "Import routes to this address-family\n"
+ "Export routes from this address-family\n"
+ "to/from default instance VPN RIB\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- int ret;
- int dodir[BGP_VPN_POLICY_DIR_MAX] = {0};
- int doafi[AFI_MAX] = {0};
- vpn_policy_direction_t dir;
+ int previous_state;
afi_t afi;
+ safi_t safi;
int idx = 0;
+ int yes = 1;
+ int flag;
+ vpn_policy_direction_t dir;
- ret = vpn_policy_afis(vty, doafi);
- if (ret != CMD_SUCCESS)
- return ret;
+ if (argv_find(argv, argc, "no", &idx))
+ yes = 0;
- ret = argv_find_and_parse_vpn_policy_dirs(vty, argv, argc, &idx, dodir);
- if (ret != CMD_SUCCESS)
- return ret;
+ if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type &&
+ BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
- for (afi = 0; afi < AFI_MAX; ++afi) {
- if (!doafi[afi])
- continue;
- for (dir = 0; dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
- if (!dodir[dir])
- continue;
+ vty_out(vty, "%% import|export vpn valid only for bgp vrf or default instance\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+ afi = bgp_node_afi(vty);
+ safi = bgp_node_safi(vty);
+ if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
+ vty_out(vty, "%% import|export vpn valid only for unicast ipv4|ipv6\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!strcmp(direction_str, "import")) {
+ flag = BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT;
+ dir = BGP_VPN_POLICY_DIR_FROMVPN;
+ } else if (!strcmp(direction_str, "export")) {
+ flag = BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT;
+ dir = BGP_VPN_POLICY_DIR_TOVPN;
+ } else {
+ vty_out(vty, "%% unknown direction %s\n", direction_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- if (bgp->vpn_policy[afi].rmap_name[dir])
- XFREE(MTYPE_ROUTE_MAP_NAME,
- bgp->vpn_policy[afi].rmap_name[dir]);
- bgp->vpn_policy[afi].rmap_name[dir] = NULL;
- bgp->vpn_policy[afi].rmap[dir] = NULL;
+ previous_state = CHECK_FLAG(bgp->af_flags[afi][safi], flag);
+ if (yes) {
+ SET_FLAG(bgp->af_flags[afi][safi], flag);
+ if (!previous_state) {
+ /* trigger export current vrf */
vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
}
+ } else {
+ if (previous_state) {
+ /* trigger un-export current vrf */
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+ }
+ UNSET_FLAG(bgp->af_flags[afi][safi], flag);
}
return CMD_SUCCESS;
}
}
-/* This command is valid only in a bgp vrf instance or the default instance */
-DEFUN (bgp_export_vpn,
- bgp_export_vpn_cmd,
- "export vpn",
- "Export routes to another routing protocol\n"
- "to VPN RIB per vpn-policy")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int was_off = 0;
- afi_t afi;
- safi_t safi;
-
- if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type
- && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
- vty_out(vty,
- "%% export vpn valid only for bgp vrf or default instance\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- afi = bgp_node_afi(vty);
- safi = bgp_node_safi(vty);
- if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
- vty_out(vty,
- "%% export vpn valid only for unicast ipv4|ipv6\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (!CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
- was_off = 1;
- }
- SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT);
- if (was_off) {
- /* trigger export current vrf */
- zlog_debug("%s: calling postchange", __func__);
- vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (bgp_no_export_vpn,
- bgp_no_export_vpn_cmd,
- "no export vpn",
- NO_STR
- "Export routes to another routing protocol\n"
- "to VPN RIB per vpn-policy")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- int was_on = 0;
- afi_t afi;
- safi_t safi;
-
- if (BGP_INSTANCE_TYPE_VRF != bgp->inst_type
- && BGP_INSTANCE_TYPE_DEFAULT != bgp->inst_type) {
- vty_out(vty,
- "%% export vpn valid only for bgp vrf or default instance\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- afi = bgp_node_afi(vty);
- safi = bgp_node_safi(vty);
- if ((SAFI_UNICAST != safi) || ((AFI_IP != afi) && (AFI_IP6 != afi))) {
- vty_out(vty,
- "%% export vpn valid only for unicast ipv4|ipv6\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
- was_on = 1;
- }
- if (was_on) {
- /* trigger un-export current vrf */
- zlog_debug("%s: calling postchange", __func__);
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
- bgp_get_default(), bgp);
- }
- UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT);
- return CMD_SUCCESS;
-}
-
-static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
+/* This is part of the address-family block (unicast only) */
+void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
afi_t afi)
{
- vty_frame(vty, " vpn-policy ipv%d\n", ((afi == AFI_IP) ? 4 : 6));
+ int indent = 2;
if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
- vty_out(vty, " label %u\n",
+ vty_out(vty, "%*slabel vpn export %u\n", indent, "",
bgp->vpn_policy[afi].tovpn_label);
}
if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET)) {
char buf[RD_ADDRSTRLEN];
- vty_out(vty, " rd %s\n",
+ vty_out(vty, "%*srd vpn export %s\n", indent, "",
prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
sizeof(buf)));
}
&bgp->vpn_policy[afi].tovpn_nexthop.u.prefix, buf,
sizeof(buf))) {
- vty_out(vty, " nexthop %s\n", buf);
+ vty_out(vty, "%*snexthop vpn export %s\n",
+ indent, "", buf);
}
}
if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]
char *b = ecommunity_ecom2str(
bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN],
ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
- vty_out(vty, " rt both %s\n", b);
+ vty_out(vty, "%*srt vpn both %s\n", indent, "", b);
XFREE(MTYPE_ECOMMUNITY_STR, b);
} else {
if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN]) {
.rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
ECOMMUNITY_FORMAT_ROUTE_MAP,
ECOMMUNITY_ROUTE_TARGET);
- vty_out(vty, " rt fromvpn %s\n", b);
+ vty_out(vty, "%*srt vpn import %s\n", indent, "", b);
XFREE(MTYPE_ECOMMUNITY_STR, b);
}
if (bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
.rtlist[BGP_VPN_POLICY_DIR_TOVPN],
ECOMMUNITY_FORMAT_ROUTE_MAP,
ECOMMUNITY_ROUTE_TARGET);
- vty_out(vty, " rt tovpn %s\n", b);
+ vty_out(vty, "%*srt vpn export %s\n", indent, "", b);
XFREE(MTYPE_ECOMMUNITY_STR, b);
}
}
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) {
- vty_out(vty, " route-map fromvpn %s\n",
+ vty_out(vty, "%*sroute-map vpn import %s\n", indent, "",
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]);
}
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN]) {
- vty_out(vty, " route-map tovpn %s\n",
+ vty_out(vty, "%*sroute-map vpn export %s\n", indent, "",
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_TOVPN]);
}
- vty_endframe(vty, " exit\n");
-}
-
-void bgp_vpn_policy_config_write(struct vty *vty, struct bgp *bgp)
-{
- bgp_vpn_policy_config_write_afi(vty, bgp, AFI_IP);
- bgp_vpn_policy_config_write_afi(vty, bgp, AFI_IP6);
}
static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# ", 1};
-static struct cmd_node bgp_vpn_policy_ipv4_node = {
- BGP_VPNPOLICY_IPV4_NODE, "%s(config-router-vpn-policy-ipv4)# ", 1};
-
-static struct cmd_node bgp_vpn_policy_ipv6_node = {
- BGP_VPNPOLICY_IPV6_NODE, "%s(config-router-vpn-policy-ipv6)# ", 1};
-
static void community_list_vty(void);
static void bgp_ac_neighbor(vector comps, struct cmd_token *token)
install_node(&bgp_vpnv6_node, NULL);
install_node(&bgp_evpn_node, NULL);
install_node(&bgp_evpn_vni_node, NULL);
- install_node(&bgp_vpn_policy_ipv4_node, NULL);
- install_node(&bgp_vpn_policy_ipv6_node, NULL);
/* Install default VTY commands to new nodes. */
install_default(BGP_NODE);
install_default(BGP_VPNV6_NODE);
install_default(BGP_EVPN_NODE);
install_default(BGP_EVPN_VNI_NODE);
- install_default(BGP_VPNPOLICY_IPV4_NODE);
- install_default(BGP_VPNPOLICY_IPV6_NODE);
/* "bgp multiple-instance" commands. */
install_element(CONFIG_NODE, &bgp_multiple_instance_cmd);
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd);
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd);
- /* export vpn [route-map WORD] */
- install_element(BGP_IPV4_NODE, &bgp_export_vpn_cmd);
- install_element(BGP_IPV6_NODE, &bgp_export_vpn_cmd);
- install_element(BGP_IPV4_NODE, &bgp_no_export_vpn_cmd);
- install_element(BGP_IPV6_NODE, &bgp_no_export_vpn_cmd);
+ /* import|export vpn [route-map WORD] */
+ install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_imexport_vpn_cmd);
/* ttl_security commands */
install_element(BGP_NODE, &neighbor_ttl_security_cmd);
community_list_vty();
/* vpn-policy commands */
- install_element(BGP_NODE, &vpn_policy_afi_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_rd_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_rd_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_label_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_label_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_nexthop_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_nexthop_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_rt_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_rt_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_route_map_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_route_map_cmd);
-
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_rd_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_rd_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_label_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_label_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_nexthop_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_nexthop_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_rt_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_rt_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vpn_policy_no_route_map_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vpn_policy_no_route_map_cmd);
+ install_element(BGP_IPV4_NODE, &af_rd_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_rd_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_label_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_label_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_nexthop_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_nexthop_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_rt_vpn_imexport_cmd);
+ install_element(BGP_IPV6_NODE, &af_rt_vpn_imexport_cmd);
+ install_element(BGP_IPV4_NODE, &af_route_map_vpn_imexport_cmd);
+ install_element(BGP_IPV6_NODE, &af_route_map_vpn_imexport_cmd);
+
+ install_element(BGP_IPV4_NODE, &af_no_rd_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_no_rd_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_no_label_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_no_label_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_no_nexthop_vpn_export_cmd);
+ install_element(BGP_IPV6_NODE, &af_no_nexthop_vpn_export_cmd);
+ install_element(BGP_IPV4_NODE, &af_no_rt_vpn_imexport_cmd);
+ install_element(BGP_IPV6_NODE, &af_no_rt_vpn_imexport_cmd);
+ install_element(BGP_IPV4_NODE, &af_no_route_map_vpn_imexport_cmd);
+ install_element(BGP_IPV6_NODE, &af_no_route_map_vpn_imexport_cmd);
}
#include "memory.h"
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(struct vty *vty, struct bgp *bgp);
+extern void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
+ afi_t afi);
#endif /* _QUAGGA_BGP_VTY_H */
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;
/* 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;
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))
+ || 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);
}
#endif
- /* vpn -> vrf (happens within bgp but we hijack redist bits */
- if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
- || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- && type == ZEBRA_ROUTE_BGP_VPN) {
-
- /* leak update all */
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
- bgp_get_default(), bgp);
- }
-
vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id);
-
- /* vpn -> vrf (happens within bgp but we hijack redist bits */
- if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
- || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- && type == ZEBRA_ROUTE_BGP_VPN) {
-
- /* leak update all */
- vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
- bgp_get_default(), bgp);
- }
}
/*
vnc_export_bgp_disable(bgp, afi);
}
#endif
- /* vpn -> vrf (happend within bgp but we hijack redist bits */
- if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
- || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- && type == ZEBRA_ROUTE_BGP_VPN) {
-
- /* leak withdraw all */
- vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
- bgp_get_default(), bgp);
- }
red = bgp_redist_lookup(bgp, afi, type, instance);
if (!red)
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);
if (safi == SAFI_EVPN)
bgp_config_write_evpn_info(vty, bgp, afi, safi);
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) {
+ 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");
+ 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");
if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
vty_out(vty, " no auto-summary\n");
- bgp_vpn_policy_config_write(vty, bgp);
-
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
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)
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 router id */
+ 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
developer/OSPF-API.md \
developer/workflow.rst \
developer/Building_FRR_on_Ubuntu1404.rst \
+ developer/Building_FRR_on_Alpine.rst \
user/ospf_fundamentals.rst \
user/routemap.rst \
user/index.rst \
--- /dev/null
+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).
:maxdepth: 2
Building_FRR_on_LEDE-OpenWRT
+ Building_FRR_on_Alpine
Building_FRR_on_CentOS6
Building_FRR_on_CentOS7
Building_FRR_on_Debian8
+.. _command-line-interface:
+
Command Line Interface
======================
governance or process changes, updates to the Development list and either this
file or information posted at https://frrouting.org/.
+Release Process & Schedule
+==========================
+
+FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
+
+MAJOR
+ Significant new features or multiple minor features. The addition of a new
+ routing protocol or daemon would fall under this class.
+
+MINOR
+ Small features, e.g. options for automatic BGP shutdown.
+
+BUGFIX
+ Fixes for actual bugs and/or security issues.
+
+We will pull a new development branch for the next release every 4 months. The
+current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR release
+is made at the time of branch pull based on what has been received the previous
+4 months. The branch name will be dev/MAJOR.MINOR. At this point in time the
+master branch, :file:`configure.ac`, documentation and packaging systems will
+be updated to reflect the next possible release name to allow for easy
+distinguishing. Additionally the new dev branch will have these files updated
+too.
+
+After one month the development branch will be renamed to stable/MAJOR.MINOR.
+This process is not held up unless a crash or security issue has been found and
+needs to be addressed. Issues being fixed will not cause a delay.
+
+Bugfix releases are made as needed at 1 month intervals until the next
+MAJOR.MINOR relese branch is pulled. Depending on the severity of the bugs,
+bugfix releases may occur sooner.
+
+Bugfixes are applied to the two most recent releases. Security fixes are
+backported to all releases less than or equal to one year old. Security fixes
+may also be backported to older releases depending on severity.
Changelog
=========
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.
+The project provides multiple tools to allow you to correctly style your code
+as painlessly as possible, primarily built around ``clang-format``.
+
+clang-format
+ In the project root there is a :file:`.clang-format` configuration file
+ which can be used with the ``clang-format`` source formatter tool from the
+ LLVM project. Most of the time, this is the easiest and smartest tool to
+ use. It can be run in a variety of ways. If you point it at a C source file
+ or directory of source files, it will format all of them. In the LLVM source
+ tree there are scripts that allow you to integrate it with ``git``, ``vim``
+ and ``emacs``, and there are third-party plugins for other editors. The
+ ``git`` integration is particularly useful; suppose you have some changes in
+ your git index. Then, with the integration installed, you can do the
+ following:
+
+ ::
+
+ git clang-format
+
+ This will format *only* the changes present in your index. If you have just
+ made a few commits and would like to correctly style only the changes made
+ in those commits, you can use the following syntax:
+
+ ::
+
+ git clang-format HEAD~X
+
+ Where X is one more than the number of commits back from the tip of your
+ branch you would like ``clang-format`` to look at (similar to specifying the
+ target for a rebase).
+
+ The ``vim`` plugin is particularly useful. It allows you to select lines in
+ visual line mode and press a key binding to invoke ``clang-format`` on only
+ those lines.
+
+ When using ``clang-format``, it is recommended to use the latest version.
+ Each consecutive version generally has better handling of various edge
+ cases. You may notice on occasion that two consecutive runs of
+ ``clang-format`` over the same code may result in changes being made on the
+ second run. This is an unfortunate artifact of the tool. Please check with
+ the kernel style guide if in doubt.
+
+ One stylistic problem with the FRR codebase is the use of ``DEFUN`` macros
+ for defining CLI commands. ``clang-format`` will happily format these macro
+ invocations, but the result is often unsightly and difficult to read.
+ Consequently, FRR takes a more relaxed position with how these are
+ formatted. In general you should lean towards using the style exemplified in
+ the section on :ref:`command-line-interface`. Because ``clang-format``
+ mangles this style, there is a Python script named ``tools/indent.py`` that
+ wraps ``clang-format`` and handles ``DEFUN`` macros as well as some other
+ edge cases specific to FRR. If you are submitting a new file, it is
+ recommended to run that script over the new file, preferably after ensuring
+ that the latest stable release of ``clang-format`` is in your ``PATH``.
+
+ Documentation on ``clang-format`` and its various integrations is maintained
+ on the LLVM website.
+
+ https://clang.llvm.org/docs/ClangFormat.html
+
+checkpatch.sh
+ In the Linux kernel source tree there is a Perl script used to check
+ incoming patches for style errors. FRR uses an adapted version of this
+ script for the same purpose. It can be found at
+ :file:`tools/checkpatch.sh`. This script takes a git-formatted diff or
+ patch file, applies it to a clean FRR tree, and inspects the result to catch
+ potential style errors. Running this script on your patches before
+ submission is highly recommended. The CI system runs this script as well and
+ will comment on the PR with the results if style errors are found.
+
+ It is run like this:
+
+ ::
+
+ checkpatch.sh <patch> <tree>
+
+ Reports are generated on ``stderr`` and the exit code indicates whether
+ issues were found (2, 1) or not (0).
+
+ Where ``<patch>`` is the path to the diff or patch file and ``<tree>`` is
+ the path to your FRR source tree. The tree should be on the branch that you
+ intend to submit the patch against. The script will make a best-effort
+ attempt to save the state of your working tree and index before applying the
+ patch, and to restore it when it is done, but it is still recommended that
+ you have a clean working tree as the script does perform a hard reset on
+ your tree during its run.
+
+ The script reports two classes of issues, namely WARNINGs and ERRORs. Please
+ pay attention to both of them. The script will generally report WARNINGs
+ where it cannot be 100% sure that a particular issue is real. In most cases
+ WARNINGs indicate an issue that needs to be fixed. Sometimes the script will
+ report false positives; these will be handled in code review on a
+ case-by-case basis. Since the script only looks at changed lines,
+ occasionally changing one part of a line can cause the script to report a
+ style issue already present on that line that is unrelated to the change.
+ When convenient it is preferred that these be cleaned up inline, but this is
+ not required.
+
+ If the script finds one or more WARNINGs it will exit with 1. If it finds
+ one or more ERRORs it will exit with 2.
+
+
+Please remember that while FRR provides these tools for your convenience,
+responsibility for properly formatting your code ultimately lies on the
+shoulders of the submitter. As such, it is recommended to double-check the
+results of these tools to avoid delays in merging your submission.
**Whitespace changes in untouched parts of the code are not acceptable
in patches that change actual code.** To change/fix formatting issues,
large-community list. The third will add a large-community value without
overwriting other values. Multiple large-community values can be specified.
+
+.. _bgp-vrfs:
+
+BGP VRFs
+========
+
+Bgpd supports multiple VRF instances via the *router bgp* command:
+
+.. index:: router bgp ASN vrf VRFNAME
+.. clicmd:: router bgp ASN vrf VRFNAME
+
+VRFNAME is matched against VRFs configured in the kernel. When no
+*vrf VRFNAME* is specified, the BGP protocol process belongs to
+the default VRF.
+
+BGP routes may be leaked (i.e., copied) between a unicast VRF RIB
+and the VPN safi RIB of the default VRF (leaking is also permitted
+between the unicast RIB of the default VRF and VPN). A common
+application of this feature is to connect a customer's private
+routing domain to a provider's VPN service. Leaking is configured
+from the point of view of an individual VRF: ``import`` refers to
+routes leaked from VPN to a unicast VRF, whereas ``export`` refers
+to routes leaked from a unicast VRF to VPN.
+
+Required Parameters
+-------------------
+
+Routes exported from a unicast VRF to the VPN RIB must be augmented
+by two parameters:
+a route-distinguisher (RD) and a route-target list (RTLIST).
+Configuration for these exported routes must, at a minimum, specify
+these two parameters.
+
+Routes imported from the VPN RIB to a unicast VRF are selected
+according to their RTLISTs.
+Routes whose RTLIST contains at least one route-target in common with
+the configured import RTLIST are leaked.
+Configuration for these imported routes must specify an RTLIST to be matched.
+
+The RD, which carries no semantic value, is intended to make the
+route unique in the VPN RIB among all routes of its prefix that
+originate from all the customers and sites that are attached
+to the provider's VPN service. Accordingly, each site of each customer
+is typically assigned an RD that is unique across the entire provider
+network.
+
+The RTLIST is a set of route-target extended community values whose
+purpose is to specify route-leaking policy. Typically, a customer
+is assigned a single route-target value for import and export to be
+used at all customer sites. This configuration specifies a simple
+topology wherein a customer has a single routing domain which is
+shared across all its sites. More complex routing topologies are possible
+through use of additional route-targets to augment the leaking of
+sets of routes in various ways.
+
+Configuration
+-------------
+
+Configuration of route leaking between a unicast VRF RIB and the
+VPN safi RIB of the default VRF is accomplished via commands in the
+context of a VRF address-family:
+
+.. index:: rd vpn export AS:NN|IP:nn
+.. clicmd:: rd vpn export AS:NN|IP:nn
+
+ Specifies the route distinguisher to be added to a route exported
+ from the current unicast VRF to VPN.
+
+.. index:: no rd vpn export [AS:NN|IP:nn]
+.. clicmd:: no rd vpn export [AS:NN|IP:nn]
+
+ Deletes any previously-configured export route distinguisher.
+
+.. index:: rt vpn import|export|both RTLIST...
+.. clicmd:: rt vpn import|export|both RTLIST...
+
+ Specifies the route-target list to be attached to a route (export)
+ or the route-target list to match against (import) when
+ exporting/importing between the current unicast VRF and VPN.
+
+ The RTLIST is a space-separated list of route-targets, which are
+ BGP extended community values as described in
+ :ref:`bgp-extended-communities-attribute`.
+
+.. index:: no rt vpn import|export|both [RTLIST...]
+.. clicmd:: no rt vpn import|export|both [RTLIST...]
+
+ Deletes any previously-configured import or export route-target list.
+
+.. index:: label vpn export (0..1048575)
+.. clicmd:: label vpn export (0..1048575)
+
+ Specifies an optional MPLS label to be attached to a route exported
+ from the current unicast VRF to VPN.
+
+.. index:: no label vpn export [(0..1048575)]
+.. clicmd:: no label vpn export [(0..1048575)]
+
+ Deletes any previously-configured export label.
+
+.. index:: nexthop vpn export A.B.C.D|X:X::X:X
+.. clicmd:: nexthop vpn export A.B.C.D|X:X::X:X
+
+ Specifies an optional nexthop value to be assigned to a route exported
+ from the current unicast VRF to VPN. If left unspecified, the nexthop
+ will be set to 0.0.0.0 or 0:0::0:0 (self).
+
+.. index:: no nexthop vpn export [A.B.C.D|X:X::X:X]
+.. clicmd:: no nexthop vpn export [A.B.C.D|X:X::X:X]
+
+ Deletes any previously-configured export nexthop.
+
+.. index:: route-map vpn import|export MAP
+.. clicmd:: route-map vpn import|export MAP
+
+ Specifies an optional route-map to be applied to routes imported
+ or exported betwen the current unicast VRF and VPN.
+
+.. index:: no route-map vpn import|export [MAP]
+.. clicmd:: no route-map vpn import|export [MAP]
+
+ Deletes any previously-configured import or export route-map.
+
+.. index:: import|export vpn
+.. clicmd:: import|export vpn
+
+ Enables import or export of routes betwen the current unicast VRF and VPN.
+
+.. index:: no import|export vpn
+.. clicmd:: no import|export vpn
+
+ Disables import or export of routes betwen the current unicast VRF and VPN.
+
+
.. _displaying-bgp-information:
Displaying BGP information
--- /dev/null
+src.tar
+pkgs/
--- /dev/null
+FROM alpine:3.7 as source-builder
+ARG commit
+RUN apk add --no-cache abuild acct alpine-sdk attr 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 g++ gcc gdbm \
+ git gmp isl json-c 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 \
+ groff gzip bc py-sphinx
+RUN mkdir -p /src
+ADD src.tar /src
+RUN (cd /src && \
+ ./bootstrap.sh && \
+ ./configure \
+ --enable-numeric-version \
+ --with-pkg-extra-version=_git$commit && \
+ make dist)
+FROM alpine:3.7 as alpine-builder
+RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
+ADD alpine-build.sh /usr/bin/
+ADD builder /etc/sudoers.d
+COPY --from=source-builder /src/*.tar.gz /src/alpine/APKBUILD /dist/
+RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
+USER builder
+RUN /usr/bin/alpine-build.sh
--- /dev/null
+#!/bin/sh
+
+set -e
+
+cd /dist
+
+sudo apk --update add alpine-conf
+sudo setup-apkcache /var/cache/apk
+abuild-keygen -a -n
+abuild checksum
+abuild -r -P /pkgs/apk
--- /dev/null
+#!/bin/sh
+
+set -e
+set -v
+set -x
+
+##
+# commit must be converted to decimal
+##
+c=`git rev-parse --short=10 HEAD`
+commit=`printf '%u\n' 0x$c`
+git archive --format=tar $c > docker/alpine/src.tar
+(cd docker/alpine && \
+ docker build --build-arg commit=$commit --rm --force-rm -t \
+ frr:alpine-$c . && \
+ rm -f src.tar)
+
+id=`docker create frr:alpine-$c`
+docker cp ${id}:/pkgs/ docker
+docker rm $id
+docker rmi frr:alpine-$c
--- /dev/null
+builder ALL=(ALL) NOPASSWD:ALL
int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa)
{
- int bytesread = 0, bytestoread, offset, one = 1;
+ int bytesread = 0, bytestoread, offset, one = 1, err = ISIS_OK;
+ u_char *buff_ptr;
struct bpf_hdr *bpf_hdr;
assert(circuit->fd > 0);
}
if (bytesread < 0) {
zlog_warn("isis_recv_pdu_bcast(): read() failed: %s",
- safe_strerror(errno));
+ safe_strerror(errno));
return ISIS_WARNING;
}
if (bytesread == 0)
return ISIS_WARNING;
- bpf_hdr = (struct bpf_hdr *)readbuff;
+ buff_ptr = readbuff;
+ while (buff_ptr < readbuff + bytesread) {
+ bpf_hdr = (struct bpf_hdr *) buff_ptr;
+ assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
+ offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
- assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
+ /* then we lose the BPF, LLC and ethernet headers */
+ stream_write(circuit->rcv_stream, buff_ptr + offset,
+ bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
+ stream_set_getp(circuit->rcv_stream, 0);
- offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
+ memcpy(ssnpa, buff_ptr + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
+ ETHER_ADDR_LEN);
- /* then we lose the BPF, LLC and ethernet headers */
- stream_write(circuit->rcv_stream, readbuff + offset,
- bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
- stream_set_getp(circuit->rcv_stream, 0);
+ err = isis_handle_pdu(circuit, ssnpa);
+ stream_reset(circuit->rcv_stream);
+ buff_ptr += BPF_WORDALIGN(bpf_hdr->bh_hdrlen +
+ bpf_hdr->bh_datalen);
+ }
- memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, ETH_ALEN);
if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0)
zlog_warn("Flushing failed: %s", safe_strerror(errno));
* PDU Dispatcher
*/
-static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa)
+int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa)
{
int retval = ISIS_OK;
retval = circuit->rx(circuit, ssnpa);
+#if ISIS_METHOD != ISIS_METHOD_BPF
if (retval == ISIS_OK)
retval = isis_handle_pdu(circuit, ssnpa);
+#endif //ISIS_METHOD != ISIS_METHOD_BPF
/*
* prepare for next packet.
int send_lsp(struct thread *thread);
void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream);
int send_hello(struct isis_circuit *circuit, int level);
-
+int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa);
#endif /* _ZEBRA_ISIS_PDU_H */
"bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
"rfp defaults", // RFP_DEFAULTS_NODE,
"bgp evpn", // BGP_EVPN_NODE,
- "bgp vpn policy ipv4", // BGP_VPNPOLICY_IPV4_NODE
- "bgp vpn policy ipv6", // BGP_VPNPOLICY_IPV6_NODE
"ospf", // OSPF_NODE,
"ospf6", // OSPF6_NODE,
"ldp", // LDP_NODE,
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
- case BGP_VPNPOLICY_IPV4_NODE:
- case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_VRF_POLICY_NODE:
- case BGP_VPNPOLICY_IPV4_NODE:
- case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
case BABEL_NODE:
case BGP_NODE:
case BGP_VRF_POLICY_NODE:
- case BGP_VPNPOLICY_IPV4_NODE:
- case BGP_VPNPOLICY_IPV6_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
RFP_DEFAULTS_NODE, /* RFP defaults node */
BGP_EVPN_NODE, /* BGP EVPN node. */
- BGP_VPNPOLICY_IPV4_NODE, /* BGP VPN IPv6 policy */
- BGP_VPNPOLICY_IPV6_NODE, /* BGP VPN IPv6 policy */
OSPF_NODE, /* OSPF protocol mode */
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
LDP_NODE, /* LDP protocol mode */
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
- else if (strmatch(s, "vpn"))
- return ZEBRA_ROUTE_BGP_VPN;
}
if (afi == AFI_IP6) {
if (strmatch(s, "kernel"))
return ZEBRA_ROUTE_BABEL;
else if (strmatch(s, "sharp"))
return ZEBRA_ROUTE_SHARP;
- else if (strmatch(s, "vpn"))
- return ZEBRA_ROUTE_BGP_VPN;
}
return -1;
}
ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
# bgp unicast -> vnc
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
-ZEBRA_ROUTE_BGP_VPN, vpn, NULL, 'c', 1, 1, "VPN", bgpd
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
-ZEBRA_ROUTE_BGP_VPN, "BGP VPN routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
case NEXTHOP_TYPE_BLACKHOLE:
break;
}
+ STREAM_GETC(s, nhr->nexthops[i].label_num);
+ if (nhr->nexthops[i].label_num > MPLS_MAX_LABELS) {
+ zlog_warn("%s: invalid number of MPLS labels (%u)",
+ __func__, nhr->nexthops[i].label_num);
+ return false;
+ }
+ if (nhr->nexthops[i].label_num)
+ STREAM_GET(&nhr->nexthops[i].labels[0], s,
+ nhr->nexthops[i].label_num
+ * sizeof(mpls_label_t));
}
return true;
struct timeval ts_spf; /* SPF calculation time stamp. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
+ uint8_t intra_prefix_originate; /* Force intra_prefix lsa originate */
};
#define OSPF6_AREA_ENABLE 0x01
prefix2str(&prefix, buf, sizeof(buf));
zlog_debug("AS-External route %s not found", buf);
}
+
+ ospf6_route_delete(route_to_del);
return;
}
ospf6_lsa_premature_aging(lsa);
}
+/* Puring Multi Link-State IDs LSAs:
+ * Same Advertising Router with Multiple Link-State IDs
+ * LSAs, purging require to traverse all Link-State IDs
+ */
+void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa, struct ospf6_lsa *lsa)
+{
+ int ls_id = 0;
+ struct ospf6_lsa *lsa_next;
+ uint16_t type;
+
+ type = lsa->header->type;
+
+ ospf6_lsa_purge(lsa);
+
+ lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
+ oa->ospf6->router_id, oa->lsdb);
+ while (lsa_next) {
+ ospf6_lsa_purge(lsa_next);
+ lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
+ oa->ospf6->router_id, oa->lsdb);
+ }
+}
void ospf6_increment_retrans_count(struct ospf6_lsa *lsa)
{
struct ospf6_interface *oi);
extern void ospf6_lsa_purge(struct ospf6_lsa *lsa);
+extern void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa,
+ struct ospf6_lsa *lsa);
+
/* access method to retrans_count */
extern void ospf6_increment_retrans_count(struct ospf6_lsa *lsa);
extern void ospf6_decrement_retrans_count(struct ospf6_lsa *lsa);
return 0;
}
+ /* Neighbor change to FULL, if INTRA-AREA-PREFIX LSA
+ * has not change, Flush old LSA and Re-Originate INP,
+ * as ospf6_flood() checks if LSA is same as DB,
+ * it won't be updated to neighbor's DB.
+ */
+ if (oa->intra_prefix_originate) {
+ if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
+ zlog_debug("%s: Re-originate intra prefix LSA, Current full nbrs %u",
+ __PRETTY_FUNCTION__, oa->full_nbrs);
+ if (old)
+ ospf6_lsa_purge_multi_ls_id(oa, old);
+ oa->intra_prefix_originate = 0;
+ }
+
/* put prefixes to advertise */
prefix_num = 0;
op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if);
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if);
}
+ if (next_state == OSPF6_NEIGHBOR_FULL)
+ on->ospf6_if->area->intra_prefix_originate = 1;
+
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
if (prev_state == OSPF6_NEIGHBOR_LOADING
pim_socket_ip_hdr(fd);
if (interface == NULL) {
+ memset(&nexthop, 0, sizeof(nexthop));
ret = pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0);
if (ret != 0) {
+ close(fd);
if (PIM_DEBUG_MTRACE)
zlog_warn(
"Dropping mtrace packet, "
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace response to RP");
} else {
+ memset(&nexthop, 0, sizeof(nexthop));
/* TODO: should use unicast rib lookup */
ret = pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1);
nh_addr.s_addr = 0;
+ memset(&nexthop, 0, sizeof(nexthop));
ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
if (ret == 0) {
BuildRequires: gcc patch libcap-devel
BuildRequires: readline readline-devel ncurses ncurses-devel
BuildRequires: json-c-devel bison >= 2.7 flex make
+BuildRequires: c-ares-devel texinfo
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
BuildRequires: python27-devel python27-sphinx
*/
int suppress = 0;
struct rip_info *tmp_rinfo = NULL;
+ struct connected *tmp_ifc = NULL;
for (ALL_LIST_ELEMENTS_RO(list, listnode,
tmp_rinfo))
}
if (!suppress
- && rinfo->type == ZEBRA_ROUTE_CONNECT
- && prefix_match((struct prefix *)p,
- ifc->address))
- suppress = 1;
+ && rinfo->type == ZEBRA_ROUTE_CONNECT) {
+ for (ALL_LIST_ELEMENTS_RO(
+ ifc->ifp->connected,
+ listnode, tmp_ifc))
+ if (prefix_match(
+ (struct prefix *)p,
+ tmp_ifc->address)) {
+ suppress = 1;
+ break;
+ }
+ }
if (suppress)
continue;
* configured on the same interface).
*/
struct rip_info *tmp_rinfo = NULL;
+ struct connected *tmp_ifc = NULL;
for (ALL_LIST_ELEMENTS_RO(list, listnode,
tmp_rinfo))
if (tmp_rinfo->type == ZEBRA_ROUTE_RIP
&& tmp_rinfo->nh.ifindex
== ifc->ifp->ifindex)
- tmp_rinfo->metric_out =
+ rinfo->metric_out =
RIP_METRIC_INFINITY;
- if (rinfo->type == ZEBRA_ROUTE_CONNECT
- && prefix_match((struct prefix *)p,
- ifc->address))
- rinfo->metric_out = RIP_METRIC_INFINITY;
+ if (rinfo->metric_out != RIP_METRIC_INFINITY
+ && rinfo->type == ZEBRA_ROUTE_CONNECT) {
+ for (ALL_LIST_ELEMENTS_RO(
+ ifc->ifp->connected,
+ listnode, tmp_ifc))
+ if (prefix_match(
+ (struct prefix *)p,
+ tmp_ifc->address)) {
+ rinfo->metric_out =
+ RIP_METRIC_INFINITY;
+ break;
+ }
+ }
}
/* Prepare preamble, auth headers, if needs be */
extern uint32_t installed_routes;
extern uint32_t removed_routes;
+DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
+ "sharp watch nexthop X:X::X:X$nhop",
+ "Sharp routing Protocol\n"
+ "Watch for changes\n"
+ "Watch for nexthop changes\n"
+ "The v6 nexthop to signal for watching\n")
+{
+ struct prefix p;
+
+ memset(&p, 0, sizeof(p));
+
+ p.prefixlen = 128;
+ memcpy(&p.u.prefix6, &nhop, 16);
+ p.family = AF_INET6;
+
+ sharp_zebra_nexthop_watch(&p, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
+ "sharp watch nexthop A.B.C.D$nhop",
+ "Sharp routing Protocol\n"
+ "Watch for changes\n"
+ "Watch for nexthop changes\n"
+ "The v4 nexthop to signal for watching\n")
+{
+ struct prefix p;
+
+ memset(&p, 0, sizeof(p));
+
+ p.prefixlen = 32;
+ p.u.prefix4 = nhop;
+ p.family = AF_INET;
+
+ sharp_zebra_nexthop_watch(&p, true);
+
+ return CMD_SUCCESS;
+}
+
DEFPY (install_routes,
install_routes_cmd,
"sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes",
install_element(ENABLE_NODE, &install_routes_cmd);
install_element(ENABLE_NODE, &remove_routes_cmd);
install_element(ENABLE_NODE, &vrf_label_cmd);
+ install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
+ install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
return;
}
return;
}
+void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
+{
+ int command = ZEBRA_NEXTHOP_REGISTER;
+
+ if (!watch)
+ command = ZEBRA_NEXTHOP_UNREGISTER;
+
+ zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT);
+}
+
+static int sharp_nexthop_update(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct zapi_route nhr;
+ char buf[PREFIX_STRLEN];
+ int i;
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__);
+
+ return 0;
+ }
+
+ zlog_debug("Received update for %s",
+ prefix2str(&nhr.prefix, buf, sizeof(buf)));
+ for (i = 0; i < nhr.nexthop_num; i++) {
+ struct zapi_nexthop *znh = &nhr.nexthops[i];
+
+ switch (znh->type) {
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4:
+ zlog_debug(
+ "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
+ inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf,
+ sizeof(buf)),
+ znh->type, znh->ifindex, znh->vrf_id,
+ znh->label_num);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6:
+ zlog_debug(
+ "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
+ inet_ntop(AF_INET6, &znh->gate.ipv6, buf,
+ sizeof(buf)),
+ znh->type, znh->ifindex, znh->vrf_id,
+ znh->label_num);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ zlog_debug("\tNexthop IFINDEX: %d, ifindex: %d",
+ znh->type, znh->ifindex);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ zlog_debug("\tNexthop blackhole");
+ break;
+ }
+ }
+ return 0;
+}
+
extern struct zebra_privs_t sharp_privs;
void sharp_zebra_init(void)
zclient->interface_address_add = interface_address_add;
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
+ zclient->nexthop_update = sharp_nexthop_update;
}
extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
extern void route_add(struct prefix *p, struct nexthop *nh);
extern void route_delete(struct prefix *p);
+extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch);
#endif
} else if ((saved_node == KEYCHAIN_KEY_NODE
|| saved_node == LDP_PSEUDOWIRE_NODE
|| saved_node == LDP_IPV4_IFACE_NODE
- || saved_node == LDP_IPV6_IFACE_NODE
- || saved_node == BGP_VPNPOLICY_IPV4_NODE
- || saved_node == BGP_VPNPOLICY_IPV6_NODE)
+ || saved_node == LDP_IPV6_IFACE_NODE)
&& (tried == 1)) {
vtysh_execute("exit");
} else if (tried) {
} else if ((prev_node == BGP_EVPN_VNI_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit-vni\n");
- } else if ((prev_node == KEYCHAIN_KEY_NODE
- || prev_node == BGP_VPNPOLICY_IPV4_NODE
- || prev_node == BGP_VPNPOLICY_IPV6_NODE)
+ } else if ((prev_node == KEYCHAIN_KEY_NODE)
&& (tried == 1)) {
fprintf(outputfile, "exit\n");
} else if (tried) {
static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# "};
-static struct cmd_node bgp_vpn_policy_ipv4_node = {
- BGP_VPNPOLICY_IPV4_NODE, "%s(config-router-vpn-policy-ipv4)# ", 1};
-
-static struct cmd_node bgp_vpn_policy_ipv6_node = {
- BGP_VPNPOLICY_IPV6_NODE, "%s(config-router-vpn-policy-ipv6)# ", 1};
-
static struct cmd_node bgp_ipv6l_node = {BGP_IPV6L_NODE,
"%s(config-router-af)# "};
return CMD_SUCCESS;
}
-DEFUNSH(VTYSH_BGPD, vpn_policy_afi, vpn_policy_afi_cmd, "vpn-policy <ipv4|ipv6>",
- "Configure a VPN policy\n"
- BGP_AFI_HELP_STR)
-{
- int idx = 1;
-
- if (argv_find(argv, argc, "ipv4", &idx))
- vty->node = BGP_VPNPOLICY_IPV4_NODE;
- else
- vty->node = BGP_VPNPOLICY_IPV6_NODE;
- return CMD_SUCCESS;
-}
-
-
#if defined(ENABLE_BGP_VNC)
DEFUNSH(VTYSH_BGPD, vnc_defaults, vnc_defaults_cmd, "vnc defaults",
"VNC/RFP related configuration\n"
case BGP_IPV6M_NODE:
case BGP_IPV6L_NODE:
case BGP_VRF_POLICY_NODE:
- case BGP_VPNPOLICY_IPV4_NODE:
- case BGP_VPNPOLICY_IPV6_NODE:
case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
install_node(&bgp_vrf_policy_node, NULL);
install_node(&bgp_evpn_node, NULL);
install_node(&bgp_evpn_vni_node, NULL);
- install_node(&bgp_vpn_policy_ipv4_node, NULL);
- install_node(&bgp_vpn_policy_ipv6_node, NULL);
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
install_node(&bgp_vnc_l2_group_node, NULL);
install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_quit_bgpd_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VPNPOLICY_IPV4_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VPNPOLICY_IPV6_NODE, &vtysh_end_all_cmd);
install_element(ISIS_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
install_element(CONFIG_NODE, &router_bgp_cmd);
install_element(BGP_NODE, &address_family_vpnv4_cmd);
install_element(BGP_NODE, &address_family_vpnv6_cmd);
- install_element(BGP_NODE, &vpn_policy_afi_cmd);
#if defined(ENABLE_BGP_VNC)
install_element(BGP_NODE, &vnc_vrf_policy_cmd);
install_element(BGP_NODE, &vnc_defaults_cmd);
*/
frr_config_fork();
- /* Clean up rib -- before fork (?) */
- /* rib_weed_tables (); */
-
/* After we have successfully acquired the pidfile, we can be sure
* about being the only copy of zebra process, which is submitting
* changes to the FIB.
if (afi == AFI_MAX)
return 0;
- if (is_zebra_valid_kernel_table(table_id))
+ if (is_zebra_valid_kernel_table(table_id) &&
+ table_id < ZEBRA_KERNEL_TABLE_MAX)
return zebra_import_table_used[afi][table_id];
return 0;
}
RIB_UPDATE_OTHER
} rib_update_event_t;
-extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *,
- ifindex_t,
+extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
+ ifindex_t ifindex,
vrf_id_t nh_vrf_id);
-extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *,
- enum blackhole_type);
-extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *,
- struct in_addr *,
- struct in_addr *,
+extern struct nexthop *
+route_entry_nexthop_blackhole_add(struct route_entry *re,
+ enum blackhole_type bh_type);
+extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re,
+ struct in_addr *ipv4,
+ struct in_addr *src,
vrf_id_t nh_vrf_id);
extern struct nexthop *
-route_entry_nexthop_ipv4_ifindex_add(struct route_entry *, struct in_addr *,
- struct in_addr *, ifindex_t,
- vrf_id_t nh_vrf_id);
+route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
+ struct in_addr *ipv4, struct in_addr *src,
+ ifindex_t ifindex, vrf_id_t nh_vrf_id);
extern void route_entry_nexthop_delete(struct route_entry *re,
struct nexthop *nexthop);
-extern struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *,
- struct in6_addr *,
+extern struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re,
+ struct in6_addr *ipv6,
vrf_id_t nh_vrf_id);
extern struct nexthop *
route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
struct nexthop *nh);
#define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
-extern void _route_entry_dump(const char *, union prefixconstptr,
- union prefixconstptr, const struct route_entry *);
+extern void _route_entry_dump(const char *func, union prefixconstptr pp,
+ union prefixconstptr src_pp,
+ const struct route_entry *re);
/* RPF lookup behaviour */
enum multicast_mode {
MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */
extern void multicast_mode_ipv4_set(enum multicast_mode mode);
extern enum multicast_mode multicast_mode_ipv4_get(void);
-extern void rib_lookup_and_dump(struct prefix_ipv4 *, vrf_id_t);
-extern void rib_lookup_and_pushup(struct prefix_ipv4 *, vrf_id_t);
+extern void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id);
+extern void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id);
-extern int rib_lookup_ipv4_route(struct prefix_ipv4 *, union sockunion *,
- vrf_id_t);
+extern int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
+ vrf_id_t vrf_id);
#define ZEBRA_RIB_LOOKUP_ERROR -1
#define ZEBRA_RIB_FOUND_EXACT 0
#define ZEBRA_RIB_FOUND_NOGATE 1
u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
uint8_t distance, route_tag_t tag);
-extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *,
- struct prefix_ipv6 *src_p, struct route_entry *);
+extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re);
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
u_short instance, int flags, struct prefix *p,
u_int32_t table_id, u_int32_t metric, bool fromkernel,
struct ethaddr *rmac);
-extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t,
- union g_addr *,
+extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
+ union g_addr *addr,
struct route_node **rn_out);
extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
struct in_addr addr,
struct route_node **rn_out);
-extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *, vrf_id_t);
+extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
+ vrf_id_t vrf_id);
-extern void rib_update(vrf_id_t, rib_update_event_t);
-extern void rib_weed_tables(void);
+extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event);
extern void rib_sweep_route(void);
-extern void rib_close_table(struct route_table *);
+extern void rib_sweep_table(struct route_table *table);
+extern void rib_close_table(struct route_table *table);
extern void rib_init(void);
extern unsigned long rib_score_proto(u_char proto, u_short instance);
+extern unsigned long rib_score_proto_table(u_char proto, u_short instance,
+ struct route_table *table);
extern void rib_queue_add(struct route_node *rn);
extern void meta_queue_free(struct meta_queue *mq);
extern int zebra_rib_labeled_unicast(struct route_entry *re);
extern struct route_table *rib_table_ipv6;
-extern void rib_unlink(struct route_node *, struct route_entry *);
+extern void rib_unlink(struct route_node *rn, struct route_entry *re);
extern int rib_gc_dest(struct route_node *rn);
extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter);
fec_print(rn->info, vty);
}
+static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
+ enum lsp_types_t type, mpls_label_t label)
+{
+ if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
+ nexthop_add_labels(nexthop, type, 1, &label);
+ else if (!add && nexthop->nh_label_type == type)
+ nexthop_del_labels(nexthop);
+ else
+ return false;
+
+ return true;
+}
+
/*
* Install/uninstall a FEC-To-NHLFE (FTN) binding.
*/
struct route_node *rn;
struct route_entry *re;
struct nexthop *nexthop;
+ bool found;
/* Lookup table. */
table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
if (re == NULL)
return -1;
+ found = false;
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
&& nexthop->ifindex != ifindex)
continue;
- goto found;
+ if (!mpls_ftn_update_nexthop(add, nexthop, type,
+ out_label))
+ return 0;
+ found = true;
+ break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
if (gtype != NEXTHOP_TYPE_IPV6
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
&& nexthop->ifindex != ifindex)
continue;
- goto found;
+ if (!mpls_ftn_update_nexthop(add, nexthop, type,
+ out_label))
+ return 0;
+ found = true;
+ break;
default:
break;
}
}
- /* nexthop not found */
- return -1;
-found:
- if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE)
- nexthop_add_labels(nexthop, type, 1, &out_label);
- else if (!add && nexthop->nh_label_type == type)
- nexthop_del_labels(nexthop);
- else
- return 0;
+ if (!found)
+ return -1;
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
if (sock < 0) {
zlog_err("netlink( %u) socket() error: %s", sock,
safe_strerror(errno));
+ close(fd);
return NS_UNKNOWN;
}
memset(&snl, 0, sizeof(snl));
if (fd == -1)
return NS_DEFAULT_INTERNAL;
- if (!vrf_is_backend_netns())
+ if (!vrf_is_backend_netns()) {
+ close(fd);
return NS_DEFAULT_INTERNAL;
+ }
close(fd);
return zebra_ns_id_get((char *)NS_DEFAULT_NAME);
#else /* HAVE_NETNS */
#include "zebra_netns_notify.h"
#include "zebra_netns_id.h"
#include "zebra_pbr.h"
+#include "rib.h"
extern struct zebra_privs_t zserv_privs;
return NULL;
}
+unsigned long zebra_ns_score_proto(u_char proto, u_short instance)
+{
+ struct zebra_ns *zns;
+ struct zebra_ns_table *znst;
+ unsigned long cnt = 0;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables)
+ cnt += rib_score_proto_table(proto, instance, znst->table);
+
+ return cnt;
+}
+
+void zebra_ns_sweep_route(void)
+{
+ struct zebra_ns_table *znst;
+ struct zebra_ns *zns;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables)
+ rib_sweep_table(znst->table);
+}
+
struct route_table *zebra_ns_get_table(struct zebra_ns *zns,
struct zebra_vrf *zvrf, uint32_t tableid,
afi_t afi)
struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi);
int zebra_ns_config_write(struct vty *vty, struct ns *ns);
+
+unsigned long zebra_ns_score_proto(u_char proto, u_short instance);
+void zebra_ns_sweep_route(void);
#endif
__PRETTY_FUNCTION__);
}
+static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data)
+{
+ struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+ struct zebra_pbr_rule *rule = b->data;
+ int *sock = data;
+
+ if (rule->sock == *sock) {
+ kernel_del_pbr_rule(rule);
+ hash_release(zns->rules_hash, rule);
+ }
+}
+
+void zebra_pbr_client_close_cleanup(int sock)
+{
+ struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+
+ hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock);
+}
+
/*
* Handle success or failure of rule (un)install in the kernel.
*/
*/
extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule);
+extern void zebra_pbr_client_close_cleanup(int sock);
+
extern void zebra_pbr_rules_free(void *arg);
extern uint32_t zebra_pbr_rules_hash_key(void *arg);
extern int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2);
+
#endif /* _ZEBRA_PBR_H */
int is_zebra_valid_kernel_table(u_int32_t table_id)
{
- if ((table_id > ZEBRA_KERNEL_TABLE_MAX))
- return 0;
-
#ifdef linux
if ((table_id == RT_TABLE_UNSPEC) || (table_id == RT_TABLE_LOCAL)
|| (table_id == RT_TABLE_COMPAT))
[ZEBRA_ROUTE_VNC_DIRECT_RH] = 3,
[ZEBRA_ROUTE_BGP_DIRECT] = 3,
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = 3,
- [ZEBRA_ROUTE_BGP_VPN] = 3,
[ZEBRA_ROUTE_BABEL] = 2,
[ZEBRA_ROUTE_ALL] = 4, // Shouldn't happen but for safety
};
rib_update_table(table, event);
}
-/* Remove all routes which comes from non main table. */
-static void rib_weed_table(struct route_table *table)
-{
- struct route_node *rn;
- struct route_entry *re;
- struct route_entry *next;
-
- if (table)
- for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
- RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
- continue;
-
- if (re->table != zebrad.rtm_table_default
- && re->table != RT_TABLE_MAIN)
- rib_delnode(rn, re);
- }
-}
-
-/* Delete all routes from non main table. */
-void rib_weed_tables(void)
-{
- struct vrf *vrf;
- struct zebra_vrf *zvrf;
-
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
- if ((zvrf = vrf->info) != NULL) {
- rib_weed_table(zvrf->table[AFI_IP][SAFI_UNICAST]);
- rib_weed_table(zvrf->table[AFI_IP6][SAFI_UNICAST]);
- }
-}
-
/* Delete self installed routes after zebra is relaunched. */
-static void rib_sweep_table(struct route_table *table)
+void rib_sweep_table(struct route_table *table)
{
struct route_node *rn;
struct route_entry *re;
rib_sweep_table(zvrf->table[AFI_IP][SAFI_UNICAST]);
rib_sweep_table(zvrf->table[AFI_IP6][SAFI_UNICAST]);
}
+
+ zebra_ns_sweep_route();
}
/* Remove specific by protocol routes from 'table'. */
-static unsigned long rib_score_proto_table(u_char proto, u_short instance,
- struct route_table *table)
+unsigned long rib_score_proto_table(u_char proto, u_short instance,
+ struct route_table *table)
{
struct route_node *rn;
struct route_entry *re;
proto, instance,
zvrf->table[AFI_IP6][SAFI_UNICAST]);
+ cnt += zebra_ns_score_proto(proto, instance);
+
return cnt;
}
struct route_entry *re;
unsigned long nump;
u_char num;
- struct nexthop *nexthop;
+ struct nexthop *nh;
struct route_node *rn;
int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE
: ZEBRA_NEXTHOP_UPDATE;
num = 0;
nump = stream_get_endp(s);
stream_putc(s, 0);
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
- if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
- || CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE))
- && CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_ACTIVE)) {
- stream_putc(s, nexthop->type);
- switch (nexthop->type) {
+ for (nh = re->ng.nexthop; nh; nh = nh->next)
+ if ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+ || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) {
+ stream_putc(s, nh->type);
+ switch (nh->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- stream_put_in_addr(s,
- &nexthop->gate.ipv4);
- stream_putl(s, nexthop->ifindex);
+ stream_put_in_addr(s, &nh->gate.ipv4);
+ stream_putl(s, nh->ifindex);
break;
case NEXTHOP_TYPE_IFINDEX:
- stream_putl(s, nexthop->ifindex);
+ stream_putl(s, nh->ifindex);
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- stream_put(s, &nexthop->gate.ipv6, 16);
- stream_putl(s, nexthop->ifindex);
+ stream_put(s, &nh->gate.ipv6, 16);
+ stream_putl(s, nh->ifindex);
break;
default:
/* do nothing */
break;
}
+ if (nh->nh_label) {
+ stream_putc(s,
+ nh->nh_label->num_labels);
+ if (nh->nh_label->num_labels)
+ stream_put(
+ s,
+ &nh->nh_label->label[0],
+ nh->nh_label->num_labels
+ * sizeof(mpls_label_t));
+ } else
+ stream_putc(s, 0);
num++;
}
stream_putc_at(s, nump, num);
if (ret)
return ret;
- ret = strcmp(shr2->nhvrf_name, shr2->nhvrf_name);
+ ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
if (ret)
return ret;
return CMD_SUCCESS;
}
+ XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr);
/*
* If a person enters the same line again
* we need to silently accept it
if (shr->flag_str)
vty_out(vty, "%s ", shr->flag_str);
if (shr->tag_str)
- vty_out(vty, "tag %s", shr->tag_str);
+ vty_out(vty, "tag %s ", shr->tag_str);
if (shr->distance_str)
vty_out(vty, "%s ", shr->distance_str);
if (shr->label_str)
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
/* Check this client need interface information. */
- if (!client->ifinfo)
+ if (!client->ifinfo) {
+ stream_free(s);
return 0;
+ }
- if (!ifp->link_params)
+ if (!ifp->link_params) {
+ stream_free(s);
return 0;
+ }
zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id);
stream_putl(s, ifp->ifindex);
/* Then TE Link Parameters */
- if (zebra_interface_link_params_write(s, ifp) == 0)
+ if (zebra_interface_link_params_write(s, ifp) == 0) {
+ stream_free(s);
return 0;
+ }
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
/* Encode route and send. */
- if (zapi_route_encode(cmd, s, &api) < 0)
+ if (zapi_route_encode(cmd, s, &api) < 0) {
+ stream_free(s);
return -1;
+ }
if (IS_ZEBRA_DEBUG_SEND) {
char buf_prefix[PREFIX_STRLEN];
struct ipaddr vtep_ip;
s = msg;
- zapi_route_decode(s, &api);
+ if (zapi_route_decode(s, &api) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_route sent",
+ __PRETTY_FUNCTION__);
+ return;
+ }
if (IS_ZEBRA_DEBUG_RECV) {
char buf_prefix[PREFIX_STRLEN];
struct stream *msg,
struct zebra_vrf *zvrf)
{
- if (hdr->command > sizeof(zserv_handlers)
+ if (hdr->command > array_size(zserv_handlers)
|| zserv_handlers[hdr->command] == NULL)
zlog_info("Zebra received unknown command %d", hdr->command);
else
/* Send client de-registration to BFD */
zebra_ptm_bfd_client_deregister(client->proto);
+ /* Cleanup any rules installed from this client */
+ zebra_pbr_client_close_cleanup(client->sock);
+
/* Cleanup any registered nexthops - across all VRFs. */
zebra_client_close_cleanup_rnh(client);