Merge branch 'master' into babel_nonzero_interval

Signed-off-by: Mingwei Zheng <zmw12306@gmail.com>
This commit is contained in:
Mingwei Zheng 2024-10-05 12:26:16 -04:00 committed by GitHub
commit 6cb374a174
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3340 changed files with 279913 additions and 71914 deletions

View file

@ -1,92 +1,231 @@
# SPDX-License-Identifier: GPL-2.0
# clang-format configuration file. Intended for clang-format >= 11.
# If the version is changed also check that CI tool frrbot is updated.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
BasedOnStyle: LLVM
Language: Cpp
IndentWidth: 8
UseTab: Always
BreakBeforeBraces: Linux
AlwaysBreakBeforeMultilineStrings: true
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
# FRR: Right
AlignEscapedNewlines: Right
AlignOperands: Align
# FRR: true
AlignTrailingComments: true
# FRR: true
AlignConsecutiveMacros: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
IndentCaseLabels: false
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AlignAfterOpenBracket: true
SpaceAfterCStyleCast: false
MaxEmptyLinesToKeep: 2
BreakBeforeBinaryOperators: None
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
SortIncludes: false
ColumnLimit: 100
# Linux: CommentPragmas: '^ IWYU pragma:'
CommentPragmas: '\$(FRR|clippy)'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
# Some taken from:
# git grep -h '^#define [^[:space:]]*frr_(each|with)[^[:space:]]*(' ./ \
# | sed "s,^#define \([^[:space:]]*frr_(each|with)[^[:space:]]*\)(.*$, - '\1'," \
# | LC_ALL=C sort -u
# and
# git grep -h '^#define [^[:space:]]*FOREACH[^[:space:]]*(' ./
# | sed "s,^#define \([^[:space:]]*FOREACH[^)]*\)(.*, - '\1',"
# | LC_ALL=C sort -u
ForEachMacros:
# lib: outliers:
- 'FOR_ALL_INTERFACES'
# libyang outliers:
- 'LY_FOR_KEYS'
- 'LY_LIST_FOR'
- 'LYD_LIST_FOR_INST'
- 'LYD_LIST_FOR_INST_SAFE'
- 'LY_TREE_FOR'
- 'LY_TREE_DFS_BEGIN'
- 'LYD_TREE_DFS_BEGIN'
# ospfd outliers:
- 'LSDB_LOOP'
# first git grep
- 'darr_foreach_p'
- 'darr_foreach_i'
- 'frr_each'
- 'frr_each_safe'
- 'frr_each_from'
- 'frr_rev_each'
- 'frr_rev_each_safe'
- 'frr_rev_each_from'
- 'frr_with_mutex'
- 'frr_with_privs'
# second git grep
- 'AF_FOREACH'
- 'FOREACH_ADAPTER_IN_LIST'
- 'FOREACH_AFI_SAFI'
- 'FOREACH_AFI_SAFI_NSF'
- 'FOREACH_BE_APPLY_BATCH_IN_LIST'
- 'FOREACH_BE_CLIENT_BITS'
- 'FOREACH_BE_TXN_BATCH_IN_LIST'
- 'FOREACH_BE_TXN_IN_LIST'
- 'FOREACH_CMT_REC'
- 'FOREACH_MGMTD_BE_CLIENT_ID'
- 'FOREACH_MGMTD_DS_ID'
- 'FOREACH_SAFI'
- 'FOREACH_SESSION_IN_LIST'
- 'FOREACH_TXN_CFG_BATCH_IN_LIST'
- 'FOREACH_TXN_IN_LIST'
- 'FOREACH_TXN_REQ_IN_LIST'
- 'JSON_FOREACH'
- 'LIST_FOREACH'
- 'LIST_FOREACH_SAFE'
- 'RB_FOREACH'
- 'RB_FOREACH_REVERSE'
- 'RB_FOREACH_REVERSE_SAFE'
- 'RB_FOREACH_SAFE'
- 'RE_DEST_FOREACH_ROUTE'
- 'RE_DEST_FOREACH_ROUTE_SAFE'
- 'RNODE_FOREACH_RE'
- 'RNODE_FOREACH_RE_SAFE'
- 'SIMPLEQ_FOREACH'
- 'SIMPLEQ_FOREACH_SAFE'
- 'SLIST_FOREACH'
- 'SLIST_FOREACH_PREVPTR'
- 'SLIST_FOREACH_SAFE'
- 'SPLAY_FOREACH'
- 'STAILQ_FOREACH'
- 'STAILQ_FOREACH_SAFE'
- 'SUBGRP_FOREACH_ADJ'
- 'SUBGRP_FOREACH_ADJ_SAFE'
- 'SUBGRP_FOREACH_PEER'
- 'SUBGRP_FOREACH_PEER_SAFE'
- 'TAILQ_FOREACH'
- 'TAILQ_FOREACH_REVERSE'
- 'TAILQ_FOREACH_REVERSE_SAFE'
- 'TAILQ_FOREACH_SAFE'
- 'UPDGRP_FOREACH_SUBGRP'
- 'UPDGRP_FOREACH_SUBGRP_SAFE'
- 'XSIMPLEQ_FOREACH'
- 'XSIMPLEQ_FOREACH_SAFE'
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^(<|lib)'
Priority: 0
CommentPragmas: '\$(FRR|clippy)'
ContinuationIndentWidth: 8
ForEachMacros:
# lib
- frr_each
- frr_each_safe
- frr_each_from
- frr_rev_each
- frr_rev_each_safe
- frr_rev_each_from
- frr_with_mutex
- frr_with_privs
- LIST_FOREACH
- LIST_FOREACH_SAFE
- SLIST_FOREACH
- SLIST_FOREACH_SAFE
- SLIST_FOREACH_PREVPTR
- STAILQ_FOREACH
- STAILQ_FOREACH_SAFE
- TAILQ_FOREACH
- TAILQ_FOREACH_SAFE
- TAILQ_FOREACH_REVERSE
- TAILQ_FOREACH_REVERSE_SAFE
- RB_FOREACH
- RB_FOREACH_SAFE
- RB_FOREACH_REVERSE
- RB_FOREACH_REVERSE_SAFE
- SPLAY_FOREACH
- FOR_ALL_INTERFACES
- FOR_ALL_INTERFACES_ADDRESSES
- JSON_FOREACH
- FOREACH_BE_TXN_BATCH_IN_LIST
- FOREACH_BE_APPLY_BATCH_IN_LIST
- FOREACH_BE_TXN_IN_LIST
- FOREACH_SESSION_IN_LIST
- FOREACH_MGMTD_BE_CLIENT_ID
# libyang
- LY_FOR_KEYS
- LY_LIST_FOR
- LY_TREE_FOR
- LY_TREE_DFS_BEGIN
- LYD_TREE_DFS_BEGIN
# zebra
- RE_DEST_FOREACH_ROUTE
- RE_DEST_FOREACH_ROUTE_SAFE
- RNODE_FOREACH_RE
- RNODE_FOREACH_RE_SAFE
# bgpd
- UPDGRP_FOREACH_SUBGRP
- UPDGRP_FOREACH_SUBGRP_SAFE
- SUBGRP_FOREACH_PEER
- SUBGRP_FOREACH_PEER_SAFE
- SUBGRP_FOREACH_ADJ
- SUBGRP_FOREACH_ADJ_SAFE
- AF_FOREACH
- FOREACH_AFI_SAFI
- FOREACH_AFI_SAFI_NSF
- FOREACH_SAFI
# ospfd
- LSDB_LOOP
# mgmtd
- FOREACH_CMT_REC
- FOREACH_TXN_CFG_BATCH_IN_LIST
- FOREACH_TXN_REQ_IN_LIST
- FOREACH_TXN_IN_LIST
- FOREACH_MGMTD_DB_ID
- FOREACH_ADAPTER_IN_LIST
- FOREACH_SESSION_IN_LIST
- FOREACH_SESSION_IN_LIST_SAFE
## New: XXX whats it mean?
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
## Linux: MaxEmptyLinesToKeep: 1
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
## Lowest Penalty Value wins. Values are used by clang-format to influence
## the brak decisions, it's a bit of voodoo magic though.
## Originally from linux which was "Taken from git's rules"
PenaltyBreakAssignment: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
# Don't break a string into multi-string-fragments
PenaltyBreakString: 1000
# Allow going past the ColumnLimit to keep function arguments aligned
# with the open parenthesis.
PenaltyBreakBeforeFirstCallParameter: 1000
# Try and stay under ColumnLimit, but not at the cost of incomprehensible code.
PenaltyExcessCharacter: 30
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
WhitespaceSensitiveMacros:
- "DEFPY"
- "DEFPY_HIDDEN"
- "DEFPY_NOSH"
- "DEFPY_YANG"
- "DEFPY_YANG_HIDDEN"
- "DEFPY_YANG_NOSH"
- "DEFSH"
- "DEFSH_HIDDEN"
- "DEFUN"
- "DEFUN_HIDDEN"
- "DEFUN_NOSH"
- "DEFUN_YANG"
- "DEFUN_YANG_HIDDEN"
- "DEFUN_YANG_NOSH"
- "DEFUNSH"
- "DEFUNSH_HIDDEN"
- "ALIAS"
- "ALIAS_HIDDEN"
- "ALIAS_YANG"
- "ALIAS_DEPRECATED"
...

View file

@ -20,3 +20,5 @@ c14777c6bfd0a446c85243d3a9835054a259c276
8451921b70044a2c1075e7ba391f095fabee2550
bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c
96941f80927ce31a41f7d1905717f099187be723
# apply `black` python formatting for all tests/topotests
1a1c2a9f84d0ad1bdadc0cb47d6175d4ccc32544

View file

@ -1,97 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: triage
assignees: ''
---
<!--
*** ATTENTION ***
YOU MUST READ THIS TO HAVE YOUR ISSUE ADDRESSED
PLEASE READ AND FILL OUT THIS TEMPLATE
NEGLECTING TO PROVIDE INFORMATION REQUESTED HERE WILL RESULT IN
SIGNIFICANT DELAYS ADDRESSING YOUR ISSUE
ALWAYS PROVIDE:
- FRR VERSION
- OPERATING SYSTEM VERSION
- KERNEL VERSION
FAILURE TO PROVIDE THIS MAY RESULT IN YOUR ISSUE BEING IGNORED
FOLLOW THESE GUIDELINES:
- When reporting a crash, provide a backtrace
- When pasting configs, logs, shell output, backtraces, and other large chunks
of text, surround this text with triple backtics
```
like this
```
- Include the FRR version; if you built from Git, please provide the commit
hash
- Write your issue in English
-->
---------------
**Describe the bug**
<!--
A clear and concise description of what the bug is.
Put "x" in "[ ]" if you already tried following:
-->
- [ ] Did you check if this is a duplicate issue?
- [ ] Did you test it on the latest FRRouting/frr master branch?
**To Reproduce**
<!--
Describe the steps to reproduce the behavior.
Be as descriptive as possible.
For example:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
**Expected behavior**
<!--
Write here a clear and concise description of what you expected to happen when
using the reproduction steps you provided above
-->
**Screenshots**
<!--
If applicable, add screenshots to help explain your problem.
-->
**Versions**
<!--
Include your operating system type and version here
FAILURE TO PROVIDE THIS MAY RESULT IN YOUR ISSUE BEING IGNORED
-->
<!-- e.g. Fedora 24, Debian 10] -->
- OS Version:
<!-- [e.g. Linux 5.4, OpenBSD 6.6] -->
- Kernel:
<!-- e.g. 6.0, 7.4 -->
- FRR Version:
**Additional context**
<!--
Add any other context about the problem here.
-->

78
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,78 @@
name: Bug report
description: Report a bug in the FRRouting software
labels: triage
body:
- type: markdown
attributes:
value: >
**This form is only for reporting a bug in the FRRouting software.**
If you need help troubleshooting your configuration, have a problem
building or installing the software, or want to ask a question or
discuss the project, learn how to [connect with the FRRouting
community](https://frrouting.org/community/).
**Do not include sensitive information in this report.** IP addresses
should be masked (example: 192.XXX.XXX.32/24).
- type: textarea
id: description
attributes:
label: Description
description: Provide a clear and concise description of the bug.
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: >
Run the `show version` command in the VTY shell, and provide the output
here. (If possible, test the current development version of FRRouting
for this bug.)
render: text
validations:
required: true
- type: textarea
id: how-to-reproduce
attributes:
label: How to reproduce
description: >
Give a list of steps that someone else can follow to observe
the bug. Be as descriptive as possible, including any relevant
configuration files and commands used. Topology diagrams are
helpful when the bug involves more than one router.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: >
What do you expect to happen when following the steps above?
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual behavior
description: >
What actually happens when following the steps above? Include
screenshots, log file snippets, and/or platform routing tables
as appropriate. If a crash occurs, provide a backtrace.
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: >
Include any other relevant information about this bug here.
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I have searched the open issues for this bug.
required: true
- label: I have not included sensitive information in this report.
required: true

28
.github/workflows/behind-base.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: Add rebase label if the branch is > 50 commits behind
on:
pull_request_target:
types: [synchronize, opened, reopened, labeled, unlabeled]
jobs:
behind:
if: github.repository == 'frrouting/frr'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Set custom variables
id: vars
run: |
echo "behind_by=$(git log --oneline origin/${{ github.base_ref }} ^${{ github.event.pull_request.head.sha }} | wc -l)" >> $GITHUB_OUTPUT
- name: Add rebase label if needed
if: ${{ steps.vars.outputs.behind_by > 50 }}
uses: actions-ecosystem/action-add-labels@v1
with:
labels: rebase

163
.github/workflows/build-test-docker.yml vendored Normal file
View file

@ -0,0 +1,163 @@
name: build-test
on:
pull_request:
push:
branches:
- 'master'
- 'stable/**'
defaults:
run:
shell: bash
jobs:
build-docker:
name: Build the ubuntu 22.04 docker image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Build docker image
run: |
docker build -t frr-ubuntu22 -f docker/ubuntu-ci/Dockerfile .
docker save --output /tmp/frr-ubuntu22.tar frr-ubuntu22
- name: Upload docker image artifact
uses: actions/upload-artifact@v4
with:
name: ubuntu-image
path: /tmp/frr-ubuntu22.tar
- name: Clear any previous results
# So if all jobs are re-run then all tests will be re-run
run: |
rm -rf test-results*
mkdir -p test-results
touch test-results/cleared-results.txt
- name: Save cleared previous results
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results
overwrite: true
- name: Cleanup
if: ${{ always() }}
run: rm -rf test-results* /tmp/frr-ubuntu22.tar
test-docker:
name: Test ubuntu docker image
needs: build-docker
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Fetch docker image artifact
uses: actions/download-artifact@v4
with:
name: ubuntu-image
path: /tmp
- name: Fetch previous results
if: ${{ github.run_attempt > 1 }}
uses: actions/download-artifact@v4
with:
name: test-results
path: test-results
- name: Run topotests
run: |
uname -a
MODPKGVER=$(uname -r)
sudo apt-get update -y
# Github is running old kernels but installing newer packages :(
sudo apt-get install -y linux-modules-extra-azure linux-modules-${MODPKGVER} linux-modules-extra-${MODPKGVER} python3-xmltodict
sudo modprobe vrf || true
sudo modprobe mpls-iptunnel
sudo modprobe mpls-router
docker load --input /tmp/frr-ubuntu22.tar
if ! grep CONFIG_IP_MROUTE_MULTIPLE_TABLES=y /boot/config*; then
ADD_DOCKER_ENV+="-e MROUTE_VRF_MISSING=1"
fi
echo "ADD_DOCKER_ENV: ${ADD_DOCKER_ENV}"
if [ -f test-results/topotests.xml ]; then
./tests/topotests/analyze.py -r test-results
ls -l test-results/topotests.xml
run_tests=$(./tests/topotests/analyze.py -r test-results | cut -f1 -d: | sort -u)
else
echo "No test results dir"
run_tests=""
fi
rm -rf test-results* /tmp/topotests
echo RUN_TESTS: $run_tests
if docker run --init -i --privileged --name frr-ubuntu-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-ubuntu22 \
bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest -n$(($(nproc) * 5 / 2)) --dist=loadfile '$run_tests; then
echo "All tests passed."
exit 0
fi
# Grab the results from the container
if ! ./tests/topotests/analyze.py -Ar test-results -C frr-ubuntu-cont; then
if [ ! -d test-results ]; then
echo "ERROR: Basic failure in docker run, no test results directory available." >&2
exit 1;
fi
if [ ! -f test-results/topotests.xml ]; then
# In this case we may be missing topotests.xml
echo "ERROR: No topotests.xml available perhaps docker run aborted?" >&2
exit 1;
fi
echo "WARNING: analyyze.py returned error but grabbed results anyway." >&2
fi
# Save some information useful for debugging
cp /boot/config* test-results/
sysctl -a > test-results/sysctl.out 2> /dev/null
# Now get the failed tests (if any) from the archived results directory.
rerun_tests=$(./tests/topotests/analyze.py -r test-results | cut -f1 -d: | sort -u)
if [ -z "$rerun_tests" ]; then
echo "All tests passed during parallel run."
exit 0
fi
echo "ERROR: Some tests failed during parallel run, rerunning serially." >&2
echo RERUN_TESTS: $rerun_tests >&2
docker stop frr-ubuntu-cont
docker rm frr-ubuntu-cont
mv test-results test-results-initial
if docker run --init -i --privileged --name frr-ubuntu-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-ubuntu22 \
bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest '$rerun_tests; then
echo "All rerun tests passed."
exit 0
fi
echo "Some rerun tests still failed."
exit 1
- name: Gather results
if: ${{ always() }}
run: |
if [ ! -d test-results ]; then
if ! ./tests/topotests/analyze.py -Ar test-results -C frr-ubuntu-cont; then
echo "ERROR: gathering results produced an error, perhaps due earlier run cancellation." >&2
fi
fi
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
test-results
test-results-initial
overwrite: true
- name: Cleanup
if: ${{ always() }}
run: |
rm -rf test-results* /tmp/frr-ubuntu22.tar
docker stop frr-ubuntu-cont || true
docker rm frr-ubuntu-cont || true

View file

@ -1,9 +1,8 @@
name: Add a conflict label if PR needs to rebase
on:
push:
pull_request_target:
types: [synchronize]
types: [opened, reopened, synchronize]
jobs:
conflicts:

View file

@ -1,4 +1,4 @@
name: Warn before merging if a "freeze" label exists
name: Warn before merging if a "freeze" or "do not merge" label exists
on:
pull_request_target:
@ -6,12 +6,12 @@ on:
jobs:
freeze_warning:
if: ${{ contains(github.event.*.labels.*.name, 'freeze') }}
name: Warn before merging if a "freeze" label exists
if: ${{ contains(github.event.*.labels.*.name, 'freeze') || contains(github.event.*.labels.*.name, 'do not merge') }}
name: Warn before merging if a "freeze" or "do not merge" label exists
runs-on: ubuntu-latest
steps:
- name: Check for "freeze" label
run: |
echo "Pull request is labeled as 'freeze'"
echo "Pull request is labeled as 'freeze' or 'do not merge'"
echo "This workflow fails so that the pull request cannot be merged."
exit 1

3
.gitignore vendored
View file

@ -62,6 +62,7 @@
*.cg.dot
*.cg.svg
*.xref
*_tsexpand.h
### gcov outputs
@ -106,6 +107,7 @@ GSYMS
GRTAGS
GPATH
compile_commands.json
.ccls
.ccls-cache
.dirstamp
refix
@ -116,3 +118,4 @@ refix
/test-suite.log
pceplib/test/*.log
pceplib/test/*.trs
/tests/topotests/lib/mgmt_pb2.py

View file

@ -56,7 +56,7 @@ MODULE_LDFLAGS = \
$(SAN_FLAGS) \
# end
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE)
DEFS = @DEFS@ -DCONFDATE=$(CONFDATE)
AR_FLAGS = @AR_FLAGS@
ARFLAGS = @ARFLAGS@

View file

@ -13,13 +13,13 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
expat fakeroot flex fortify-headers gdbm git gmp json-c-dev kmod
lddtree libacl libatomic libattr libblkid libburn libbz2 libc-dev
libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
libltdl libressl libssh2 libstdc++ libtool libuuid
libltdl openssl libssh2 libstdc++ libtool libuuid
linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre2
perl pkgconf python3 python3-dev readline readline-dev sqlite-libs pcre2-dev
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
py3-sphinx elfutils elfutils-dev libyang-dev protobuf-c-compiler protobuf-c-dev
lua5.3-dev lua5.3"
py3-sphinx elfutils elfutils-dev protobuf-c-compiler protobuf-c-dev
lua5.3-dev lua5.3 gzip"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
@ -27,21 +27,22 @@ source="$pkgname-$pkgver.tar.gz"
builddir="$srcdir"/$pkgname-$pkgver
_sysconfdir=/etc
_sbindir=/usr/lib/frr
_sysconfdir=/etc/frr
_libdir=/usr/lib
_localstatedir=/var/run/frr
_user=frr
build() {
export ABUILD_APK_INDEX_OPTS="--allow-untrusted"
cd "$builddir"
./configure \
--prefix=/usr \
--sbindir=$_sbindir \
--sysconfdir=$_sysconfdir \
--localstatedir=/var \
--sbindir=$_sbindir \
--libdir=$_libdir \
--localstatedir=$_localstatedir \
--enable-rpki \
--enable-vtysh \
--enable-multipath=64 \
@ -63,7 +64,9 @@ package() {
cd "$builddir"
make DESTDIR="$pkgdir" install
install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir/daemons
install -d "$pkgdir"/etc/init.d
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
install -d $pkgdir/$_sysconfdir/frr
install -m 0644 tools/etc/frr/daemons $pkgdir/$_sysconfdir/frr/daemons
install -d $pkgdir/$_sysconfdir/init.d
ln -s ${_sbindir}/frr $pkgdir/$_sysconfdir/init.d/frr
}

View file

@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS)
if (prefix->family == AF_INET) {
flush_interface_routes(ifc->ifp, 0);
babel_ifp = babel_get_if_nfo(ifc->ifp);
assert (babel_ifp != NULL);
if (babel_ifp->ipv4 == NULL) {
babel_ifp->ipv4 = malloc(4);
if (babel_ifp->ipv4 == NULL) {
@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
if (prefix->family == AF_INET) {
flush_interface_routes(ifc->ifp, 0);
babel_ifp = babel_get_if_nfo(ifc->ifp);
assert (babel_ifp != NULL);
if (babel_ifp->ipv4 != NULL
&& memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN)
== 0) {
@ -542,7 +544,10 @@ DEFPY (babel_set_channel,
unsigned
jitter(babel_interface_nfo *babel_ifp, int urgent)
{
unsigned interval = babel_ifp->hello_interval;
unsigned interval;
assert (babel_ifp != NULL);
interval = babel_ifp->hello_interval;
if(urgent)
interval = MIN(interval, 100);
else
@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent)
unsigned
update_jitter(babel_interface_nfo *babel_ifp, int urgent)
{
unsigned interval = babel_ifp->hello_interval;
unsigned interval;
assert (babel_ifp != NULL);
interval = babel_ifp->hello_interval;
if(urgent)
interval = MIN(interval, 100);
else
@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent)
static int
interface_recalculate(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
unsigned char *tmp = NULL;
int mtu, rc;
struct ipv6_mreq mreq;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
assert (babel_ifp != NULL);
if (!IS_ENABLE(ifp))
return -1;
@ -656,6 +665,7 @@ interface_reset(struct interface *ifp)
int rc;
struct ipv6_mreq mreq;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
assert (babel_ifp != NULL);
if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP))
return 0;
@ -695,6 +705,11 @@ interface_reset(struct interface *ifp)
babel_ifp->cost,
babel_ifp->ipv4 ? ", IPv4" : "");
if (babel_ifp->ipv4 != NULL){
free(babel_ifp->ipv4);
babel_ifp->ipv4 = NULL;
}
return 1;
}
@ -734,12 +749,11 @@ int
is_interface_ll_address(struct interface *ifp, const unsigned char *address)
{
struct connected *connected;
struct listnode *node;
if(!if_up(ifp))
return 0;
FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
frr_each (if_connected, ifp->connected, connected) {
if (connected->address->family == AF_INET6
&& memcmp(&connected->address->u.prefix6, address,
IPV6_MAX_BYTELEN)
@ -773,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp)
return;
}
babel_ifp = babel_get_if_nfo (ifp);
assert (babel_ifp != NULL);
vty_out (vty, " Babel protocol is running on this interface\n");
vty_out (vty, " Operating mode is \"%s\"\n",
CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
@ -1156,6 +1171,11 @@ DEFUN (show_babel_parameters,
return CMD_SUCCESS;
}
void babel_if_terminate(void)
{
vector_free(babel_enable_if);
}
void
babel_if_init(void)
{
@ -1224,6 +1244,7 @@ interface_config_write (struct vty *vty)
if (ifp->desc)
vty_out (vty, " description %s\n",ifp->desc);
babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
assert (babel_ifp != NULL);
/* wireless is the default*/
if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
{
@ -1326,10 +1347,11 @@ babel_interface_allocate (void)
{
babel_interface_nfo *babel_ifp;
babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
assert (babel_ifp != NULL);
/* All flags are unset */
babel_ifp->bucket_time = babel_now.tv_sec;
babel_ifp->bucket = BUCKET_TOKENS_MAX;
babel_ifp->hello_seqno = (frr_weak_random() & 0xFFFF);
babel_ifp->hello_seqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_ifp->rtt_decay = BABEL_DEFAULT_RTT_DECAY;
babel_ifp->rtt_min = BABEL_DEFAULT_RTT_MIN;
babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX;
@ -1345,5 +1367,11 @@ babel_interface_allocate (void)
static void
babel_interface_free (babel_interface_nfo *babel_ifp)
{
assert (babel_ifp != NULL);
if (babel_ifp->ipv4){
free(babel_ifp->ipv4);
babel_ifp->ipv4 = NULL;
}
XFREE(MTYPE_BABEL_IF, babel_ifp);
}

View file

@ -82,7 +82,6 @@ static inline int
if_up(struct interface *ifp)
{
return (if_is_operative(ifp) &&
ifp->connected != NULL &&
CHECK_FLAG(babel_get_if_nfo(ifp)->flags, BABEL_IF_IS_UP));
}
@ -95,6 +94,7 @@ struct buffered_update {
/* init function */
void babel_if_init(void);
void babel_if_terminate(void);
/* Callback functions for zebra client */
int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t);

View file

@ -5,6 +5,8 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
/* include zebra library */
#include <zebra.h>
#include <fcntl.h>
#include "getopt.h"
#include "if.h"
#include "log.h"
@ -56,7 +58,6 @@ unsigned char protocol_group[16]; /* babel's link-local multicast address */
int protocol_port; /* babel's port */
int protocol_socket = -1; /* socket: communicate with others babeld */
static const char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
static char *babel_vty_addr = NULL;
static int babel_vty_port = BABEL_VTY_PORT;
@ -124,18 +125,20 @@ static const struct frr_yang_module_info *const babeld_yang_modules[] = {
&frr_vrf_info,
};
/* clang-format off */
FRR_DAEMON_INFO(babeld, BABELD,
.vty_port = BABEL_VTY_PORT,
.proghelp = "Implementation of the BABEL routing protocol.",
.vty_port = BABEL_VTY_PORT,
.proghelp = "Implementation of the BABEL routing protocol.",
.signals = babel_signals,
.n_signals = array_size(babel_signals),
.signals = babel_signals,
.n_signals = array_size(babel_signals),
.privs = &babeld_privs,
.privs = &babeld_privs,
.yang_modules = babeld_yang_modules,
.n_yang_modules = array_size(babeld_yang_modules),
.yang_modules = babeld_yang_modules,
.n_yang_modules = array_size(babeld_yang_modules),
);
/* clang-format on */
int
main(int argc, char **argv)
@ -169,8 +172,8 @@ main(int argc, char **argv)
}
}
snprintf(state_file, sizeof(state_file), "%s/%s",
frr_vtydir, "babel-state");
snprintf(state_file, sizeof(state_file), "%s/%s", frr_runstatedir,
"babel-state");
/* create the threads handler */
master = frr_init ();
@ -182,8 +185,10 @@ main(int argc, char **argv)
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
/* init some quagga's dependencies, and babeld's commands */
if_zapi_callbacks(babel_ifp_create, babel_ifp_up,
babel_ifp_down, babel_ifp_destroy);
hook_register_prio(if_real, 0, babel_ifp_create);
hook_register_prio(if_up, 0, babel_ifp_up);
hook_register_prio(if_down, 0, babel_ifp_down);
hook_register_prio(if_unreal, 0, babel_ifp_destroy);
babeld_quagga_init();
/* init zebra client's structure and it's commands */
/* this replace kernel_setup && kernel_setup_socket */
@ -300,12 +305,14 @@ babel_exit_properly(void)
/* Uninstall and flush all routes. */
debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
flush_all_routes();
babel_interface_close_all();
babel_clean_routing_process();
babel_zebra_close_connexion();
babel_if_terminate();
babel_save_state_file();
debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
debugf(BABEL_DEBUG_COMMON, "Done.");
vrf_terminate();
frr_fini();
exit(0);
@ -360,7 +367,7 @@ show_babel_main_configuration (struct vty *vty)
"id = %s\n"
"kernel_metric = %d\n",
state_file,
babeld_di.config_file ? babeld_di.config_file : babel_config_default,
babeld_di.config_file,
format_address(protocol_group),
protocol_port,
babel_vty_addr ? babel_vty_addr : "None",

View file

@ -108,14 +108,14 @@ babel_config_write (struct vty *vty)
/* list redistributed protocols */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (i != zclient->redist_default &&
vrf_bitmap_check (zclient->redist[afi][i], VRF_DEFAULT)) {
vty_out (vty, " redistribute %s %s\n",
(afi == AFI_IP) ? "ipv4" : "ipv6",
zebra_route_string(i));
lines++;
}
}
if (i != zclient->redist_default &&
vrf_bitmap_check(&zclient->redist[afi][i], VRF_DEFAULT)) {
vty_out(vty, " redistribute %s %s\n",
(afi == AFI_IP) ? "ipv4" : "ipv6",
zebra_route_string(i));
lines++;
}
}
}
lines += config_write_distribute (vty, babel_routing_process->distribute_ctx);
@ -204,7 +204,7 @@ static void babel_read_protocol(struct event *thread)
making these inits have sense. */
static void babel_init_routing_process(struct event *thread)
{
myseqno = (frr_weak_random() & 0xFFFF);
myseqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_get_myid();
babel_load_state_file();
debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
@ -242,7 +242,7 @@ babel_get_myid(void)
/* We failed to get a global EUI64 from the interfaces we were given.
Let's try to find an interface with a MAC address. */
for(i = 1; i < 256; i++) {
char buf[INTERFACE_NAMSIZ], *ifname;
char buf[IFNAMSIZ], *ifname;
unsigned char eui[8];
ifname = if_indextoname(i, buf);
if(ifname == NULL)
@ -299,8 +299,7 @@ babel_initial_noise(void)
}
/* Delete all the added babel routes, make babeld only speak to zebra. */
static void
babel_clean_routing_process(void)
void babel_clean_routing_process(void)
{
flush_all_routes();
babel_interface_close_all();
@ -444,8 +443,8 @@ babel_fill_with_next_timeout(struct timeval *tv)
#if (defined NO_DEBUG)
#define printIfMin(a,b,c,d)
#else
#define printIfMin(a, b, c, d) \
if (unlikely(debug & BABEL_DEBUG_TIMEOUT)) { \
#define printIfMin(a, b, c, d) \
if (unlikely(CHECK_FLAG(debug, BABEL_DEBUG_TIMEOUT))) { \
printIfMin(a, b, c, d); \
}
@ -696,9 +695,8 @@ DEFPY (babel_set_smoothing_half_life,
DEFUN (babel_distribute_list,
babel_distribute_list_cmd,
"distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]",
"distribute-list ACCESSLIST4_NAME <in|out> [WORD]",
"Filter networks in routing updates\n"
"Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
@ -710,16 +708,26 @@ DEFUN (babel_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg;
return distribute_list_parser(prefix, true, argv[2 + prefix]->text,
return distribute_list_parser(babel_routing_process->distribute_ctx,
prefix, true, argv[2 + prefix]->text,
argv[1 + prefix]->arg, ifname);
}
ALIAS (babel_distribute_list,
babel_distribute_list_prefix_cmd,
"distribute-list prefix PREFIXLIST4_NAME <in|out> [WORD]",
"Filter networks in routing updates\n"
"Specify a prefix list\n"
"Prefix-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (babel_no_distribute_list,
babel_no_distribute_list_cmd,
"no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]",
"no distribute-list ACCESSLIST4_NAME <in|out> [WORD]",
NO_STR
"Filter networks in routing updates\n"
"Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
@ -731,17 +739,28 @@ DEFUN (babel_no_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg;
return distribute_list_no_parser(vty, prefix, true,
return distribute_list_no_parser(babel_routing_process->distribute_ctx,
vty, prefix, true,
argv[3 + prefix]->text,
argv[2 + prefix]->arg, ifname);
}
ALIAS (babel_no_distribute_list,
babel_no_distribute_list_prefix_cmd,
"no distribute-list prefix PREFIXLIST4_NAME <in|out> [WORD]",
NO_STR
"Filter networks in routing updates\n"
"Specify a prefix list\n"
"Prefix-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (babel_ipv6_distribute_list,
babel_ipv6_distribute_list_cmd,
"ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]",
"ipv6 distribute-list ACCESSLIST6_NAME <in|out> [WORD]",
"IPv6\n"
"Filter networks in routing updates\n"
"Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
@ -753,17 +772,28 @@ DEFUN (babel_ipv6_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg;
return distribute_list_parser(prefix, false, argv[3 + prefix]->text,
return distribute_list_parser(babel_routing_process->distribute_ctx,
prefix, false, argv[3 + prefix]->text,
argv[2 + prefix]->arg, ifname);
}
ALIAS (babel_ipv6_distribute_list,
babel_ipv6_distribute_list_prefix_cmd,
"ipv6 distribute-list prefix PREFIXLIST6_NAME <in|out> [WORD]",
"IPv6\n"
"Filter networks in routing updates\n"
"Specify a prefix list\n"
"Prefix-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
"Interface name\n")
DEFUN (babel_no_ipv6_distribute_list,
babel_no_ipv6_distribute_list_cmd,
"no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]",
"no ipv6 distribute-list ACCESSLIST6_NAME <in|out> [WORD]",
NO_STR
"IPv6\n"
"Filter networks in routing updates\n"
"Specify a prefix\n"
"Access-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
@ -775,11 +805,24 @@ DEFUN (babel_no_ipv6_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg;
return distribute_list_no_parser(vty, prefix, false,
return distribute_list_no_parser(babel_routing_process->distribute_ctx,
vty, prefix, false,
argv[4 + prefix]->text,
argv[3 + prefix]->arg, ifname);
}
ALIAS (babel_no_ipv6_distribute_list,
babel_no_ipv6_distribute_list_prefix_cmd,
"no ipv6 distribute-list prefix PREFIXLIST6_NAME <in|out> [WORD]",
NO_STR
"IPv6\n"
"Filter networks in routing updates\n"
"Specify a prefix list\n"
"Prefix-list name\n"
"Filter incoming routing updates\n"
"Filter outgoing routing updates\n"
"Interface name\n")
void
babeld_quagga_init(void)
{
@ -797,9 +840,13 @@ babeld_quagga_init(void)
install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
install_element(BABEL_NODE, &babel_distribute_list_cmd);
install_element(BABEL_NODE, &babel_distribute_list_prefix_cmd);
install_element(BABEL_NODE, &babel_no_distribute_list_cmd);
install_element(BABEL_NODE, &babel_no_distribute_list_prefix_cmd);
install_element(BABEL_NODE, &babel_ipv6_distribute_list_cmd);
install_element(BABEL_NODE, &babel_ipv6_distribute_list_prefix_cmd);
install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_cmd);
install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_prefix_cmd);
vrf_cmd_init(NULL);

View file

@ -53,7 +53,6 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
#endif
#define BABEL_VTY_PORT 2609
#define BABEL_DEFAULT_CONFIG "babeld.conf"
/* Values in milliseconds */
@ -99,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen,
extern int resize_receive_buffer(int size);
extern void schedule_neighbours_check(int msecs, int override);
extern struct babel *babel_lookup(void);
extern void babel_clean_routing_process(void);
#endif /* BABEL_BABELD_H */

View file

@ -11,6 +11,7 @@ Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek
#include <sys/time.h>
#include <sys/param.h>
#include <time.h>
#include <fcntl.h>
#include "babeld.h"
@ -91,13 +92,9 @@ kernel_route(enum babel_kernel_routes operation, const unsigned char *pref,
case ROUTE_MODIFY:
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
newifindex == ifindex)
return 0;
debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
rc = zebra_route(0, family, pref, plen, gate, ifindex, metric);
if (rc < 0)
return -1;
return 0;
rc = zebra_route(1, family, pref, plen, newgate, newifindex,
rc = zebra_route(1, family, pref, plen, newgate, newifindex,
newmetric);
return rc;
}

View file

@ -48,6 +48,13 @@ static const unsigned char tlv_min_length[MESSAGE_MAX + 1] =
[ MESSAGE_MH_REQUEST ] = 14,
};
/* Checks whether an AE exists or must be silently ignored */
static bool
known_ae(int ae)
{
return ae <= 4;
}
/* Parse a network prefix, encoded in the somewhat baroque compressed
representation used by Babel. Return the number of bytes parsed. */
static int
@ -132,7 +139,7 @@ static bool parse_update_subtlv(const unsigned char *a, int alen,
return false;
}
if (type & SUBTLV_MANDATORY) {
if (CHECK_FLAG(type, SUBTLV_MANDATORY)) {
/*
* RFC 8966 - 4.4
* If the mandatory bit is set, then the whole enclosing
@ -155,8 +162,7 @@ static bool parse_update_subtlv(const unsigned char *a, int alen,
}
if (memchr(a + i + 2, 0, len) != NULL) {
/* 0 is reserved. */
flog_err(EC_BABEL_PACKET,
"Channel information contains 0!");
flog_err(EC_BABEL_PACKET, "Channel information contains 0!");
return false;
}
memset(channels, 0, DIVERSITY_HOPS);
@ -196,7 +202,7 @@ parse_hello_subtlv(const unsigned char *a, int alen,
return -1;
}
if (type & SUBTLV_MANDATORY) {
if (CHECK_FLAG(type, SUBTLV_MANDATORY)) {
/*
* RFC 8966 4.4
* If the mandatory bit is set, then the whole enclosing
@ -276,6 +282,62 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
return ret;
}
static int
parse_request_subtlv(int ae, const unsigned char *a, int alen,
unsigned char *src_prefix, unsigned char *src_plen)
{
int type, len, i = 0;
int have_src_prefix = 0;
while(i < alen) {
type = a[0];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
if(i + 2 > alen)
goto fail;
len = a[i + 1];
if(i + 2 + len > alen)
goto fail;
if(type == SUBTLV_PADN) {
/* Nothing to do. */
} else if(type == SUBTLV_SOURCE_PREFIX) {
int rc;
if(len < 1)
goto fail;
if(a[i + 2] == 0)
goto fail;
if(have_src_prefix != 0)
goto fail;
rc = network_prefix(ae, a[i + 2], 0, a + i + 3, NULL,
len - 1, src_prefix);
if(rc < 0)
goto fail;
if(ae==1)
*src_plen = a[i + 2] + 96;
else
*src_plen = a[i + 2];
have_src_prefix = 1;
} else {
debugf(BABEL_DEBUG_COMMON,"Received unknown%s Route Request sub-TLV %d.",
(CHECK_FLAG(type, 0x80) != 0) ? " mandatory" : "", type);
if(CHECK_FLAG(type, 0x80) != 0)
return -1;
}
i += len + 2;
}
return 1;
fail:
flog_err(EC_BABEL_PACKET, "Received truncated sub-TLV on Route Request.");
return -1;
}
static int
network_address(int ae, const unsigned char *a, unsigned int len,
unsigned char *a_r)
@ -354,7 +416,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
unsigned int hello_send_us = 0, hello_rtt_receive_time = 0;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) {
if (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS)) {
/* We want to track exactly when we received this packet. */
gettime(&babel_now);
}
@ -456,8 +518,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
schedule_neighbours_check(interval * 15, 0);
/* Sub-TLV handling. */
if (len > 8) {
if (parse_hello_subtlv(message + 8, len - 6,
&timestamp) > 0) {
if (parse_hello_subtlv(message + 8, len - 6, &timestamp) > 0) {
neigh->hello_send_us = timestamp;
neigh->hello_rtt_receive_time = babel_now;
have_hello_rtt = 1;
@ -524,9 +585,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
} else if(type == MESSAGE_NH) {
unsigned char nh[16];
int rc;
rc = network_address(message[2], message + 4, len - 2,
nh);
if(rc < 0) {
rc = network_address(message[2], message + 4, len - 2, nh);
if(rc <= 0) {
have_v4_nh = 0;
have_v6_nh = 0;
goto fail;
@ -547,9 +607,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
unsigned char channels[DIVERSITY_HOPS];
unsigned short interval, seqno, metric;
int rc, parsed_len;
bool ignore_update = false;
bool ignore_update = false;
DO_NTOHS(interval, message + 6);
DO_NTOHS(interval, message + 6);
DO_NTOHS(seqno, message + 8);
DO_NTOHS(metric, message + 10);
if(message[5] == 0 ||
@ -561,7 +621,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
else
rc = -1;
if(rc < 0) {
if(message[3] & 0x80)
if(CHECK_FLAG(message[3], 0x80))
have_v4_prefix = have_v6_prefix = 0;
goto fail;
}
@ -569,7 +629,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
plen = message[4] + (message[2] == 1 ? 96 : 0);
if(message[3] & 0x80) {
if(CHECK_FLAG(message[3], 0x80)) {
if(message[2] == 1) {
memcpy(v4_prefix, prefix, 16);
have_v4_prefix = 1;
@ -578,7 +638,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_v6_prefix = 1;
}
}
if(message[3] & 0x40) {
if(CHECK_FLAG(message[3], 0x40)) {
if(message[2] == 1) {
memset(router_id, 0, 4);
memcpy(router_id + 4, prefix + 12, 4);
@ -593,8 +653,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
goto fail;
}
debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
(message[3] & 0x80) ? "/prefix" : "",
(message[3] & 0x40) ? "/id" : "",
((CHECK_FLAG(message[3], 0x80)) ? "/prefix" : ""),
((CHECK_FLAG(message[3], 0x40)) ? "/id" : ""),
format_prefix(prefix, plen),
format_address(from), ifp->name);
@ -621,7 +681,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
goto done;
}
if((babel_get_if_nfo(ifp)->flags & BABEL_IF_FARAWAY)) {
if(CHECK_FLAG(babel_get_if_nfo(ifp)->flags, BABEL_IF_FARAWAY)) {
channels[0] = 0;
} else {
/* This will be overwritten by parse_update_subtlv below. */
@ -635,23 +695,28 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
if(parsed_len < len)
ignore_update =
parse_update_subtlv(message + 2 + parsed_len,
len - parsed_len, channels);
ignore_update =
parse_update_subtlv(message + 2 + parsed_len,
len - parsed_len, channels);
}
if (!ignore_update) {
if(interval > 0) {
update_route(router_id, prefix, plen, seqno, metric,
interval, neigh, nh, channels,
channels_len(channels));
} else {
debugf(BABEL_DEBUG_COMMON, "Received update with zero interval.");
}
}
if (!ignore_update) {
if(interval > 0) {
update_route(router_id, prefix, plen, seqno, metric,
interval, neigh, nh, channels, channels_len(channels));
} else {
debugf(BABEL_DEBUG_COMMON, "Received update with zero interval.");
}
} else if(type == MESSAGE_REQUEST) {
unsigned char prefix[16], plen;
int rc;
unsigned char prefix[16], src_prefix[16], plen, src_plen;
int rc, is_ss;
if(len < 2) goto fail;
if(!known_ae(message[2])) {
debugf(BABEL_DEBUG_COMMON,"Received request with unknown AE %d. Ignoring.",
message[2]);
goto done;
}
rc = network_prefix(message[2], message[3], 0,
message + 4, NULL, len - 2, prefix);
if(rc < 0) goto fail;
@ -659,8 +724,26 @@ parse_packet(const unsigned char *from, struct interface *ifp,
debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.",
message[2] == 0 ? "any" : format_prefix(prefix, plen),
format_address(from), ifp->name);
if(message[2] == 1) {
v4tov6(src_prefix, zeroes);
src_plen = 96;
} else {
memcpy(src_prefix, zeroes, 16);
src_plen = 0;
}
rc = parse_request_subtlv(message[2], message + 4 + rc,
len - 2 - rc, src_prefix, &src_plen);
if(rc < 0)
goto done;
is_ss = !is_default(src_prefix, src_plen);
if(message[2] == 0) {
struct babel_interface *neigh_ifp =babel_get_if_nfo(neigh->ifp);
if(is_ss) {
/* Wildcard requests don't carry a source prefix. */
flog_err(EC_BABEL_PACKET,
"Received source-specific wildcard request.");
goto done;
}
/* If a neighbour is requesting a full route dump from us,
we might as well send it an IHU. */
send_ihu(neigh, NULL);
@ -698,15 +781,14 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
rc = network_prefix(message[2], message[3], 0,
message + 16, NULL, len - 14, prefix);
if(rc < 0) goto fail;
if(rc <= 0) goto fail;
plen = message[3] + (message[2] == 1 ? 96 : 0);
debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).",
message[6],
format_prefix(prefix, plen),
format_address(from), ifp->name,
format_eui64(message + 8), seqno);
handle_request(neigh, prefix, plen, message[6],
seqno, message + 8);
handle_request(neigh, prefix, plen, message[6], seqno, message + 8);
} else {
debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.",
type, format_address(from), ifp->name);
@ -788,11 +870,10 @@ check_bucket(struct interface *ifp)
}
}
static int
fill_rtt_message(struct interface *ifp)
static int fill_rtt_message(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) &&
if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) &&
(babel_ifp->buffered_hello >= 0)) {
if(babel_ifp->sendbuf[babel_ifp->buffered_hello + 8] == SUBTLV_PADN &&
babel_ifp->sendbuf[babel_ifp->buffered_hello + 9] == 4) {
@ -812,8 +893,7 @@ fill_rtt_message(struct interface *ifp)
return 0;
}
void
flushbuf(struct interface *ifp)
void flushbuf(struct interface *ifp)
{
int rc;
struct sockaddr_in6 sin6;
@ -855,8 +935,7 @@ flushbuf(struct interface *ifp)
babel_ifp->flush_timeout.tv_usec = 0;
}
static void
schedule_flush(struct interface *ifp)
static void schedule_flush(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
unsigned msecs = jitter(babel_ifp, 0);
@ -866,8 +945,7 @@ schedule_flush(struct interface *ifp)
set_timeout(&babel_ifp->flush_timeout, msecs);
}
static void
schedule_flush_now(struct interface *ifp)
static void schedule_flush_now(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
/* Almost now */
@ -878,8 +956,7 @@ schedule_flush_now(struct interface *ifp)
set_timeout(&babel_ifp->flush_timeout, msecs);
}
static void
schedule_unicast_flush(unsigned msecs)
static void schedule_unicast_flush(unsigned msecs)
{
if(!unicast_neighbour)
return;
@ -891,16 +968,14 @@ schedule_unicast_flush(unsigned msecs)
babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000;
}
static void
ensure_space(struct interface *ifp, int space)
static void ensure_space(struct interface *ifp, int space)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
if(babel_ifp->bufsize - babel_ifp->buffered < space)
flushbuf(ifp);
}
static void
start_message(struct interface *ifp, int type, int len)
static void start_message(struct interface *ifp, int type, int len)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
if(babel_ifp->bufsize - babel_ifp->buffered < len + 2)
@ -909,8 +984,7 @@ start_message(struct interface *ifp, int type, int len)
babel_ifp->sendbuf[babel_ifp->buffered++] = len;
}
static void
end_message(struct interface *ifp, int type, int bytes)
static void end_message(struct interface *ifp, int type, int bytes)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
assert(babel_ifp->buffered >= bytes + 2 &&
@ -919,23 +993,20 @@ end_message(struct interface *ifp, int type, int bytes)
schedule_flush(ifp);
}
static void
accumulate_byte(struct interface *ifp, unsigned char value)
static void accumulate_byte(struct interface *ifp, unsigned char value)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
babel_ifp->sendbuf[babel_ifp->buffered++] = value;
}
static void
accumulate_short(struct interface *ifp, unsigned short value)
static void accumulate_short(struct interface *ifp, unsigned short value)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value);
babel_ifp->buffered += 2;
}
static void
accumulate_int(struct interface *ifp, unsigned int value)
static void accumulate_int(struct interface *ifp, unsigned int value)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
DO_HTONL(babel_ifp->sendbuf + babel_ifp->buffered, value);
@ -951,8 +1022,7 @@ accumulate_bytes(struct interface *ifp,
babel_ifp->buffered += len;
}
static int
start_unicast_message(struct neighbour *neigh, int type, int len)
static int start_unicast_message(struct neighbour *neigh, int type, int len)
{
if(unicast_neighbour) {
if(neigh != unicast_neighbour ||
@ -975,8 +1045,7 @@ start_unicast_message(struct neighbour *neigh, int type, int len)
return 1;
}
static void
end_unicast_message(struct neighbour *neigh, int type, int bytes)
static void end_unicast_message(struct neighbour *neigh, int type, int bytes)
{
assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 &&
unicast_buffer[unicast_buffered - bytes - 2] == type &&
@ -997,8 +1066,7 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
unicast_buffered += 2;
}
static void
accumulate_unicast_int(struct neighbour *neigh, unsigned int value)
static void accumulate_unicast_int(struct neighbour *neigh, unsigned int value)
{
DO_HTONL(unicast_buffer + unicast_buffered, value);
unicast_buffered += 4;
@ -1018,15 +1086,16 @@ send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval)
int rc;
debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.",
nonce, format_address(neigh->address), neigh->ifp->name);
rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return;
rc = start_unicast_message(neigh, MESSAGE_ACK, 2);
if(rc < 0)
return;
accumulate_unicast_short(neigh, nonce);
end_unicast_message(neigh, MESSAGE_ACK, 2);
/* Roughly yields a value no larger than 3/2, so this meets the deadline */
schedule_unicast_flush(roughly(interval * 6));
}
void
send_hello_noupdate(struct interface *ifp, unsigned interval)
void send_hello_noupdate(struct interface *ifp, unsigned interval)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
/* This avoids sending multiple hellos in a single packet, which breaks
@ -1044,12 +1113,12 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
babel_ifp->hello_seqno, interval, ifp->name);
start_message(ifp, MESSAGE_HELLO,
(babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6);
(CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) ? 12 : 6));
babel_ifp->buffered_hello = babel_ifp->buffered - 2;
accumulate_short(ifp, 0);
accumulate_short(ifp, babel_ifp->hello_seqno);
accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval);
if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) {
if (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS)) {
/* Sub-TLV containing the local time of emission. We use a
Pad4 sub-TLV, which we'll fill just before sending. */
accumulate_byte(ifp, SUBTLV_PADN);
@ -1057,11 +1126,10 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
accumulate_int(ifp, 0);
}
end_message(ifp, MESSAGE_HELLO,
(babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6);
CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) ? 12 : 6);
}
void
send_hello(struct interface *ifp)
void send_hello(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10);
@ -1072,8 +1140,7 @@ send_hello(struct interface *ifp)
send_marginal_ihu(ifp);
}
void
flush_unicast(int dofree)
void flush_unicast(int dofree)
{
struct sockaddr_in6 sin6;
int rc;
@ -1150,7 +1217,7 @@ really_send_update(struct interface *ifp,
/* Worst case */
ensure_space(ifp, 20 + 12 + 28);
v4 = plen >= 96 && v4mapped(prefix);
v4 = (plen >= 96) && v4mapped(prefix);
if(v4) {
if(!babel_ifp->ipv4)
@ -1175,7 +1242,7 @@ really_send_update(struct interface *ifp,
omit++;
}
if(!babel_ifp->have_buffered_prefix || plen >= 48)
flags |= 0x80;
SET_FLAG(flags, 0x80);
real_prefix = prefix;
real_plen = plen;
}
@ -1183,7 +1250,7 @@ really_send_update(struct interface *ifp,
if(!babel_ifp->have_buffered_id
|| memcmp(id, babel_ifp->buffered_id, 8) != 0) {
if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) {
flags |= 0x40;
SET_FLAG(flags, 0x40);
} else {
start_message(ifp, MESSAGE_ROUTER_ID, 10);
accumulate_short(ifp, 0);
@ -1215,14 +1282,13 @@ really_send_update(struct interface *ifp,
end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
channels_size);
if(flags & 0x80) {
if (CHECK_FLAG(flags, 0x80)) {
memcpy(babel_ifp->buffered_prefix, prefix, 16);
babel_ifp->have_buffered_prefix = 1;
}
}
static int
compare_buffered_updates(const void *av, const void *bv)
static int compare_buffered_updates(const void *av, const void *bv)
{
const struct buffered_update *a = av, *b = bv;
int rc, v4a, v4b, ma, mb;
@ -1255,8 +1321,7 @@ compare_buffered_updates(const void *av, const void *bv)
return memcmp(a->prefix, b->prefix, 16);
}
void
flushupdates(struct interface *ifp)
void flushupdates(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = NULL;
struct xroute *xroute;
@ -1266,7 +1331,7 @@ flushupdates(struct interface *ifp)
int i;
if(ifp == NULL) {
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp_aux;
FOR_ALL_INTERFACES(vrf, ifp_aux)
flushupdates(ifp_aux);
@ -1339,7 +1404,7 @@ flushupdates(struct interface *ifp)
if(metric < INFINITY)
satisfy_request(route->src->prefix, route->src->plen,
seqno, route->src->id, ifp);
if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) &&
if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) &&
route->neigh->ifp == ifp)
continue;
@ -1381,11 +1446,11 @@ flushupdates(struct interface *ifp)
babel_ifp->update_flush_timeout.tv_usec = 0;
}
static void
schedule_update_flush(struct interface *ifp, int urgent)
static void schedule_update_flush(struct interface *ifp, int urgent)
{
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
unsigned msecs;
msecs = update_jitter(babel_ifp, urgent);
if(babel_ifp->update_flush_timeout.tv_sec != 0 &&
timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs)
@ -1495,10 +1560,10 @@ send_update_resend(struct interface *ifp,
record_resend(RESEND_UPDATE, prefix, plen, 0, NULL, NULL, resend_delay);
}
void
send_wildcard_retraction(struct interface *ifp)
void send_wildcard_retraction(struct interface *ifp)
{
babel_interface_nfo *babel_ifp = NULL;
if(ifp == NULL) {
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp_aux;
@ -1524,14 +1589,12 @@ send_wildcard_retraction(struct interface *ifp)
babel_ifp->have_buffered_id = 0;
}
void
update_myseqno(void)
void update_myseqno(void)
{
myseqno = seqno_plus(myseqno, 1);
}
void
send_self_update(struct interface *ifp)
void send_self_update(struct interface *ifp)
{
struct xroute_stream *xroutes;
if(ifp == NULL) {
@ -1559,8 +1622,7 @@ send_self_update(struct interface *ifp)
}
}
void
send_ihu(struct neighbour *neigh, struct interface *ifp)
void send_ihu(struct neighbour *neigh, struct interface *ifp)
{
babel_interface_nfo *babel_ifp = NULL;
int rxcost, interval;
@ -1612,7 +1674,7 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
ll = linklocal(neigh->address);
if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) && neigh->hello_send_us
if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) && neigh->hello_send_us
/* Checks whether the RTT data is not too old to be sent. */
&& timeval_minus_msec(&babel_now,
&neigh->hello_rtt_receive_time) < 1000000) {
@ -1667,14 +1729,13 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
}
/* Send IHUs to all marginal neighbours */
void
send_marginal_ihu(struct interface *ifp)
void send_marginal_ihu(struct interface *ifp)
{
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(ifp && neigh->ifp != ifp)
continue;
if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000)
if(neigh->txcost >= 384 || CHECK_FLAG(neigh->reach, 0xF000) != 0xF000)
send_ihu(neigh, ifp);
}
}

View file

@ -34,6 +34,7 @@ Copyright (c) 2007, 2008 by Juliusz Chroboczek
#define SUBTLV_PADN 1
#define SUBTLV_DIVERSITY 2 /* Also known as babelz. */
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
#define SUBTLV_SOURCE_PREFIX 128 /* Source-specific routing. */
#define SUBTLV_MANDATORY 0x80
extern unsigned short myseqno;

View file

@ -34,15 +34,13 @@ find_neighbour_nocreate(const unsigned char *address, struct interface *ifp)
{
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
if(memcmp(address, neigh->address, 16) == 0 &&
neigh->ifp == ifp)
if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp)
return neigh;
}
return NULL;
}
void
flush_neighbour(struct neighbour *neigh)
void flush_neighbour(struct neighbour *neigh)
{
debugf(BABEL_DEBUG_COMMON,"Flushing neighbour %s (reach 0x%04x)",
format_address(neigh->address), neigh->reach);
@ -102,8 +100,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
}
/* Recompute a neighbour's rxcost. Return true if anything changed. */
int
update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
int update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
{
int missed_hellos;
int rc = 0;
@ -160,26 +157,26 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
if(hello >= 0) {
neigh->hello_seqno = hello;
neigh->reach >>= 1;
neigh->reach |= 0x8000;
if((neigh->reach & 0xFC00) != 0xFC00)
SET_FLAG(neigh->reach, 0x8000);
if(CHECK_FLAG(neigh->reach, 0xFC00) != 0xFC00)
rc = 1;
}
/* Make sure to give neighbours some feedback early after association */
if((neigh->reach & 0xBF00) == 0x8000) {
if(CHECK_FLAG(neigh->reach, 0xBF00) == 0x8000) {
/* A new neighbour */
send_hello(neigh->ifp);
} else {
/* Don't send hellos, in order to avoid a positive feedback loop. */
int a = (neigh->reach & 0xC000);
int b = (neigh->reach & 0x3000);
int a = CHECK_FLAG(neigh->reach, 0xC000);
int b = CHECK_FLAG(neigh->reach, 0x3000);
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
/* Reachability is either 1100 or 0011 */
send_self_update(neigh->ifp);
}
}
if((neigh->reach & 0xFC00) == 0xC000) {
if(CHECK_FLAG(neigh->reach, 0xFC00) == 0xC000) {
/* This is a newish neighbour, let's request a full route dump.
We ought to avoid this when the network is dense */
send_unicast_request(neigh, NULL, 0);
@ -188,8 +185,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
return rc;
}
static int
reset_txcost(struct neighbour *neigh)
static int reset_txcost(struct neighbour *neigh)
{
unsigned delay;
@ -199,9 +195,8 @@ reset_txcost(struct neighbour *neigh)
return 0;
/* If we're losing a lot of packets, we probably lost an IHU too */
if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 ||
(neigh->ihu_interval > 0 &&
delay >= neigh->ihu_interval * 10U * 10U)) {
if (delay >= 180000 || CHECK_FLAG(neigh->reach, 0xFFF0) == 0 ||
(neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) {
neigh->txcost = INFINITY;
neigh->ihu_time = babel_now;
return 1;
@ -210,14 +205,12 @@ reset_txcost(struct neighbour *neigh)
return 0;
}
unsigned
neighbour_txcost(struct neighbour *neigh)
unsigned neighbour_txcost(struct neighbour *neigh)
{
return neigh->txcost;
}
unsigned
check_neighbours(void)
unsigned check_neighbours(void)
{
struct neighbour *neigh;
int changed, rc;
@ -253,21 +246,20 @@ check_neighbours(void)
return msecs;
}
unsigned
neighbour_rxcost(struct neighbour *neigh)
unsigned neighbour_rxcost(struct neighbour *neigh)
{
unsigned delay;
unsigned short reach = neigh->reach;
delay = timeval_minus_msec(&babel_now, &neigh->hello_time);
if((reach & 0xFFF0) == 0 || delay >= 180000) {
if(CHECK_FLAG(reach, 0xFFF0) == 0 || delay >= 180000) {
return INFINITY;
} else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) {
} else if (CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)) {
int sreach =
((reach & 0x8000) >> 2) +
((reach & 0x4000) >> 1) +
(reach & 0x3FFF);
(CHECK_FLAG(reach, 0x8000) >> 2) +
(CHECK_FLAG(reach, 0x4000) >> 1) +
CHECK_FLAG(reach, 0x3FFF);
/* 0 <= sreach <= 0x7FFF */
int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1);
/* cost >= interface->cost */
@ -276,19 +268,18 @@ neighbour_rxcost(struct neighbour *neigh)
return MIN(cost, INFINITY);
} else {
/* To lose one hello is a misfortune, to lose two is carelessness. */
if((reach & 0xC000) == 0xC000)
if (CHECK_FLAG(reach, 0xC000) == 0xC000)
return babel_get_if_nfo(neigh->ifp)->cost;
else if((reach & 0xC000) == 0)
else if (CHECK_FLAG(reach, 0xC000) == 0)
return INFINITY;
else if((reach & 0x2000))
else if (CHECK_FLAG(reach, 0x2000))
return babel_get_if_nfo(neigh->ifp)->cost;
else
return INFINITY;
}
}
unsigned
neighbour_rttcost(struct neighbour *neigh)
unsigned neighbour_rttcost(struct neighbour *neigh)
{
struct interface *ifp = neigh->ifp;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
@ -304,15 +295,14 @@ neighbour_rttcost(struct neighbour *neigh)
(unsigned long long)babel_ifp->max_rtt_penalty *
(neigh->rtt - babel_ifp->rtt_min) /
(babel_ifp->rtt_max - babel_ifp->rtt_min);
assert((tmp & 0x7FFFFFFF) == tmp);
assert(CHECK_FLAG(tmp, 0x7FFFFFFF) == tmp);
return tmp;
} else {
return babel_ifp->max_rtt_penalty;
}
}
unsigned
neighbour_cost(struct neighbour *neigh)
unsigned neighbour_cost(struct neighbour *neigh)
{
unsigned a, b, cost;
@ -328,7 +318,7 @@ neighbour_cost(struct neighbour *neigh)
if(b >= INFINITY)
return INFINITY;
if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ)
if (!CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)
|| (a < 256 && b < 256)) {
cost = a;
} else {
@ -347,8 +337,7 @@ neighbour_cost(struct neighbour *neigh)
return MIN(cost, INFINITY);
}
int
valid_rtt(struct neighbour *neigh)
int valid_rtt(struct neighbour *neigh)
{
return (timeval_minus_msec(&babel_now, &neigh->rtt_time) < 180000) ? 1 : 0;
}

View file

@ -352,7 +352,7 @@ route_stream_done(struct route_stream *stream)
static int
metric_to_kernel(int metric)
{
return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
return metric < INFINITY ? metric : KERNEL_INFINITY;
}
/* This is used to maintain the invariant that the installed route is at

View file

@ -211,8 +211,8 @@ mask_prefix(unsigned char *restrict ret,
memset(ret, 0, 16);
memcpy(ret, prefix, plen / 8);
if(plen % 8 != 0)
ret[plen / 8] =
(prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF));
ret[plen / 8] = CHECK_FLAG(prefix[plen / 8],
CHECK_FLAG((0xFF << (8 - (plen % 8))), 0xFF));
return ret;
}
@ -353,12 +353,13 @@ martian_prefix(const unsigned char *prefix, int plen)
{
return
(plen >= 8 && prefix[0] == 0xFF) ||
(plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) ||
(plen >= 10 && prefix[0] == 0xFE &&
(CHECK_FLAG(prefix[1], 0xC0) == 0x80)) ||
(plen >= 128 && memcmp(prefix, zeroes, 15) == 0 &&
(prefix[15] == 0 || prefix[15] == 1)) ||
(plen >= 96 && v4mapped(prefix) &&
((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) ||
(plen >= 100 && (prefix[12] & 0xE0) == 0xE0)));
(plen >= 100 && CHECK_FLAG(prefix[12], 0xE0) == 0xE0)));
}
int

View file

@ -47,19 +47,19 @@ seqno_compare(unsigned short s1, unsigned short s2)
if(s1 == s2)
return 0;
else
return ((s2 - s1) & 0x8000) ? 1 : -1;
return (CHECK_FLAG((s2 - s1), 0x8000)) ? 1 : -1;
}
static inline short
seqno_minus(unsigned short s1, unsigned short s2)
{
return (short)((s1 - s2) & 0xFFFF);
return (short)(CHECK_FLAG((s1 - s2), 0xFFFF));
}
static inline unsigned short
seqno_plus(unsigned short s, int plus)
{
return ((s + plus) & 0xFFFF);
return CHECK_FLAG((s + plus), 0xFFFF);
}
/* Returns a time in microseconds on 32 bits (thus modulo 2^32,
@ -104,6 +104,12 @@ void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src);
int daemonise(void);
extern const unsigned char v4prefix[16];
static inline bool
is_default(const unsigned char *prefix, int plen)
{
return plen == 0 || (plen == 96 && v4mapped(prefix));
}
/* If debugging is disabled, we want to avoid calling format_address
for every omitted debugging message. So debug is a macro. But
vararg macros are not portable. */
@ -124,7 +130,7 @@ extern const unsigned char v4prefix[16];
#define debugf(level, ...) \
do { \
if (unlikely(debug & level)) \
if (unlikely(CHECK_FLAG(debug, level))) \
zlog_debug(__VA_ARGS__); \
} while (0)

View file

@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
struct peer_label *pl;
struct bfd_key key;
/* Try to find label first. */
if (bpc->bpc_has_label) {
pl = pl_find(bpc->bpc_label);
if (pl != NULL) {
bs = pl->pl_bs;
return bs;
}
}
/* Otherwise fallback to peer/local hash lookup. */
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
bpc->bpc_localif, bpc->bpc_vrfname);
@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs)
bs->ifp = ifp;
/* Attempt to use data plane. */
if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) {
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs);
if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0)
return 0;
}
/* Sanity check: don't leak open sockets. */
if (bs->sock != -1) {
@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void)
* random session identification numbers.
*/
do {
session_id = ((frr_weak_random() << 16) & 0xFFFF0000)
| (frr_weak_random() & 0x0000FFFF);
session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) |
CHECK_FLAG(frr_weak_random(), 0x0000FFFF);
} while (session_id == 0 || bfd_id_lookup(session_id) != NULL);
return session_id;
@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd)
/* Start sending control packets with poll bit immediately. */
ptm_bfd_snd(bfd, 0);
control_notify(bfd, bfd->ses_state);
ptm_bfd_notify(bfd, bfd->ses_state);
if (old_state != bfd->ses_state) {
bfd->stats.session_up++;
@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
/* only signal clients when going from up->down state */
if (old_state == PTM_BFD_UP)
control_notify(bfd, PTM_BFD_DOWN);
ptm_bfd_notify(bfd, PTM_BFD_DOWN);
/* Stop echo packet transmission if they are active */
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void)
return bs;
}
int bfd_session_update_label(struct bfd_session *bs, const char *nlabel)
{
/* New label treatment:
* - Check if the label is taken;
* - Try to allocate the memory for it and register;
*/
if (bs->pl == NULL) {
if (pl_find(nlabel) != NULL) {
/* Someone is already using it. */
return -1;
}
pl_new(nlabel, bs);
return 0;
}
/*
* Test label change consistency:
* - Do nothing if it's the same label;
* - Check if the future label is already taken;
* - Change label;
*/
if (strcmp(nlabel, bs->pl->pl_label) == 0)
return -1;
if (pl_find(nlabel) != NULL)
return -1;
strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label));
return 0;
}
static void _bfd_session_update(struct bfd_session *bs,
struct bfd_peer_cfg *bpc)
{
@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs,
bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx;
}
if (bpc->bpc_has_label)
bfd_session_update_label(bs, bpc->bpc_label);
if (bpc->bpc_cbit)
SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
else
@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
_bfd_session_update(bs, bpc);
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
return 0;
}
@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs)
if (bso != NULL)
bs_observer_del(bso);
pl_free(bs->pl);
XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
XFREE(MTYPE_BFDD_CONFIG, bs);
}
@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd)
if (bglobal.debug_peer_event)
zlog_debug("session-new: %s", bs_to_string(bfd));
control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
return bfd;
}
@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
if (bglobal.debug_peer_event)
zlog_debug("%s: %s", __func__, bs_to_string(bs));
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
bfd_session_free(bs);
return 0;
@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs)
* When using demand mode we must disable the detection timer
* for lost control packets.
*/
if (bs->demand_mode) {
/* Notify watchers about changed timers. */
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
if (bs->demand_mode)
return;
}
/*
* Calculate transmission time based on new timers.
@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs)
/* Apply new transmission timer immediately. */
ptm_bfd_start_xmt_timer(bs, false);
/* Notify watchers about changed timers. */
control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
}
void bs_set_slow_timers(struct bfd_session *bs)
@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
if (bs->bdc) {
bs->ses_state = PTM_BFD_ADM_DOWN;
bfd_dplane_update_session(bs);
control_notify(bs, bs->ses_state);
ptm_bfd_notify(bs, bs->ses_state);
return;
}
@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
/* Change and notify state change. */
bs->ses_state = PTM_BFD_ADM_DOWN;
control_notify(bs, bs->ses_state);
ptm_bfd_notify(bs, bs->ses_state);
/* Don't try to send packets with a disabled session. */
if (bs->sock != -1)
@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
if (bs->bdc) {
bs->ses_state = PTM_BFD_DOWN;
bfd_dplane_update_session(bs);
control_notify(bs, bs->ses_state);
ptm_bfd_notify(bs, bs->ses_state);
return;
}
/* Change and notify state change. */
bs->ses_state = PTM_BFD_DOWN;
control_notify(bs, bs->ses_state);
ptm_bfd_notify(bs, bs->ses_state);
/* Enable timers if non passive, otherwise stop them. */
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) {

View file

@ -20,17 +20,78 @@
#include "lib/queue.h"
#include "lib/vrf.h"
#include "bfdctl.h"
#ifdef BFD_DEBUG
#define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY)
#else
#define BFDD_JSON_CONV_OPTIONS (0)
#endif
#ifndef MAXNAMELEN
#define MAXNAMELEN 32
#endif
#define BPC_DEF_DETECTMULTIPLIER 3
#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
DECLARE_MGROUP(BFDD);
DECLARE_MTYPE(BFDD_CONTROL);
DECLARE_MTYPE(BFDD_NOTIFICATION);
DECLARE_MTYPE(BFDD_CLIENT);
DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION);
struct sockaddr_any {
union {
struct sockaddr_in sa_sin;
struct sockaddr_in6 sa_sin6;
};
};
struct bfd_peer_cfg {
bool bpc_mhop;
bool bpc_ipv4;
struct sockaddr_any bpc_peer;
struct sockaddr_any bpc_local;
bool bpc_has_localif;
char bpc_localif[MAXNAMELEN + 1];
bool bpc_has_vrfname;
char bpc_vrfname[MAXNAMELEN + 1];
bool bpc_has_detectmultiplier;
uint8_t bpc_detectmultiplier;
bool bpc_has_recvinterval;
uint64_t bpc_recvinterval;
bool bpc_has_txinterval;
uint64_t bpc_txinterval;
bool bpc_has_echorecvinterval;
uint64_t bpc_echorecvinterval;
bool bpc_has_echotxinterval;
uint64_t bpc_echotxinterval;
bool bpc_has_minimum_ttl;
uint8_t bpc_minimum_ttl;
bool bpc_echo;
bool bpc_createonly;
bool bpc_shutdown;
bool bpc_cbit;
bool bpc_passive;
bool bpc_has_profile;
char bpc_profile[64];
};
/* bfd Authentication Type. */
#define BFD_AUTH_NULL 0
#define BFD_AUTH_SIMPLE 1
#define BFD_AUTH_CRYPTOGRAPHIC 2
struct bfd_timers {
uint32_t desired_min_tx;
@ -60,6 +121,15 @@ struct bfd_pkt {
struct bfd_timers timers;
};
/*
* Format of authentification.
*/
struct bfd_auth {
uint8_t type;
uint8_t length;
};
/*
* Format of Echo packet.
*/
@ -79,45 +149,48 @@ struct bfd_echo_pkt {
/* Macros for manipulating control packets */
#define BFD_VERMASK 0x03
#define BFD_VERMASK 0x07
#define BFD_DIAGMASK 0x1F
#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK)
#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5)
#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK))
#define BFD_SETVER(diag, val) \
SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5)
#define BFD_VERSION 1
#define BFD_PBIT 0x20
#define BFD_FBIT 0x10
#define BFD_CBIT 0x08
#define BFD_ABIT 0x04
#define BFD_DEMANDBIT 0x02
#define BFD_MBIT 0x01
#define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT))
#define BFD_SETDEMANDBIT(flags, val) \
{ \
if ((val)) \
flags |= BFD_DEMANDBIT; \
SET_FLAG(flags, BFD_DEMANDBIT); \
}
#define BFD_SETPBIT(flags, val) \
{ \
if ((val)) \
flags |= BFD_PBIT; \
SET_FLAG(flags, BFD_PBIT); \
}
#define BFD_GETPBIT(flags) (flags & BFD_PBIT)
#define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT))
#define BFD_SETFBIT(flags, val) \
{ \
if ((val)) \
flags |= BFD_FBIT; \
SET_FLAG(flags, BFD_FBIT); \
}
#define BFD_GETFBIT(flags) (flags & BFD_FBIT)
#define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT))
#define BFD_SETSTATE(flags, val) \
{ \
if ((val)) \
flags |= (val & 0x3) << 6; \
SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \
}
#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3)
#define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3))
#define BFD_SETCBIT(flags, val) \
{ \
if ((val)) \
flags |= val; \
SET_FLAG(flags, val); \
}
#define BFD_GETCBIT(flags) (flags & BFD_FBIT)
#define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT))
#define BFD_ECHO_VERSION 1
#define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt)
@ -179,7 +252,7 @@ struct bfd_key {
uint16_t mhop;
struct in6_addr peer;
struct in6_addr local;
char ifname[INTERFACE_NAMSIZ];
char ifname[IFNAMSIZ];
char vrfname[VRF_NAMSIZ];
} __attribute__((packed));
@ -227,9 +300,6 @@ struct bfd_profile {
/** Profile list type. */
TAILQ_HEAD(bfdproflist, bfd_profile);
/* bfd_session shortcut label forwarding. */
struct peer_label;
struct bfd_config_timers {
uint32_t desired_min_tx;
uint32_t required_min_rx;
@ -307,14 +377,6 @@ struct bfd_session {
uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */
};
struct peer_label {
TAILQ_ENTRY(peer_label) pl_entry;
struct bfd_session *pl_bs;
char pl_label[MAXNAMELEN];
};
TAILQ_HEAD(pllist, peer_label);
struct bfd_diag_str_list {
const char *str;
int type;
@ -366,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer);
#define BFD_DEF_ECHO_PORT 3785
#define BFD_DEF_MHOP_DEST_PORT 4784
/*
* control.c
*
* Daemon control code to speak with local consumers.
*/
/* See 'bfdctrl.h' for client protocol definitions. */
struct bfd_control_buffer {
size_t bcb_left;
size_t bcb_pos;
union {
struct bfd_control_msg *bcb_bcm;
uint8_t *bcb_buf;
};
};
struct bfd_control_queue {
TAILQ_ENTRY(bfd_control_queue) bcq_entry;
struct bfd_control_buffer bcq_bcb;
};
TAILQ_HEAD(bcqueue, bfd_control_queue);
struct bfd_notify_peer {
TAILQ_ENTRY(bfd_notify_peer) bnp_entry;
struct bfd_session *bnp_bs;
};
TAILQ_HEAD(bnplist, bfd_notify_peer);
struct bfd_control_socket {
TAILQ_ENTRY(bfd_control_socket) bcs_entry;
int bcs_sd;
struct event *bcs_ev;
struct event *bcs_outev;
struct bcqueue bcs_bcqueue;
/* Notification data */
uint64_t bcs_notify;
struct bnplist bcs_bnplist;
enum bc_msg_version bcs_version;
enum bc_msg_type bcs_type;
/* Message buffering */
struct bfd_control_buffer bcs_bin;
struct bfd_control_buffer *bcs_bout;
};
TAILQ_HEAD(bcslist, bfd_control_socket);
int control_init(const char *path);
void control_shutdown(void);
int control_notify(struct bfd_session *bs, uint8_t notify_state);
int control_notify_config(const char *op, struct bfd_session *bs);
void control_accept(struct event *t);
/*
* bfdd.c
@ -449,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx);
struct bfd_global {
int bg_csock;
struct event *bg_csockev;
struct bcslist bg_bcslist;
struct pllist bg_pllist;
struct obslist bg_obslist;
@ -497,27 +498,6 @@ extern const struct bfd_state_str_list state_list[];
void socket_close(int *s);
/*
* config.c
*
* Contains the code related with loading/reloading configuration.
*/
int parse_config(const char *fname);
int config_request_add(const char *jsonstr);
int config_request_del(const char *jsonstr);
char *config_response(const char *status, const char *error);
char *config_notify(struct bfd_session *bs);
char *config_notify_config(const char *op, struct bfd_session *bs);
typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg);
int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
bpc_handle bh);
struct peer_label *pl_new(const char *label, struct bfd_session *bs);
struct peer_label *pl_find(const char *label);
void pl_free(struct peer_label *pl);
/*
* logging - alias to zebra log
*/
@ -602,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
bool is_mhop);
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc);
int bfd_session_update_label(struct bfd_session *bs, const char *nlabel);
void bfd_set_polling(struct bfd_session *bs);
void bs_state_handler(struct bfd_session *bs, int nstate);
void bs_echo_timer_handler(struct bfd_session *bs);
@ -768,6 +747,7 @@ void bfdd_cli_init(void);
*/
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv);
void bfdd_zclient_stop(void);
void bfdd_zclient_terminate(void);
void bfdd_zclient_unregister(vrf_id_t vrf_id);
void bfdd_zclient_register(vrf_id_t vrf_id);
void bfdd_sessions_enable_vrf(struct vrf *vrf);

View file

@ -12,6 +12,11 @@
*/
#include <zebra.h>
#include <sys/ioctl.h>
#ifdef GNU_LINUX
#include <linux/filter.h>
#endif
#ifdef BFD_LINUX
#include <linux/if_packet.h>
@ -768,6 +773,37 @@ static void cp_debug(bool mhop, struct sockaddr_any *peer,
mhop ? "yes" : "no", peerstr, localstr, portstr, vrfstr);
}
static bool bfd_check_auth(const struct bfd_session *bfd,
const struct bfd_pkt *cp)
{
if (CHECK_FLAG(cp->flags, BFD_ABIT)) {
/* RFC5880 4.1: Authentication Section is present. */
struct bfd_auth *auth = (struct bfd_auth *)(cp + 1);
uint16_t pkt_auth_type = ntohs(auth->type);
if (cp->len < BFD_PKT_LEN + sizeof(struct bfd_auth))
return false;
if (cp->len < BFD_PKT_LEN + auth->length)
return false;
switch (pkt_auth_type) {
case BFD_AUTH_NULL:
return false;
case BFD_AUTH_SIMPLE:
/* RFC5880 6.7: To be finshed. */
return false;
case BFD_AUTH_CRYPTOGRAPHIC:
/* RFC5880 6.7: To be finshed. */
return false;
default:
/* RFC5880 6.7: To be finshed. */
return false;
}
}
return true;
}
void bfd_recv_cb(struct event *t)
{
int sd = EVENT_FD(t);
@ -862,6 +898,12 @@ void bfd_recv_cb(struct event *t)
return;
}
if (BFD_GETMBIT(cp->flags)) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"detect non-zero Multipoint (M) flag");
return;
}
if (cp->discrs.my_discr == 0) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"'my discriminator' is zero");
@ -878,7 +920,7 @@ void bfd_recv_cb(struct event *t)
/*
* We may have a situation where received packet is on wrong vrf
*/
if (bfd && bfd->vrf && bfd->vrf != bvrf->vrf) {
if (bfd && bfd->vrf && bfd->vrf->vrf_id != vrfid) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"wrong vrfid.");
return;
@ -932,8 +974,15 @@ void bfd_recv_cb(struct event *t)
bfd->discrs.remote_discr = ntohl(cp->discrs.my_discr);
/* Check authentication. */
if (!bfd_check_auth(bfd, cp)) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"Authentication failed");
return;
}
/* Save remote diagnostics before state switch. */
bfd->remote_diag = cp->diag & BFD_DIAGMASK;
bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK);
/* Update remote timers settings. */
bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx);
@ -1689,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd,
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET))
return;
if (ifp->flags & IFF_NOARP)
if (CHECK_FLAG(ifp->flags, IFF_NOARP))
return;
if (peer->sa_sin.sin_family == AF_INET) {
@ -1704,9 +1753,10 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd,
strlcpy(arpreq_.arp_dev, ifp->name, sizeof(arpreq_.arp_dev));
if (ioctl(sd, SIOCGARP, &arpreq_) < 0) {
zlog_warn(
"BFD: getting peer's mac on %s failed error %s",
ifp->name, strerror(errno));
if (bglobal.debug_network)
zlog_debug(
"BFD: getting peer's mac on %s failed error %s",
ifp->name, strerror(errno));
UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET);
memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr));

View file

@ -1,157 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* bfdctl.h: all BFDd control socket protocol definitions.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#ifndef _BFDCTRL_H_
#define _BFDCTRL_H_
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
/*
* Auxiliary definitions
*/
struct sockaddr_any {
union {
struct sockaddr_in sa_sin;
struct sockaddr_in6 sa_sin6;
};
};
#ifndef MAXNAMELEN
#define MAXNAMELEN 32
#endif
#define BPC_DEF_DETECTMULTIPLIER 3
#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
/* Peer status */
enum bfd_peer_status {
BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */
BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */
BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */
BPS_UP = 3, /* == PTM_BFD_UP, "up" */
};
struct bfd_peer_cfg {
bool bpc_mhop;
bool bpc_ipv4;
struct sockaddr_any bpc_peer;
struct sockaddr_any bpc_local;
bool bpc_has_label;
char bpc_label[MAXNAMELEN];
bool bpc_has_localif;
char bpc_localif[MAXNAMELEN + 1];
bool bpc_has_vrfname;
char bpc_vrfname[MAXNAMELEN + 1];
bool bpc_has_detectmultiplier;
uint8_t bpc_detectmultiplier;
bool bpc_has_recvinterval;
uint64_t bpc_recvinterval;
bool bpc_has_txinterval;
uint64_t bpc_txinterval;
bool bpc_has_echorecvinterval;
uint64_t bpc_echorecvinterval;
bool bpc_has_echotxinterval;
uint64_t bpc_echotxinterval;
bool bpc_has_minimum_ttl;
uint8_t bpc_minimum_ttl;
bool bpc_echo;
bool bpc_createonly;
bool bpc_shutdown;
bool bpc_cbit;
bool bpc_passive;
bool bpc_has_profile;
char bpc_profile[64];
/* Status information */
enum bfd_peer_status bpc_bps;
uint32_t bpc_id;
uint32_t bpc_remoteid;
uint8_t bpc_diag;
uint8_t bpc_remotediag;
uint8_t bpc_remote_detectmultiplier;
uint64_t bpc_remote_recvinterval;
uint64_t bpc_remote_txinterval;
uint64_t bpc_remote_echointerval;
uint64_t bpc_lastevent;
};
/*
* Protocol definitions
*/
enum bc_msg_version {
BMV_VERSION_1 = 1,
};
enum bc_msg_type {
BMT_RESPONSE = 1,
BMT_REQUEST_ADD = 2,
BMT_REQUEST_DEL = 3,
BMT_NOTIFY = 4,
BMT_NOTIFY_ADD = 5,
BMT_NOTIFY_DEL = 6,
};
/* Notify flags to use with bcm_notify. */
#define BCM_NOTIFY_ALL ((uint64_t)-1)
#define BCM_NOTIFY_PEER_STATE (1ULL << 0)
#define BCM_NOTIFY_CONFIG (1ULL << 1)
#define BCM_NOTIFY_NONE 0
/* Response 'status' definitions. */
#define BCM_RESPONSE_OK "ok"
#define BCM_RESPONSE_ERROR "error"
/* Notify operation. */
#define BCM_NOTIFY_PEER_STATUS "status"
#define BCM_NOTIFY_CONFIG_ADD "add"
#define BCM_NOTIFY_CONFIG_DELETE "delete"
#define BCM_NOTIFY_CONFIG_UPDATE "update"
/* Notification special ID. */
#define BCM_NOTIFY_ID 0
struct bfd_control_msg {
/* Total length without the header. */
uint32_t bcm_length;
/*
* Message request/response id.
* All requests will have a correspondent response with the
* same id.
*/
uint16_t bcm_id;
/* Message type. */
uint8_t bcm_type;
/* Message version. */
uint8_t bcm_ver;
/* Message payload. */
uint8_t bcm_data[0];
};
#endif

View file

@ -28,8 +28,8 @@
* FRR related code.
*/
DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data");
DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data");
/* Master of threads. */
struct event_loop *master;
@ -67,14 +67,13 @@ static void sigterm_handler(void)
/* Stop receiving message from zebra. */
bfdd_zclient_stop();
/* Shutdown controller to avoid receiving anymore commands. */
control_shutdown();
/* Shutdown and free all protocol related memory. */
bfd_shutdown();
bfd_vrf_terminate();
bfdd_zclient_terminate();
/* Terminate and free() FRR related memory. */
frr_fini();
@ -115,18 +114,23 @@ static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
&frr_vrf_info,
};
FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
.proghelp = "Implementation of the BFD protocol.",
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
.privs = &bglobal.bfdd_privs,
.yang_modules = bfdd_yang_modules,
.n_yang_modules = array_size(bfdd_yang_modules),
);
/* clang-format off */
FRR_DAEMON_INFO(bfdd, BFD,
.vty_port = BFDD_VTY_PORT,
.proghelp = "Implementation of the BFD protocol.",
.signals = bfd_signals,
.n_signals = array_size(bfd_signals),
.privs = &bglobal.bfdd_privs,
.yang_modules = bfdd_yang_modules,
.n_yang_modules = array_size(bfdd_yang_modules),
);
/* clang-format on */
#define OPTION_CTLSOCK 1001
#define OPTION_DPLANEADDR 2000
static const struct option longopts[] = {
{"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
{"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
{0}
};
@ -310,7 +314,6 @@ static void bg_init(void)
.cap_num_i = 0,
};
TAILQ_INIT(&bglobal.bg_bcslist);
TAILQ_INIT(&bglobal.bg_obslist);
memcpy(&bglobal.bfdd_privs, &bfdd_privs,
@ -319,8 +322,7 @@ static void bg_init(void)
int main(int argc, char *argv[])
{
char ctl_path[512], dplane_addr[512];
bool ctlsockused = false;
char dplane_addr[512];
int opt;
bglobal.bg_use_dplane = false;
@ -330,21 +332,14 @@ int main(int argc, char *argv[])
frr_preinit(&bfdd_di, argc, argv);
frr_opt_add("", longopts,
" --bfdctl Specify bfdd control socket\n"
" --dplaneaddr Specify BFD data plane address\n");
snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
"", "");
while (true) {
opt = frr_getopt(argc, argv, NULL);
if (opt == EOF)
break;
switch (opt) {
case OPTION_CTLSOCK:
strlcpy(ctl_path, optarg, sizeof(ctl_path));
ctlsockused = true;
break;
case OPTION_DPLANEADDR:
strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
bglobal.bg_use_dplane = true;
@ -355,16 +350,9 @@ int main(int argc, char *argv[])
}
}
if (bfdd_di.pathspace && !ctlsockused)
snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
"/", bfdd_di.pathspace);
/* Initialize FRR infrastructure. */
master = frr_init();
/* Initialize control socket. */
control_init(ctl_path);
/* Initialize BFD data structures. */
bfd_initialize();
@ -375,9 +363,6 @@ int main(int argc, char *argv[])
/* Initialize zebra connection. */
bfdd_zclient_init(&bglobal.bfdd_privs);
event_add_read(master, control_accept, NULL, bglobal.bg_csock,
&bglobal.bg_csockev);
/* Install commands. */
bfdd_vty_init();

View file

@ -219,24 +219,24 @@ static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults __attribute__((__unused__)),
bool mhop)
{
const char *vrf = yang_dnode_get_string(dnode, "./vrf");
const char *vrf = yang_dnode_get_string(dnode, "vrf");
vty_out(vty, " peer %s",
yang_dnode_get_string(dnode, "./dest-addr"));
yang_dnode_get_string(dnode, "dest-addr"));
if (mhop)
vty_out(vty, " multihop");
if (yang_dnode_exists(dnode, "./source-addr"))
if (yang_dnode_exists(dnode, "source-addr"))
vty_out(vty, " local-address %s",
yang_dnode_get_string(dnode, "./source-addr"));
yang_dnode_get_string(dnode, "source-addr"));
if (strcmp(vrf, VRF_DEFAULT_NAME))
vty_out(vty, " vrf %s", vrf);
if (!mhop) {
const char *ifname =
yang_dnode_get_string(dnode, "./interface");
yang_dnode_get_string(dnode, "interface");
if (strcmp(ifname, "*"))
vty_out(vty, " interface %s", ifname);
}
@ -338,11 +338,12 @@ void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_mult, bfd_peer_mult_cmd,
"detect-multiplier (2-255)$multiplier",
"[no] detect-multiplier ![(2-255)$multiplier]",
NO_STR
"Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n")
{
nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY,
nb_cli_enqueue_change(vty, "./detection-multiplier", no ? NB_OP_DESTROY : NB_OP_MODIFY,
multiplier_str);
return nb_cli_apply_changes(vty, NULL);
}
@ -356,14 +357,15 @@ void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_rx, bfd_peer_rx_cmd,
"receive-interval (10-60000)$interval",
"[no] receive-interval ![(10-60000)$interval]",
NO_STR
"Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n")
{
char value[32];
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY,
nb_cli_enqueue_change(vty, "./required-receive-interval", no ? NB_OP_DESTROY : NB_OP_MODIFY,
value);
return nb_cli_apply_changes(vty, NULL);
@ -379,7 +381,8 @@ void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_tx, bfd_peer_tx_cmd,
"transmit-interval (10-60000)$interval",
"[no] transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n")
{
@ -387,7 +390,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-transmission-interval",
NB_OP_MODIFY, value);
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@ -436,7 +439,8 @@ void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
"echo-interval (10-60000)$interval",
"[no] echo-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n"
"Configure peer echo rx/tx intervals value in milliseconds\n")
{
@ -449,16 +453,17 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
NB_OP_MODIFY, value);
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
NB_OP_MODIFY, value);
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG(
bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd,
"echo transmit-interval (10-60000)$interval",
"[no] echo transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n"
"Configure desired transmit interval\n"
"Configure interval value in milliseconds\n")
@ -472,7 +477,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
NB_OP_MODIFY, value);
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@ -487,7 +492,8 @@ void bfd_cli_show_desired_echo_transmission_interval(
DEFPY_YANG(
bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd,
"echo receive-interval <disabled$disabled|(10-60000)$interval>",
"[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
NO_STR
"Configure peer echo intervals\n"
"Configure required receive interval\n"
"Disable echo packets receive\n"
@ -506,7 +512,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
NB_OP_MODIFY, value);
no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@ -567,21 +573,24 @@ DEFPY_YANG(no_bfd_profile, no_bfd_profile_cmd,
void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name"));
vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "name"));
}
ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd,
"detect-multiplier (2-255)$multiplier",
"[no] detect-multiplier ![(2-255)$multiplier]",
NO_STR
"Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n")
ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd,
"transmit-interval (10-60000)$interval",
"[no] transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n")
ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd,
"receive-interval (10-60000)$interval",
"[no] receive-interval ![(10-60000)$interval]",
NO_STR
"Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n")
@ -612,20 +621,23 @@ ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
"Configure echo mode\n")
ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
"echo-interval (10-60000)$interval",
"[no] echo-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo interval\n"
"Configure peer echo interval value in milliseconds\n")
ALIAS_YANG(
bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd,
"echo transmit-interval (10-60000)$interval",
"[no] echo transmit-interval ![(10-60000)$interval]",
NO_STR
"Configure peer echo intervals\n"
"Configure desired transmit interval\n"
"Configure interval value in milliseconds\n")
ALIAS_YANG(
bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd,
"echo receive-interval <disabled$disabled|(10-60000)$interval>",
"[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
NO_STR
"Configure peer echo intervals\n"
"Configure required receive interval\n"
"Disable echo packets receive\n"

View file

@ -74,7 +74,6 @@ const struct frr_yang_module_info frr_bfdd_info = {
.xpath = "/frr-bfdd:bfdd/bfd/profile/minimum-ttl",
.cbs = {
.modify = bfdd_bfd_profile_minimum_ttl_modify,
.destroy = bfdd_bfd_profile_minimum_ttl_destroy,
.cli_show = bfd_cli_show_minimum_ttl,
}
},
@ -361,7 +360,6 @@ const struct frr_yang_module_info frr_bfdd_info = {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl",
.cbs = {
.modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify,
.destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy,
.cli_show = bfd_cli_show_minimum_ttl,
}
},

View file

@ -25,7 +25,6 @@ int bfdd_bfd_profile_required_receive_interval_modify(
int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args);
int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args);
@ -128,8 +127,6 @@ int bfdd_bfd_sessions_multi_hop_administrative_down_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy(
struct nb_cb_destroy_args *args);
struct yang_data *
bfdd_bfd_sessions_multi_hop_stats_local_discriminator_get_elem(
struct nb_cb_get_elem_args *args);

View file

@ -24,17 +24,17 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
struct sockaddr_any psa, lsa;
/* Required destination parameter. */
strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa);
strtosa(yang_dnode_get_string(dnode, "dest-addr"), &psa);
/* Get optional source address. */
memset(&lsa, 0, sizeof(lsa));
if (yang_dnode_exists(dnode, "./source-addr"))
strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
if (yang_dnode_exists(dnode, "source-addr"))
strtosa(yang_dnode_get_string(dnode, "source-addr"), &lsa);
vrfname = yang_dnode_get_string(dnode, "./vrf");
vrfname = yang_dnode_get_string(dnode, "vrf");
if (!mhop) {
ifname = yang_dnode_get_string(dnode, "./interface");
ifname = yang_dnode_get_string(dnode, "interface");
if (strcmp(ifname, "*") == 0)
ifname = NULL;
}
@ -53,7 +53,7 @@ static int session_iter_cb(const struct lyd_node *dnode, void *arg)
struct session_iter *iter = arg;
const char *ifname;
ifname = yang_dnode_get_string(dnode, "./interface");
ifname = yang_dnode_get_string(dnode, "interface");
if (strmatch(ifname, "*"))
iter->wildcard = true;
@ -76,7 +76,7 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop)
switch (args->event) {
case NB_EV_VALIDATE:
yang_dnode_get_prefix(&p, args->dnode, "./dest-addr");
yang_dnode_get_prefix(&p, args->dnode, "dest-addr");
if (mhop) {
/*
@ -97,7 +97,7 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop)
* require interface name, otherwise we can't figure
* which interface to use to send the packets.
*/
ifname = yang_dnode_get_string(args->dnode, "./interface");
ifname = yang_dnode_get_string(args->dnode, "interface");
if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
&& strcmp(ifname, "*") == 0) {
@ -112,8 +112,8 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop)
sess_dnode = yang_dnode_get_parent(args->dnode, "sessions");
dest = yang_dnode_get_string(args->dnode, "./dest-addr");
vrfname = yang_dnode_get_string(args->dnode, "./vrf");
dest = yang_dnode_get_string(args->dnode, "dest-addr");
vrfname = yang_dnode_get_string(args->dnode, "vrf");
yang_dnode_iterate(session_iter_cb, &iter, sess_dnode,
"./single-hop[dest-addr='%s'][vrf='%s']",
@ -275,7 +275,7 @@ int bfdd_bfd_profile_create(struct nb_cb_create_args *args)
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "./name");
name = yang_dnode_get_string(args->dnode, "name");
bp = bfd_profile_new(name);
nb_running_set_entry(args->dnode, bp);
@ -423,20 +423,6 @@ int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args)
return NB_OK;
}
int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args)
{
struct bfd_profile *bp;
if (args->event != NB_EV_APPLY)
return NB_OK;
bp = nb_running_get_entry(args->dnode, NULL, true);
bp->minimum_ttl = BFD_DEF_MHOP_TTL;
bfd_profile_update(bp);
return NB_OK;
}
/*
* XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode
*/
@ -859,27 +845,3 @@ int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify(
return NB_OK;
}
int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy(
struct nb_cb_destroy_args *args)
{
struct bfd_session *bs;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
return NB_OK;
case NB_EV_APPLY:
break;
case NB_EV_ABORT:
return NB_OK;
}
bs = nb_running_get_entry(args->dnode, NULL, true);
bs->peer_profile.minimum_ttl = BFD_DEF_MHOP_TTL;
bfd_session_apply(bs);
return NB_OK;
}

View file

@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n");
if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
}
static void _display_peer(struct vty *vty, struct bfd_session *bs)
@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs)
if (bs->key.ifname[0])
json_object_string_add(jo, "interface", bs->key.ifname);
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
return jo;
}
@ -213,6 +207,8 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
uint32_t avg = 0;
uint32_t max = 0;
if (bs->key.ifname[0])
json_object_string_add(jo, "interface", bs->key.ifname);
json_object_int_add(jo, "id", bs->discrs.my_discr);
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
json_object_boolean_add(jo, "passive-mode",
@ -246,6 +242,10 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
json_object_string_add(jo, "remote-diagnostic",
diag2str(bs->remote_diag));
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
json_object_string_add(jo, "type", "configured");
else
json_object_string_add(jo, "type", "dynamic");
json_object_int_add(jo, "receive-interval",
bs->timers.required_min_rx / 1000);
@ -555,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
int idx;
bool mhop;
struct bfd_session *bs = NULL;
struct peer_label *pl;
struct bfd_peer_cfg bpc;
struct sockaddr_any psa, lsa, *lsap;
char errormsg[128];
/* Look up the BFD peer. */
if (label) {
pl = pl_find(label);
if (pl)
bs = pl->pl_bs;
} else if (peer_str) {
if (peer_str) {
strtosa(peer_str, &psa);
if (local_str) {
strtosa(local_str, &lsa);
@ -873,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
bpc->bpc_lastevent = monotime(NULL);
/* Safety check: when no error buf is provided len must be zero. */
if (ebuf == NULL)

View file

@ -1,592 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* config.c: implements the BFD daemon configuration handling.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#include <zebra.h>
#include <string.h>
#include "lib/json.h"
#include "bfd.h"
DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory");
/*
* Definitions
*/
enum peer_list_type {
PLT_IPV4,
PLT_IPV6,
PLT_LABEL,
};
/*
* Prototypes
*/
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg);
static int parse_list(struct json_object *jo, enum peer_list_type plt,
bpc_handle h, void *arg);
static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc);
static int parse_peer_label_config(struct json_object *jo,
struct bfd_peer_cfg *bpc);
static int config_add(struct bfd_peer_cfg *bpc, void *arg);
static int config_del(struct bfd_peer_cfg *bpc, void *arg);
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs);
/*
* Implementation
*/
static int config_add(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
return ptm_bfd_sess_new(bpc) == NULL;
}
static int config_del(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
return ptm_bfd_sess_del(bpc) != 0;
}
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
{
const char *key, *sval;
struct json_object *jo_val;
struct json_object_iterator joi, join;
int error = 0;
JSON_FOREACH (jo, joi, join) {
key = json_object_iter_peek_name(&joi);
jo_val = json_object_iter_peek_value(&joi);
if (strcmp(key, "ipv4") == 0) {
error += parse_list(jo_val, PLT_IPV4, h, arg);
} else if (strcmp(key, "ipv6") == 0) {
error += parse_list(jo_val, PLT_IPV6, h, arg);
} else if (strcmp(key, "label") == 0) {
error += parse_list(jo_val, PLT_LABEL, h, arg);
} else {
sval = json_object_get_string(jo_val);
zlog_warn("%s:%d invalid configuration: %s", __func__,
__LINE__, sval);
error++;
}
}
/*
* Our callers never call free() on json_object and only expect
* the return value, so lets free() it here.
*/
json_object_put(jo);
return error;
}
int parse_config(const char *fname)
{
struct json_object *jo;
jo = json_object_from_file(fname);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_add, NULL);
}
static int parse_list(struct json_object *jo, enum peer_list_type plt,
bpc_handle h, void *arg)
{
struct json_object *jo_val;
struct bfd_peer_cfg bpc;
int allen, idx;
int error = 0, result;
allen = json_object_array_length(jo);
for (idx = 0; idx < allen; idx++) {
jo_val = json_object_array_get_idx(jo, idx);
/* Set defaults. */
memset(&bpc, 0, sizeof(bpc));
bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT;
bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX;
bpc.bpc_txinterval = BFD_DEFDESIREDMINTX;
bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX;
bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX;
switch (plt) {
case PLT_IPV4:
zlog_debug("ipv4 peers %d:", allen);
bpc.bpc_ipv4 = true;
break;
case PLT_IPV6:
zlog_debug("ipv6 peers %d:", allen);
bpc.bpc_ipv4 = false;
break;
case PLT_LABEL:
zlog_debug("label peers %d:", allen);
if (parse_peer_label_config(jo_val, &bpc) != 0) {
error++;
continue;
}
break;
default:
error++;
zlog_err("%s:%d: unsupported peer type", __func__,
__LINE__);
break;
}
result = parse_peer_config(jo_val, &bpc);
error += result;
if (result == 0)
error += (h(&bpc, arg) != 0);
}
return error;
}
static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
{
const char *key, *sval;
struct json_object *jo_val;
struct json_object_iterator joi, join;
int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
int error = 0;
zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6");
JSON_FOREACH (jo, joi, join) {
key = json_object_iter_peek_name(&joi);
jo_val = json_object_iter_peek_value(&joi);
if (strcmp(key, "multihop") == 0) {
bpc->bpc_mhop = json_object_get_boolean(jo_val);
zlog_debug(" multihop: %s",
bpc->bpc_mhop ? "true" : "false");
} else if (strcmp(key, "peer-address") == 0) {
sval = json_object_get_string(jo_val);
if (strtosa(sval, &bpc->bpc_peer) != 0
|| bpc->bpc_peer.sa_sin.sin_family != family_type) {
zlog_debug(
"%s:%d failed to parse peer-address '%s'",
__func__, __LINE__, sval);
error++;
}
zlog_debug(" peer-address: %s", sval);
} else if (strcmp(key, "local-address") == 0) {
sval = json_object_get_string(jo_val);
if (strtosa(sval, &bpc->bpc_local) != 0
|| bpc->bpc_local.sa_sin.sin_family
!= family_type) {
zlog_debug(
"%s:%d failed to parse local-address '%s'",
__func__, __LINE__, sval);
error++;
}
zlog_debug(" local-address: %s", sval);
} else if (strcmp(key, "local-interface") == 0) {
bpc->bpc_has_localif = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_localif, sval,
sizeof(bpc->bpc_localif))
> sizeof(bpc->bpc_localif)) {
zlog_debug(
" local-interface: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" local-interface: %s", sval);
}
} else if (strcmp(key, "vrf-name") == 0) {
bpc->bpc_has_vrfname = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_vrfname, sval,
sizeof(bpc->bpc_vrfname))
> sizeof(bpc->bpc_vrfname)) {
zlog_debug(" vrf-name: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" vrf-name: %s", sval);
}
} else if (strcmp(key, "detect-multiplier") == 0) {
bpc->bpc_detectmultiplier =
json_object_get_int64(jo_val);
bpc->bpc_has_detectmultiplier = true;
zlog_debug(" detect-multiplier: %u",
bpc->bpc_detectmultiplier);
} else if (strcmp(key, "receive-interval") == 0) {
bpc->bpc_recvinterval = json_object_get_int64(jo_val);
bpc->bpc_has_recvinterval = true;
zlog_debug(" receive-interval: %" PRIu64,
bpc->bpc_recvinterval);
} else if (strcmp(key, "transmit-interval") == 0) {
bpc->bpc_txinterval = json_object_get_int64(jo_val);
bpc->bpc_has_txinterval = true;
zlog_debug(" transmit-interval: %" PRIu64,
bpc->bpc_txinterval);
} else if (strcmp(key, "echo-receive-interval") == 0) {
bpc->bpc_echorecvinterval = json_object_get_int64(jo_val);
bpc->bpc_has_echorecvinterval = true;
zlog_debug(" echo-receive-interval: %" PRIu64,
bpc->bpc_echorecvinterval);
} else if (strcmp(key, "echo-transmit-interval") == 0) {
bpc->bpc_echotxinterval = json_object_get_int64(jo_val);
bpc->bpc_has_echotxinterval = true;
zlog_debug(" echo-transmit-interval: %" PRIu64,
bpc->bpc_echotxinterval);
} else if (strcmp(key, "create-only") == 0) {
bpc->bpc_createonly = json_object_get_boolean(jo_val);
zlog_debug(" create-only: %s",
bpc->bpc_createonly ? "true" : "false");
} else if (strcmp(key, "shutdown") == 0) {
bpc->bpc_shutdown = json_object_get_boolean(jo_val);
zlog_debug(" shutdown: %s",
bpc->bpc_shutdown ? "true" : "false");
} else if (strcmp(key, "echo-mode") == 0) {
bpc->bpc_echo = json_object_get_boolean(jo_val);
zlog_debug(" echo-mode: %s",
bpc->bpc_echo ? "true" : "false");
} else if (strcmp(key, "label") == 0) {
bpc->bpc_has_label = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_label, sval,
sizeof(bpc->bpc_label))
> sizeof(bpc->bpc_label)) {
zlog_debug(" label: %s (truncated)",
sval);
error++;
} else {
zlog_debug(" label: %s", sval);
}
} else {
sval = json_object_get_string(jo_val);
zlog_warn("%s:%d invalid configuration: '%s: %s'",
__func__, __LINE__, key, sval);
error++;
}
}
if (bpc->bpc_peer.sa_sin.sin_family == 0) {
zlog_debug("%s:%d no peer address provided", __func__,
__LINE__);
error++;
}
return error;
}
static int parse_peer_label_config(struct json_object *jo,
struct bfd_peer_cfg *bpc)
{
struct peer_label *pl;
struct json_object *label;
const char *sval;
/* Get label and translate it to BFD daemon key. */
if (!json_object_object_get_ex(jo, "label", &label))
return 1;
sval = json_object_get_string(label);
pl = pl_find(sval);
if (pl == NULL)
return 1;
zlog_debug(" peer-label: %s", sval);
/* Translate the label into BFD address keys. */
bs_to_bpc(pl->pl_bs, bpc);
return 0;
}
/*
* Control socket JSON parsing.
*/
int config_request_add(const char *jsonstr)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_add, NULL);
}
int config_request_del(const char *jsonstr)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, config_del, NULL);
}
char *config_response(const char *status, const char *error)
{
struct json_object *resp, *jo;
char *jsonstr;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
/* Add 'status' response key. */
jo = json_object_new_string(status);
if (jo == NULL) {
json_object_put(resp);
return NULL;
}
json_object_object_add(resp, "status", jo);
/* Add 'error' response key. */
if (error != NULL) {
jo = json_object_new_string(error);
if (jo == NULL) {
json_object_put(resp);
return NULL;
}
json_object_object_add(resp, "error", jo);
}
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
char *config_notify(struct bfd_session *bs)
{
struct json_object *resp;
char *jsonstr;
time_t now;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS);
json_object_add_peer(resp, bs);
/* Add status information */
json_object_int_add(resp, "id", bs->discrs.my_discr);
json_object_int_add(resp, "remote-id", bs->discrs.my_discr);
switch (bs->ses_state) {
case PTM_BFD_UP:
json_object_string_add(resp, "state", "up");
now = monotime(NULL);
json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec);
break;
case PTM_BFD_ADM_DOWN:
json_object_string_add(resp, "state", "adm-down");
break;
case PTM_BFD_DOWN:
json_object_string_add(resp, "state", "down");
now = monotime(NULL);
json_object_int_add(resp, "downtime",
now - bs->downtime.tv_sec);
break;
case PTM_BFD_INIT:
json_object_string_add(resp, "state", "init");
break;
default:
json_object_string_add(resp, "state", "unknown");
break;
}
json_object_int_add(resp, "diagnostics", bs->local_diag);
json_object_int_add(resp, "remote-diagnostics", bs->remote_diag);
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
char *config_notify_config(const char *op, struct bfd_session *bs)
{
struct json_object *resp;
char *jsonstr;
resp = json_object_new_object();
if (resp == NULL)
return NULL;
json_object_string_add(resp, "op", op);
json_object_add_peer(resp, bs);
/* On peer deletion we don't need to add any additional information. */
if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0)
goto skip_config;
json_object_int_add(resp, "detect-multiplier", bs->detect_mult);
json_object_int_add(resp, "receive-interval",
bs->timers.required_min_rx / 1000);
json_object_int_add(resp, "transmit-interval",
bs->timers.desired_min_tx / 1000);
json_object_int_add(resp, "echo-receive-interval",
bs->timers.required_min_echo_rx / 1000);
json_object_int_add(resp, "echo-transmit-interval",
bs->timers.desired_min_echo_tx / 1000);
json_object_int_add(resp, "remote-detect-multiplier",
bs->remote_detect_mult);
json_object_int_add(resp, "remote-receive-interval",
bs->remote_timers.required_min_rx / 1000);
json_object_int_add(resp, "remote-transmit-interval",
bs->remote_timers.desired_min_tx / 1000);
json_object_int_add(resp, "remote-echo-receive-interval",
bs->remote_timers.required_min_echo / 1000);
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
json_object_boolean_true_add(resp, "echo-mode");
else
json_object_boolean_false_add(resp, "echo-mode");
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
json_object_boolean_true_add(resp, "shutdown");
else
json_object_boolean_false_add(resp, "shutdown");
skip_config:
/* Generate JSON response. */
jsonstr = XSTRDUP(
MTYPE_BFDD_NOTIFICATION,
json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
json_object_put(resp);
return jsonstr;
}
int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
bpc_handle bh)
{
struct json_object *jo;
jo = json_tokener_parse(jsonstr);
if (jo == NULL)
return -1;
return parse_config_json(jo, bh, bcs);
}
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{
char addr_buf[INET6_ADDRSTRLEN];
/* Add peer 'key' information. */
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "ipv6");
else
json_object_boolean_false_add(jo, "ipv6");
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(
jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.ifname[0])
json_object_string_add(jo, "local-interface",
bs->key.ifname);
}
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
return 0;
}
/*
* Label handling
*/
struct peer_label *pl_find(const char *label)
{
struct peer_label *pl;
TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) {
if (strcmp(pl->pl_label, label) != 0)
continue;
return pl;
}
return NULL;
}
struct peer_label *pl_new(const char *label, struct bfd_session *bs)
{
struct peer_label *pl;
pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl));
if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label))
> sizeof(pl->pl_label))
zlog_warn("%s:%d: label was truncated", __func__, __LINE__);
pl->pl_bs = bs;
bs->pl = pl;
TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry);
return pl;
}
void pl_free(struct peer_label *pl)
{
if (pl == NULL)
return;
/* Remove the pointer back. */
pl->pl_bs->pl = NULL;
TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry);
XFREE(MTYPE_BFDD_LABEL, pl);
}

View file

@ -1,841 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*********************************************************************
* Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
*
* control.c: implements the BFD daemon control socket. It will be used
* to talk with clients daemon/scripts/consumers.
*
* Authors
* -------
* Rafael Zalamena <rzalamena@opensourcerouting.org>
*/
#include <zebra.h>
#include <sys/un.h>
#include "bfd.h"
/*
* Prototypes
*/
static int sock_set_nonblock(int fd);
struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs);
static void control_queue_free(struct bfd_control_socket *bcs,
struct bfd_control_queue *bcq);
static int control_queue_dequeue(struct bfd_control_socket *bcs);
static int control_queue_enqueue(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
struct bfd_session *bs);
static void control_notifypeer_free(struct bfd_control_socket *bcs,
struct bfd_notify_peer *bnp);
struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
struct bfd_session *bs);
struct bfd_control_socket *control_new(int sd);
static void control_free(struct bfd_control_socket *bcs);
static void control_reset_buf(struct bfd_control_buffer *bcb);
static void control_read(struct event *t);
static void control_write(struct event *t);
static void control_handle_request_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_handle_request_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg);
static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg);
static void control_handle_notify_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_handle_notify_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void _control_handle_notify(struct hash_bucket *hb, void *arg);
static void control_handle_notify(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm);
static void control_response(struct bfd_control_socket *bcs, uint16_t id,
const char *status, const char *error);
static void _control_notify_config(struct bfd_control_socket *bcs,
const char *op, struct bfd_session *bs);
static void _control_notify(struct bfd_control_socket *bcs,
struct bfd_session *bs);
/*
* Functions
*/
static int sock_set_nonblock(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno));
return -1;
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1) {
zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno));
return -1;
}
return 0;
}
int control_init(const char *path)
{
int sd;
mode_t umval;
struct sockaddr_un sun_ = {
.sun_family = AF_UNIX,
.sun_path = BFDD_CONTROL_SOCKET,
};
if (path)
strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path));
/* Remove previously created sockets. */
unlink(sun_.sun_path);
sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
if (sd == -1) {
zlog_err("%s: socket: %s", __func__, strerror(errno));
return -1;
}
umval = umask(0);
if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) {
zlog_err("%s: bind: %s", __func__, strerror(errno));
close(sd);
return -1;
}
umask(umval);
if (listen(sd, SOMAXCONN) == -1) {
zlog_err("%s: listen: %s", __func__, strerror(errno));
close(sd);
return -1;
}
sock_set_nonblock(sd);
bglobal.bg_csock = sd;
return 0;
}
void control_shutdown(void)
{
struct bfd_control_socket *bcs;
event_cancel(&bglobal.bg_csockev);
socket_close(&bglobal.bg_csock);
while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) {
bcs = TAILQ_FIRST(&bglobal.bg_bcslist);
control_free(bcs);
}
}
void control_accept(struct event *t)
{
int csock, sd = EVENT_FD(t);
csock = accept(sd, NULL, 0);
if (csock == -1) {
zlog_warn("%s: accept: %s", __func__, strerror(errno));
return;
}
control_new(csock);
event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev);
}
/*
* Client handling
*/
struct bfd_control_socket *control_new(int sd)
{
struct bfd_control_socket *bcs;
bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs));
/* Disable notifications by default. */
bcs->bcs_notify = 0;
bcs->bcs_sd = sd;
event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
TAILQ_INIT(&bcs->bcs_bcqueue);
TAILQ_INIT(&bcs->bcs_bnplist);
TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry);
return bcs;
}
static void control_free(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
struct bfd_notify_peer *bnp;
event_cancel(&(bcs->bcs_ev));
event_cancel(&(bcs->bcs_outev));
close(bcs->bcs_sd);
TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry);
/* Empty output queue. */
while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) {
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
control_queue_free(bcs, bcq);
}
/* Empty notification list. */
while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) {
bnp = TAILQ_FIRST(&bcs->bcs_bnplist);
control_notifypeer_free(bcs, bnp);
}
control_reset_buf(&bcs->bcs_bin);
XFREE(MTYPE_BFDD_CONTROL, bcs);
}
struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_notify_peer *bnp;
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
return bnp;
bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp));
TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry);
bnp->bnp_bs = bs;
bs->refcount++;
return bnp;
}
static void control_notifypeer_free(struct bfd_control_socket *bcs,
struct bfd_notify_peer *bnp)
{
TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry);
bnp->bnp_bs->refcount--;
XFREE(MTYPE_BFDD_CONTROL, bnp);
}
struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_notify_peer *bnp;
TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) {
if (bnp->bnp_bs == bs)
return bnp;
}
return NULL;
}
struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq));
control_reset_buf(&bcq->bcq_bcb);
TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry);
return bcq;
}
static void control_queue_free(struct bfd_control_socket *bcs,
struct bfd_control_queue *bcq)
{
control_reset_buf(&bcq->bcq_bcb);
TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry);
XFREE(MTYPE_BFDD_NOTIFICATION, bcq);
}
static int control_queue_dequeue(struct bfd_control_socket *bcs)
{
struct bfd_control_queue *bcq;
/* List is empty, nothing to do. */
if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
goto empty_list;
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
control_queue_free(bcs, bcq);
/* Get the next buffer to send. */
if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
goto empty_list;
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
bcs->bcs_bout = &bcq->bcq_bcb;
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return 1;
empty_list:
event_cancel(&(bcs->bcs_outev));
bcs->bcs_bout = NULL;
return 0;
}
static int control_queue_enqueue(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
struct bfd_control_queue *bcq;
struct bfd_control_buffer *bcb;
bcq = control_queue_new(bcs);
bcb = &bcq->bcq_bcb;
bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length);
bcb->bcb_pos = 0;
bcb->bcb_bcm = bcm;
/* If this is the first item, then dequeue and start using it. */
if (bcs->bcs_bout == NULL) {
bcs->bcs_bout = bcb;
/* New messages, active write events. */
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
}
return 0;
}
static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
struct bfd_control_queue *bcq, *bcqn;
struct bfd_control_buffer *bcb;
/* Enqueue it somewhere. */
if (control_queue_enqueue(bcs, bcm) == -1)
return -1;
/*
* The item is either the first or the last. So we must first
* check the best case where the item is already the first.
*/
bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
bcb = &bcq->bcq_bcb;
if (bcm == bcb->bcb_bcm)
return 0;
/*
* The item was not the first, so it is the last. We'll try to
* assign it to the head of the queue, however if there is a
* transfer in progress, then we have to make the item as the
* next one.
*
* Interrupting the transfer of in progress message will cause
* the client to lose track of the message position/data.
*/
bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue);
TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry);
if (bcb->bcb_pos != 0) {
/*
* First position is already being sent, insert into
* second position.
*/
TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry);
} else {
/*
* Old message didn't start being sent, we still have
* time to put this one in the head of the queue.
*/
TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry);
bcb = &bcqn->bcq_bcb;
bcs->bcs_bout = bcb;
}
return 0;
}
static void control_reset_buf(struct bfd_control_buffer *bcb)
{
/* Get ride of old data. */
XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
bcb->bcb_pos = 0;
bcb->bcb_left = 0;
}
static void control_read(struct event *t)
{
struct bfd_control_socket *bcs = EVENT_ARG(t);
struct bfd_control_buffer *bcb = &bcs->bcs_bin;
int sd = bcs->bcs_sd;
struct bfd_control_msg bcm;
ssize_t bread;
size_t plen;
/*
* Check if we have already downloaded message content, if so then skip
* to
* download the rest of it and process.
*
* Otherwise download a new message header and allocate the necessary
* memory.
*/
if (bcb->bcb_buf != NULL)
goto skip_header;
bread = read(sd, &bcm, sizeof(bcm));
if (bread == 0) {
control_free(bcs);
return;
}
if (bread < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
goto schedule_next_read;
zlog_warn("%s: read: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
/* Validate header fields. */
plen = ntohl(bcm.bcm_length);
if (plen < 2) {
zlog_debug("%s: client closed due small message length: %d",
__func__, bcm.bcm_length);
control_free(bcs);
return;
}
#define FRR_BFD_MAXLEN 10 * 1024
if (plen > FRR_BFD_MAXLEN) {
zlog_debug("%s: client closed, invalid message length: %d",
__func__, bcm.bcm_length);
control_free(bcs);
return;
}
if (bcm.bcm_ver != BMV_VERSION_1) {
zlog_debug("%s: client closed due bad version: %d", __func__,
bcm.bcm_ver);
control_free(bcs);
return;
}
/* Prepare the buffer to load the message. */
bcs->bcs_version = bcm.bcm_ver;
bcs->bcs_type = bcm.bcm_type;
bcb->bcb_pos = sizeof(bcm);
bcb->bcb_left = plen;
bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(bcm) + bcb->bcb_left + 1);
if (bcb->bcb_buf == NULL) {
zlog_warn("%s: not enough memory for message size: %zu",
__func__, bcb->bcb_left);
control_free(bcs);
return;
}
memcpy(bcb->bcb_buf, &bcm, sizeof(bcm));
/* Terminate data string with NULL for later processing. */
bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0;
skip_header:
/* Download the remaining data of the message and process it. */
bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
if (bread == 0) {
control_free(bcs);
return;
}
if (bread < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
goto schedule_next_read;
zlog_warn("%s: read: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
bcb->bcb_pos += bread;
bcb->bcb_left -= bread;
/* We need more data, return to wait more. */
if (bcb->bcb_left > 0)
goto schedule_next_read;
switch (bcb->bcb_bcm->bcm_type) {
case BMT_REQUEST_ADD:
control_handle_request_add(bcs, bcb->bcb_bcm);
break;
case BMT_REQUEST_DEL:
control_handle_request_del(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY:
control_handle_notify(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY_ADD:
control_handle_notify_add(bcs, bcb->bcb_bcm);
break;
case BMT_NOTIFY_DEL:
control_handle_notify_del(bcs, bcb->bcb_bcm);
break;
default:
zlog_debug("%s: unhandled message type: %d", __func__,
bcb->bcb_bcm->bcm_type);
control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR,
"invalid message type");
break;
}
bcs->bcs_version = 0;
bcs->bcs_type = 0;
control_reset_buf(bcb);
schedule_next_read:
bcs->bcs_ev = NULL;
event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
}
static void control_write(struct event *t)
{
struct bfd_control_socket *bcs = EVENT_ARG(t);
struct bfd_control_buffer *bcb = bcs->bcs_bout;
int sd = bcs->bcs_sd;
ssize_t bwrite;
bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
if (bwrite == 0) {
control_free(bcs);
return;
}
if (bwrite < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return;
}
zlog_warn("%s: write: %s", __func__, strerror(errno));
control_free(bcs);
return;
}
bcb->bcb_pos += bwrite;
bcb->bcb_left -= bwrite;
if (bcb->bcb_left > 0) {
bcs->bcs_outev = NULL;
event_add_write(master, control_write, bcs, bcs->bcs_sd,
&bcs->bcs_outev);
return;
}
control_queue_dequeue(bcs);
}
/*
* Message processing
*/
static void control_handle_request_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_request_add(json) == 0)
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
else
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"request add failed");
}
static void control_handle_request_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_request_del(json) == 0)
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
else
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"request del failed");
}
static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc)
{
struct peer_label *pl;
if (bpc->bpc_has_label) {
pl = pl_find(bpc->bpc_label);
if (pl)
return pl->pl_bs;
}
return bs_peer_find(bpc);
}
static void _control_handle_notify(struct hash_bucket *hb, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = hb->data;
/* Notify peer configuration. */
if (bcs->bcs_notify & BCM_NOTIFY_CONFIG)
_control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs);
/* Notify peer status. */
if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE)
_control_notify(bcs, bs);
}
static void control_handle_notify(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify));
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
/*
* If peer asked for notification configuration, send everything that
* was configured until the moment to sync up.
*/
if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE))
bfd_id_iterate(_control_handle_notify, bcs);
}
static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = _notify_find_peer(bpc);
if (bs == NULL)
return -1;
control_notifypeer_new(bcs, bs);
/* Notify peer status. */
_control_notify(bcs, bs);
return 0;
}
static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg)
{
struct bfd_control_socket *bcs = arg;
struct bfd_session *bs = _notify_find_peer(bpc);
struct bfd_notify_peer *bnp;
if (bs == NULL)
return -1;
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
control_notifypeer_free(bcs, bnp);
return 0;
}
static void control_handle_notify_add(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_notify_request(bcs, json, notify_add_cb) == 0) {
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
return;
}
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"failed to parse notify data");
}
static void control_handle_notify_del(struct bfd_control_socket *bcs,
struct bfd_control_msg *bcm)
{
const char *json = (const char *)bcm->bcm_data;
if (config_notify_request(bcs, json, notify_del_cb) == 0) {
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
return;
}
control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
"failed to parse notify data");
}
/*
* Internal functions used by the BFD daemon.
*/
static void control_response(struct bfd_control_socket *bcs, uint16_t id,
const char *status, const char *error)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_response(status, error);
if (jsonstr == NULL) {
zlog_warn("%s: config_response: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_RESPONSE;
bcm->bcm_id = id;
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue_first(bcs, bcm);
}
static void _control_notify(struct bfd_control_socket *bcs,
struct bfd_session *bs)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_notify(bs);
if (jsonstr == NULL) {
zlog_warn("%s: config_notify: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_NOTIFY;
bcm->bcm_id = htons(BCM_NOTIFY_ID);
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue(bcs, bcm);
}
int control_notify(struct bfd_session *bs, uint8_t notify_state)
{
struct bfd_control_socket *bcs;
struct bfd_notify_peer *bnp;
/* Notify zebra listeners as well. */
ptm_bfd_notify(bs, notify_state);
/*
* PERFORMANCE: reuse the bfd_control_msg allocated data for
* all control sockets to avoid wasting memory.
*/
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
/*
* Test for all notifications first, then search for
* specific peers.
*/
if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) {
bnp = control_notifypeer_find(bcs, bs);
/*
* If the notification is not configured here,
* don't send it.
*/
if (bnp == NULL)
continue;
}
_control_notify(bcs, bs);
}
return 0;
}
static void _control_notify_config(struct bfd_control_socket *bcs,
const char *op, struct bfd_session *bs)
{
struct bfd_control_msg *bcm;
char *jsonstr;
size_t jsonstrlen;
/* Generate JSON response. */
jsonstr = config_notify_config(op, bs);
if (jsonstr == NULL) {
zlog_warn("%s: config_notify_config: failed to get JSON str",
__func__);
return;
}
/* Allocate data and answer. */
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
bcm->bcm_type = BMT_NOTIFY;
bcm->bcm_id = htons(BCM_NOTIFY_ID);
memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
control_queue_enqueue(bcs, bcm);
}
int control_notify_config(const char *op, struct bfd_session *bs)
{
struct bfd_control_socket *bcs;
struct bfd_notify_peer *bnp;
/* Remove the control sockets notification for this peer. */
if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) {
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
bnp = control_notifypeer_find(bcs, bs);
if (bnp)
control_notifypeer_free(bcs, bnp);
}
}
/*
* PERFORMANCE: reuse the bfd_control_msg allocated data for
* all control sockets to avoid wasting memory.
*/
TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
/*
* Test for all notifications first, then search for
* specific peers.
*/
if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0)
continue;
_control_notify_config(bcs, op, bs);
}
return 0;
}

View file

@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc,
bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx);
/* Notify and update counters. */
control_notify(bs, bs->ses_state);
ptm_bfd_notify(bs, bs->ses_state);
/* No state change. */
if (old_state == bs->ses_state)

View file

@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag)
"ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
bs_to_string(bs));
} else {
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
bfd_session_free(bs);
}
}
@ -756,20 +755,6 @@ static int bfd_ifp_destroy(struct interface *ifp)
return 0;
}
static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
vrf_id_t nvrfid;
ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid);
if (ifp == NULL)
return 0;
if_update_to_new_vrf(ifp, nvrfid);
return 0;
}
static void bfdd_sessions_enable_address(struct connected *ifc)
{
struct bfd_session_observer *bso;
@ -833,9 +818,6 @@ static zclient_handler *const bfd_handlers[] = {
*/
[ZEBRA_BFD_DEST_REPLAY] = bfdd_replay,
/* Learn about interface VRF. */
[ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update,
/* Learn about new addresses being registered. */
[ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update,
[ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update,
@ -843,7 +825,8 @@ static zclient_handler *const bfd_handlers[] = {
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
hook_register_prio(if_real, 0, bfd_ifp_create);
hook_register_prio(if_unreal, 0, bfd_ifp_destroy);
zclient = zclient_new(master, &zclient_options_default, bfd_handlers,
array_size(bfd_handlers));
assert(zclient != NULL);
@ -875,6 +858,11 @@ void bfdd_zclient_stop(void)
pc_free_all();
}
void bfdd_zclient_terminate(void)
{
zclient_free(zclient);
}
/*
* Client handling.
@ -903,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid)
return pc;
/* Allocate the client data and save it. */
pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc));
pc->pc_pid = pid;
TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
@ -921,7 +909,7 @@ static void pc_free(struct ptm_client *pc)
pcn_free(pcn);
}
XFREE(MTYPE_BFDD_CONTROL, pc);
XFREE(MTYPE_BFDD_CLIENT, pc);
}
static void pc_free_all(void)
@ -945,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
return pcn;
/* Save the client notification data. */
pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn));
TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
pcn->pcn_pc = pc;
@ -993,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn)
pcn->pcn_pc = NULL;
TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn);
}

View file

@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \
bfdd/bfdd_vty.c \
bfdd/bfdd_cli.c \
bfdd/bfd_packet.c \
bfdd/config.c \
bfdd/control.c \
bfdd/dplane.c \
bfdd/event.c \
bfdd/ptm_adapter.c \
@ -37,7 +35,6 @@ clippy_scan += \
# end
noinst_HEADERS += \
bfdd/bfdctl.h \
bfdd/bfdd_nb.h \
bfdd/bfd.h \
# end

View file

@ -10,6 +10,8 @@
#include "bgp_addpath.h"
#include "bgp_route.h"
#include "bgp_open.h"
#include "bgp_packet.h"
static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = {
{
@ -25,7 +27,14 @@ static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = {
.human_description = "Advertise bestpath per AS via addpath",
.type_json_name = "addpathTxBestpathPerAS",
.id_json_name = "addpathTxIdBestPerAS"
}
},
{
.config_name = "addpath-tx-best-selected",
.human_name = "Best-Selected",
.human_description = "Advertise best N selected paths via addpath",
.type_json_name = "addpathTxBestSelectedPaths",
.id_json_name = "addpathTxIdBestSelected"
},
};
static const struct bgp_addpath_strategy_names unknown_names = {
@ -161,6 +170,8 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, struct bgp_path_info *pi)
return true;
else
return false;
case BGP_ADDPATH_BEST_SELECTED:
return true;
case BGP_ADDPATH_MAX:
return false;
}
@ -350,23 +361,52 @@ void bgp_addpath_type_changed(struct bgp *bgp)
}
}
int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
uint8_t paths)
{
int action = CAPABILITY_ACTION_UNSET;
switch (addpath_type) {
case BGP_ADDPATH_ALL:
case BGP_ADDPATH_BEST_PER_AS:
action = CAPABILITY_ACTION_SET;
break;
case BGP_ADDPATH_BEST_SELECTED:
if (paths)
action = CAPABILITY_ACTION_SET;
else
action = CAPABILITY_ACTION_UNSET;
break;
case BGP_ADDPATH_NONE:
case BGP_ADDPATH_MAX:
action = CAPABILITY_ACTION_UNSET;
break;
}
return action;
}
/*
* Change the addpath type assigned to a peer, or peer group. In addition to
* adjusting the counts, peer sessions will be reset as needed to make the
* change take effect.
*/
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type)
enum bgp_addpath_strat addpath_type,
uint8_t paths)
{
struct bgp *bgp = peer->bgp;
enum bgp_addpath_strat old_type;
struct listnode *node, *nnode;
struct peer *tmp_peer;
struct peer_group *group;
int action = bgp_addpath_capability_action(addpath_type, paths);
if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
peer->addpath_best_selected[afi][safi] = paths;
old_type = peer->addpath_type[afi][safi];
if (addpath_type == old_type)
return;
@ -411,17 +451,19 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
tmp_peer)) {
if (tmp_peer->addpath_type[afi][safi] ==
old_type) {
bgp_addpath_set_peer_type(tmp_peer,
afi,
safi,
addpath_type);
bgp_addpath_set_peer_type(
tmp_peer, afi, safi,
addpath_type, paths);
}
}
}
} else {
peer_change_action(peer, afi, safi, peer_change_reset);
if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
peer_change_action(peer, afi, safi, peer_change_reset);
}
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action);
}
/*

View file

@ -15,6 +15,18 @@
#include "bgpd/bgp_table.h"
#include "lib/json.h"
struct bgp_addpath_capability {
uint16_t afi;
uint8_t safi;
uint8_t flags;
};
struct bgp_paths_limit_capability {
uint16_t afi;
uint8_t safi;
uint16_t paths_limit;
} __attribute__((packed));
#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
@ -50,10 +62,13 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat,
* Change the type of addpath used for a peer.
*/
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type);
enum bgp_addpath_strat addpath_type,
uint8_t paths);
void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi,
safi_t safi);
void bgp_addpath_type_changed(struct bgp *bgp);
extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type,
uint8_t paths);
#endif

View file

@ -12,6 +12,7 @@
enum bgp_addpath_strat {
BGP_ADDPATH_ALL = 0,
BGP_ADDPATH_BEST_PER_AS,
BGP_ADDPATH_BEST_SELECTED,
BGP_ADDPATH_MAX,
BGP_ADDPATH_NONE,
};

View file

@ -36,6 +36,8 @@ struct bgp_advertise_attr *bgp_advertise_attr_new(void)
void bgp_advertise_attr_free(struct bgp_advertise_attr *baa)
{
bgp_advertise_attr_fifo_fini(&baa->fifo);
XFREE(MTYPE_BGP_ADVERTISE_ATTR, baa);
}
@ -46,6 +48,9 @@ static void *bgp_advertise_attr_hash_alloc(void *p)
baa = bgp_advertise_attr_new();
baa->attr = ref->attr;
bgp_advertise_attr_fifo_init(&baa->fifo);
return baa;
}
@ -83,21 +88,13 @@ void bgp_advertise_free(struct bgp_advertise *adv)
void bgp_advertise_add(struct bgp_advertise_attr *baa,
struct bgp_advertise *adv)
{
adv->next = baa->adv;
if (baa->adv)
baa->adv->prev = adv;
baa->adv = adv;
bgp_advertise_attr_fifo_add_tail(&baa->fifo, adv);
}
void bgp_advertise_delete(struct bgp_advertise_attr *baa,
struct bgp_advertise *adv)
{
if (adv->next)
adv->next->prev = adv->prev;
if (adv->prev)
adv->prev->next = adv->next;
else
baa->adv = adv->next;
bgp_advertise_attr_fifo_del(&baa->fifo, adv);
}
struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash,
@ -166,16 +163,20 @@ bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest,
void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
uint32_t addpath_id)
uint32_t addpath_id, struct bgp_labels *labels)
{
struct bgp_adj_in *adj;
for (adj = dest->adj_in; adj; adj = adj->next) {
if (adj->peer == peer && adj->addpath_rx_id == addpath_id) {
if (adj->attr != attr) {
if (!attrhash_cmp(adj->attr, attr)) {
bgp_attr_unintern(&adj->attr);
adj->attr = bgp_attr_intern(attr);
}
if (!bgp_labels_cmp(adj->labels, labels)) {
bgp_labels_unintern(&adj->labels);
adj->labels = bgp_labels_intern(labels);
}
return;
}
}
@ -184,26 +185,31 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
adj->attr = bgp_attr_intern(attr);
adj->uptime = monotime(NULL);
adj->addpath_rx_id = addpath_id;
adj->labels = bgp_labels_intern(labels);
BGP_ADJ_IN_ADD(dest, adj);
peer->stat_pfx_adj_rib_in++;
bgp_dest_lock_node(dest);
}
void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai)
void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai)
{
bgp_attr_unintern(&bai->attr);
BGP_ADJ_IN_DEL(dest, bai);
bgp_dest_unlock_node(dest);
bgp_labels_unintern(&bai->labels);
if (bai->peer)
bai->peer->stat_pfx_adj_rib_in--;
BGP_ADJ_IN_DEL(*dest, bai);
*dest = bgp_dest_unlock_node(*dest);
peer_unlock(bai->peer); /* adj_in peer reference */
XFREE(MTYPE_BGP_ADJ_IN, bai);
}
bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer,
uint32_t addpath_id)
{
struct bgp_adj_in *adj;
struct bgp_adj_in *adj_next;
adj = dest->adj_in;
adj = (*dest)->adj_in;
if (!adj)
return false;
@ -215,33 +221,9 @@ bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
bgp_adj_in_remove(dest, adj);
adj = adj_next;
assert(*dest);
}
return true;
}
void bgp_sync_init(struct peer *peer)
{
afi_t afi;
safi_t safi;
struct bgp_synchronize *sync;
FOREACH_AFI_SAFI (afi, safi) {
sync = XCALLOC(MTYPE_BGP_SYNCHRONISE,
sizeof(struct bgp_synchronize));
bgp_adv_fifo_init(&sync->update);
bgp_adv_fifo_init(&sync->withdraw);
bgp_adv_fifo_init(&sync->withdraw_low);
peer->sync[afi][safi] = sync;
}
}
void bgp_sync_delete(struct peer *peer)
{
afi_t afi;
safi_t safi;
FOREACH_AFI_SAFI (afi, safi) {
XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
}
}

View file

@ -11,26 +11,19 @@
PREDECL_DLIST(bgp_adv_fifo);
struct update_subgroup;
struct bgp_advertise;
PREDECL_DLIST(bgp_advertise_attr_fifo);
struct bgp_advertise_attr;
/* BGP advertise attribute. */
struct bgp_advertise_attr {
/* Head of advertisement pointer. */
struct bgp_advertise *adv;
/* Reference counter. */
unsigned long refcnt;
/* Attribute pointer to be announced. */
struct attr *attr;
};
struct bgp_advertise {
/* FIFO for advertisement. */
struct bgp_adv_fifo_item fifo;
/* Link list for same attribute advertise. */
struct bgp_advertise *next;
struct bgp_advertise *prev;
/* FIFO for this item in the bgp_advertise_attr fifo */
struct bgp_advertise_attr_fifo_item item;
/* Prefix information. */
struct bgp_dest *dest;
@ -45,8 +38,21 @@ struct bgp_advertise {
struct bgp_path_info *pathi;
};
DECLARE_DLIST(bgp_advertise_attr_fifo, struct bgp_advertise, item);
DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo);
/* BGP advertise attribute. */
struct bgp_advertise_attr {
/* Head of advertisement pointer. */
struct bgp_advertise_attr_fifo_head fifo;
/* Reference counter. */
unsigned long refcnt;
/* Attribute pointer to be announced. */
struct attr *attr;
};
/* BGP adjacency out. */
struct bgp_adj_out {
/* RB Tree of adjacency entries */
@ -63,14 +69,17 @@ struct bgp_adj_out {
uint32_t addpath_tx_id;
/* Attribute hash */
uint32_t attr_hash;
/* Advertised attribute. */
struct attr *attr;
/* VPN label information */
struct bgp_labels *labels;
/* Advertisement information. */
struct bgp_advertise *adv;
/* Attribute hash */
uint32_t attr_hash;
};
RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
@ -89,6 +98,9 @@ struct bgp_adj_in {
/* Received attribute. */
struct attr *attr;
/* VPN label information */
struct bgp_labels *labels;
/* timestamp (monotime) */
time_t uptime;
@ -100,7 +112,6 @@ struct bgp_adj_in {
struct bgp_synchronize {
struct bgp_adv_fifo_head update;
struct bgp_adv_fifo_head withdraw;
struct bgp_adv_fifo_head withdraw_low;
};
/* BGP adjacency linked list. */
@ -130,13 +141,12 @@ struct bgp_synchronize {
extern bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest,
uint32_t addpath_tx_id);
extern void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer,
struct attr *attr, uint32_t addpath_id);
extern bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
struct attr *attr, uint32_t addpath_id,
struct bgp_labels *labels);
extern bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer,
uint32_t addpath_id);
extern void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai);
extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai);
extern void bgp_sync_init(struct peer *peer);
extern void bgp_sync_delete(struct peer *peer);
extern unsigned int bgp_advertise_attr_hash_key(const void *p);
extern bool bgp_advertise_attr_hash_cmp(const void *p1, const void *p2);
extern void bgp_advertise_add(struct bgp_advertise_attr *baa,

View file

@ -21,6 +21,7 @@
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_filter.h"
/* Attr. Flags and Attr. Type Code. */
#define AS_HEADER_SIZE 2
@ -76,6 +77,9 @@ static struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
/* as-path orphan exclude list */
static struct as_list_list_head as_exclude_list_orphan;
/* Callers are required to initialize the memory */
static as_t *assegment_data_new(int num)
{
@ -1015,8 +1019,6 @@ static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath,
seg = seg->next;
seg->next = asset;
}
asset->type = AS_SET;
asset->length = 1;
asset->as[0] = as;
} else {
/* Check this AS value already exists or not. */
@ -1230,6 +1232,46 @@ bool aspath_private_as_check(struct aspath *aspath)
return true;
}
/* Replace all ASN instances of the regex rule with our own ASN */
struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
struct as_list *acl_list, as_t our_asn)
{
struct aspath *new;
struct assegment *cur_seg;
struct as_list *cur_as_list;
struct as_filter *cur_as_filter;
char str_buf[ASPATH_STR_DEFAULT_LEN];
uint32_t i;
new = aspath_dup(aspath);
cur_seg = new->segments;
while (cur_seg) {
cur_as_list = acl_list;
while (cur_as_list) {
cur_as_filter = cur_as_list->head;
while (cur_as_filter) {
for (i = 0; i < cur_seg->length; i++) {
snprintfrr(str_buf,
ASPATH_STR_DEFAULT_LEN,
ASN_FORMAT(new->asnotation),
&cur_seg->as[i]);
if (!regexec(cur_as_filter->reg,
str_buf, 0, NULL, 0))
cur_seg->as[i] = our_asn;
}
cur_as_filter = cur_as_filter->next;
}
cur_as_list = cur_as_list->next;
}
cur_seg = cur_seg->next;
}
aspath_str_update(new, false);
return new;
}
/* Replace all instances of the target ASN with our own ASN */
struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn, as_t our_asn)
@ -1368,7 +1410,8 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn)
last_new_seg = new_seg;
seg = seg->next;
}
if (!aspath->refcnt)
aspath_free(aspath);
aspath_str_update(new, false);
return new;
}
@ -1518,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* Not reached */
}
/* insert aspath exclude in head of orphan exclude list*/
void as_exclude_set_orphan(struct aspath_exclude *ase)
{
ase->exclude_aspath_acl = NULL;
as_list_list_add_head(&as_exclude_list_orphan, ase);
}
void as_exclude_remove_orphan(struct aspath_exclude *ase)
{
if (as_list_list_count(&as_exclude_list_orphan))
as_list_list_del(&as_exclude_list_orphan, ase);
}
/* currently provide only one exclude, not a list */
struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name)
{
struct aspath_exclude *ase = NULL;
char *name = NULL;
frr_each (as_list_list, &as_exclude_list_orphan, ase) {
if (ase->exclude_aspath_acl_name) {
name = ase->exclude_aspath_acl_name;
if (!strcmp(name, acl_name))
break;
}
}
if (ase)
as_exclude_remove_orphan(ase);
return ase;
}
/* Iterate over AS_PATH segments and wipe all occurrences of the
* listed AS numbers. Hence some segments may lose some or even
* all data on the way, the operation is implemented as a smarter
@ -1598,6 +1673,111 @@ struct aspath *aspath_filter_exclude(struct aspath *source,
return newpath;
}
struct aspath *aspath_filter_exclude_all(struct aspath *source)
{
struct aspath *newpath;
newpath = aspath_new(source->asnotation);
aspath_str_update(newpath, false);
/* We are happy returning even an empty AS_PATH, because the
* administrator
* might expect this very behaviour. There's a mean to avoid this, if
* necessary,
* by having a match rule against certain AS_PATH regexps in the
* route-map index.
*/
aspath_free(source);
return newpath;
}
struct aspath *aspath_filter_exclude_acl(struct aspath *source,
struct as_list *acl_list)
{
struct assegment *cur_seg, *new_seg, *prev_seg, *next_seg;
struct as_list *cur_as_list;
struct as_filter *cur_as_filter;
char str_buf[ASPATH_STR_DEFAULT_LEN];
uint32_t nb_as_del;
uint32_t i, j;
cur_seg = source->segments;
prev_seg = NULL;
/* segments from source aspath */
while (cur_seg) {
next_seg = cur_seg->next;
cur_as_list = acl_list;
nb_as_del = 0;
/* aspath filter list from acl_list */
while (cur_as_list) {
cur_as_filter = cur_as_list->head;
while (cur_as_filter) {
for (i = 0; i < cur_seg->length; i++) {
if (cur_seg->as[i] == 0)
continue;
snprintfrr(str_buf,
ASPATH_STR_DEFAULT_LEN,
ASN_FORMAT(source->asnotation),
&cur_seg->as[i]);
if (!regexec(cur_as_filter->reg,
str_buf, 0, NULL, 0)) {
cur_seg->as[i] = 0;
nb_as_del++;
}
}
cur_as_filter = cur_as_filter->next;
}
cur_as_list = cur_as_list->next;
}
/* full segment is excluded remove it */
if (nb_as_del == cur_seg->length) {
if (cur_seg == source->segments)
/* first segment */
source->segments = cur_seg->next;
else if (prev_seg)
prev_seg->next = cur_seg->next;
assegment_free(cur_seg);
}
/* change in segment size -> new allocation and replace segment*/
else if (nb_as_del) {
new_seg = assegment_new(cur_seg->type,
cur_seg->length - nb_as_del);
j = 0;
for (i = 0; i < cur_seg->length; i++) {
if (cur_seg->as[i] == 0)
continue;
new_seg->as[j] = cur_seg->as[i];
j++;
}
new_seg->next = next_seg;
if (cur_seg == source->segments)
/* first segment */
source->segments = new_seg;
else if (prev_seg)
prev_seg->next = new_seg;
assegment_free(cur_seg);
prev_seg = new_seg;
} else
prev_seg = cur_seg;
cur_seg = next_seg;
}
aspath_str_update(source, false);
/* We are happy returning even an empty AS_PATH, because the
* administrator
* might expect this very behaviour. There's a mean to avoid this, if
* necessary,
* by having a match rule against certain AS_PATH regexps in the
* route-map index.
*/
return source;
}
/* Add specified AS to the leftmost of aspath. */
static struct aspath *aspath_add_asns(struct aspath *aspath, as_t asno,
uint8_t type, unsigned num)
@ -1748,7 +1928,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
"[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls across 2/4 ASN boundary somewhere, broken..");
hops = seg->length;
}
/* fallthru */
fallthrough;
case AS_SEQUENCE:
cpasns = MIN(seg->length, hops);
hops -= seg->length;
@ -2091,20 +2271,32 @@ void aspath_init(void)
{
ashash = hash_create_size(32768, aspath_key_make, aspath_cmp,
"BGP AS Path");
as_list_list_init(&as_exclude_list_orphan);
}
void aspath_finish(void)
{
struct aspath_exclude *ase;
hash_clean_and_free(&ashash, (void (*)(void *))aspath_free);
if (snmp_stream)
stream_free(snmp_stream);
while ((ase = as_list_list_pop(&as_exclude_list_orphan))) {
aspath_free(ase->aspath);
if (ase->exclude_aspath_acl_name)
XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
}
as_list_list_fini(&as_exclude_list_orphan);
}
/* return and as path value */
const char *aspath_print(struct aspath *as)
{
return (as ? as->str : NULL);
return as ? as->str : "(null)";
}
/* Printing functions */

View file

@ -8,6 +8,8 @@
#include "lib/json.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_filter.h"
#include <typesafe.h>
/* AS path segment type. */
#define AS_SET 1
@ -64,6 +66,17 @@ struct aspath {
#define ASPATH_STR_DEFAULT_LEN 32
/* `set as-path exclude ASn' */
struct aspath_exclude {
struct as_list_list_item exclude_list;
struct aspath *aspath;
bool exclude_all;
char *exclude_aspath_acl_name;
struct as_list *exclude_aspath_acl;
};
DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list);
/* Prototypes. */
extern void aspath_init(void);
extern void aspath_finish(void);
@ -74,8 +87,14 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length,
extern struct aspath *aspath_dup(struct aspath *aspath);
extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2);
extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2);
extern void as_exclude_set_orphan(struct aspath_exclude *ase);
extern void as_exclude_remove_orphan(struct aspath_exclude *ase);
extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name);
extern struct aspath *aspath_filter_exclude(struct aspath *source,
struct aspath *exclude_list);
extern struct aspath *aspath_filter_exclude_all(struct aspath *source);
extern struct aspath *aspath_filter_exclude_acl(struct aspath *source,
struct as_list *acl_list);
extern struct aspath *aspath_add_seq_n(struct aspath *aspath, as_t asno,
unsigned num);
extern struct aspath *aspath_add_seq(struct aspath *aspath, as_t asno);
@ -103,6 +122,9 @@ extern unsigned int aspath_get_last_as(struct aspath *aspath);
extern int aspath_loop_check(struct aspath *aspath, as_t asno);
extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno);
extern bool aspath_private_as_check(struct aspath *aspath);
extern struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
struct as_list *acl_list,
as_t our_asn);
extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
as_t our_asn);

File diff suppressed because it is too large Load diff

View file

@ -155,16 +155,61 @@ struct attr {
uint32_t med;
uint32_t local_pref;
ifindex_t nh_ifindex;
uint8_t nh_flags;
#define BGP_ATTR_NH_VALID 0x01
#define BGP_ATTR_NH_IF_OPERSTATE 0x02
#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */
/* Path origin attribute */
uint8_t origin;
/* ES info */
uint8_t es_flags;
/* Path is not "locally-active" on the advertising VTEP. This is
* translated into an ARP-ND ECOM.
*/
#define ATTR_ES_PROXY_ADVERT (1 << 0)
/* Destination ES is present locally. This flag is set on local
* paths and sync paths
*/
#define ATTR_ES_IS_LOCAL (1 << 1)
/* There are one or more non-best paths from ES peers. Note that
* this flag is only set on the local MAC-IP paths in the VNI
* route table (not set in the global routing table). And only
* non-proxy advertisements from an ES peer can result in this
* flag being set.
*/
#define ATTR_ES_PEER_ACTIVE (1 << 2)
/* There are one or more non-best proxy paths from ES peers */
#define ATTR_ES_PEER_PROXY (1 << 3)
/* An ES peer has router bit set - only applicable if
* ATTR_ES_PEER_ACTIVE is set
*/
#define ATTR_ES_PEER_ROUTER (1 << 4)
/* These two flags are only set on L3 routes installed in a
* VRF as a result of EVPN MAC-IP route
* XXX - while splitting up per-family attrs these need to be
* classified as non-EVPN
*/
#define ATTR_ES_L3_NHG_USE (1 << 5)
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
/* Distance as applied by Route map */
uint8_t distance;
/* EVPN DF preference for DF election on local ESs */
uint8_t df_alg;
uint16_t df_pref;
/* PMSI tunnel type (RFC 6514). */
enum pta_type pmsi_tnl_type;
/* has the route-map changed any attribute?
Used on the peer outbound side. */
uint32_t rmap_change_flags;
uint16_t rmap_change_flags;
/* Multi-Protocol Nexthop, AFI IPv6 */
struct in6_addr mp_nexthop_global;
@ -173,6 +218,9 @@ struct attr {
/* ifIndex corresponding to mp_nexthop_local. */
ifindex_t nh_lla_ifindex;
/* MPLS label */
mpls_label_t label;
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
@ -205,50 +253,12 @@ struct attr {
/* MP Nexthop length */
uint8_t mp_nexthop_len;
/* MP Nexthop preference */
uint8_t mp_nexthop_prefer_global;
/* Static MAC for EVPN */
uint8_t sticky;
/* Flag for default gateway extended community in EVPN */
uint8_t default_gw;
/* NA router flag (R-bit) support in EVPN */
uint8_t router_flag;
/* ES info */
uint8_t es_flags;
/* Path is not "locally-active" on the advertising VTEP. This is
* translated into an ARP-ND ECOM.
*/
#define ATTR_ES_PROXY_ADVERT (1 << 0)
/* Destination ES is present locally. This flag is set on local
* paths and sync paths
*/
#define ATTR_ES_IS_LOCAL (1 << 1)
/* There are one or more non-best paths from ES peers. Note that
* this flag is only set on the local MAC-IP paths in the VNI
* route table (not set in the global routing table). And only
* non-proxy advertisements from an ES peer can result in this
* flag being set.
*/
#define ATTR_ES_PEER_ACTIVE (1 << 2)
/* There are one or more non-best proxy paths from ES peers */
#define ATTR_ES_PEER_PROXY (1 << 3)
/* An ES peer has router bit set - only applicable if
* ATTR_ES_PEER_ACTIVE is set
*/
#define ATTR_ES_PEER_ROUTER (1 << 4)
/* These two flags are only set on L3 routes installed in a
* VRF as a result of EVPN MAC-IP route
* XXX - while splitting up per-family attrs these need to be
* classified as non-EVPN
*/
#define ATTR_ES_L3_NHG_USE (1 << 5)
#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
/* EVPN flags */
uint8_t evpn_flags;
#define ATTR_EVPN_FLAG_STICKY (1 << 0)
#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1)
/* NA router flag (R-bit) support in EVPN */
#define ATTR_EVPN_FLAG_ROUTER (1 << 2)
/* route tag */
route_tag_t tag;
@ -256,23 +266,19 @@ struct attr {
/* Label index */
uint32_t label_index;
/* MPLS label */
mpls_label_t label;
/* SRv6 VPN SID */
struct bgp_attr_srv6_vpn *srv6_vpn;
/* SRv6 L3VPN SID */
struct bgp_attr_srv6_l3vpn *srv6_l3vpn;
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
#ifdef ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
/* EVPN */
struct bgp_route_evpn evpn_overlay;
struct bgp_route_evpn *evpn_overlay;
/* EVPN MAC Mobility sequence number, if any. */
uint32_t mm_seqnum;
@ -287,14 +293,13 @@ struct attr {
/* EVPN local router-mac */
struct ethaddr rmac;
/* Distance as applied by Route map */
uint8_t distance;
uint8_t encap_tunneltype;
/* rmap set table */
uint32_t rmap_table_id;
/* Link bandwidth value, if any. */
uint32_t link_bw;
uint64_t link_bw;
/* EVPN ES */
esi_t esi;
@ -302,10 +307,6 @@ struct attr {
/* SR-TE Color */
uint32_t srte_color;
/* EVPN DF preference and algorithm for DF election on local ESs */
uint16_t df_pref;
uint8_t df_alg;
/* Nexthop type */
enum nexthop_types_t nh_type;
@ -352,7 +353,7 @@ struct transit {
__builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0)
#define BGP_CLUSTER_LIST_LENGTH(attr) \
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
(CHECK_FLAG((attr)->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
? bgp_attr_get_cluster((attr))->length \
: 0)
@ -364,7 +365,7 @@ enum bgp_attr_parse_ret {
/* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR
*/
BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3,
BGP_ATTR_PARSE_EOR = -4,
BGP_ATTR_PARSE_MISSING_MANDATORY = -4,
};
struct bpacket_attr_vec_arr;
@ -390,7 +391,7 @@ extern bgp_size_t bgp_packet_attribute(
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
safi_t safi, struct peer *from, struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels, bool addpath_capable,
mpls_label_t *label, uint8_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct bgp_path_info *bpi);
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
const struct prefix *p);
@ -448,7 +449,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
const struct prefix *p,
const struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels,
mpls_label_t *label, uint8_t num_labels,
bool addpath_capable,
uint32_t addpath_tx_id, struct attr *);
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
@ -459,13 +460,15 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
safi_t safi);
extern void bgp_packet_mpunreach_prefix(
struct stream *s, const struct prefix *p, afi_t afi, safi_t safi,
const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels,
const struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels,
bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr);
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
extern enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
struct attr *attr);
extern uint32_t bgp_attr_get_color(struct attr *attr);
static inline bool bgp_rmap_nhop_changed(uint32_t out_rmap_flags,
uint32_t in_rmap_flags)
{
@ -592,7 +595,7 @@ static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp)
attr->aigp_metric = aigp;
if (aigp)
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP);
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP));
}
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
@ -604,18 +607,23 @@ static inline void bgp_attr_set_cluster(struct attr *attr,
struct cluster_list *cl)
{
attr->cluster1 = cl;
if (cl)
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
else
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
}
static inline const struct bgp_route_evpn *
static inline struct bgp_route_evpn *
bgp_attr_get_evpn_overlay(const struct attr *attr)
{
return &attr->evpn_overlay;
return attr->evpn_overlay;
}
static inline void bgp_attr_set_evpn_overlay(struct attr *attr,
struct bgp_route_evpn *eo)
struct bgp_route_evpn *bre)
{
memcpy(&attr->evpn_overlay, eo, sizeof(struct bgp_route_evpn));
attr->evpn_overlay = bre;
}
static inline struct bgp_attr_encap_subtlv *
@ -637,4 +645,7 @@ bgp_attr_set_vnc_subtlvs(struct attr *attr,
#endif
}
extern bool route_matches_soo(struct bgp_path_info *pi, struct ecommunity *soo);
extern void evpn_overlay_free(struct bgp_route_evpn *bre);
#endif /* _QUAGGA_BGP_ATTR_H */

View file

@ -24,6 +24,13 @@
bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
const struct bgp_route_evpn *e2)
{
if (!e1 && e2)
return false;
if (!e2 && e1)
return false;
if (!e1 && !e2)
return true;
return (e1->type == e2->type &&
!memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
!ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip)));
@ -115,14 +122,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
/*
* return true if attr contains default gw extended community
*/
uint8_t bgp_attr_default_gw(struct attr *attr)
void bgp_attr_default_gw(struct attr *attr)
{
struct ecommunity *ecom;
uint32_t i;
ecom = bgp_attr_get_ecommunity(attr);
if (!ecom || !ecom->size)
return 0;
return;
/* If there is a default gw extendd community return true otherwise
* return 0 */
@ -136,10 +143,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
if ((type == ECOMMUNITY_ENCODE_OPAQUE
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
return 1;
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
}
return 0;
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW);
}
/*
@ -183,7 +189,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
* Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0.
*/
uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr)
{
struct ecommunity *ecom;
uint32_t i;
@ -212,10 +218,11 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
continue;
flags = *pnt++;
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
*sticky = 1;
if (CHECK_FLAG(flags,
ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
else
*sticky = 0;
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
pnt++;
pnt = ptr_get_be32(pnt, &seq_num);
@ -229,8 +236,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
/*
* return true if attr contains router flag extended community
*/
void bgp_attr_evpn_na_flag(struct attr *attr,
uint8_t *router_flag, bool *proxy)
void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy)
{
struct ecommunity *ecom;
uint32_t i;
@ -253,10 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
val = *pnt++;
if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
*router_flag = 1;
if (CHECK_FLAG(val,
ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG))
SET_FLAG(attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER);
if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
if (CHECK_FLAG(val, ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG))
*proxy = true;
break;

View file

@ -23,6 +23,7 @@ enum overlay_index_type {
* MAC overlay index is stored in the RMAC attribute.
*/
struct bgp_route_evpn {
unsigned long refcnt;
enum overlay_index_type type;
esi_t eth_s_id;
struct ipaddr gw_ip;
@ -36,12 +37,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr,
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst);
extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
uint8_t *sticky);
extern uint8_t bgp_attr_default_gw(struct attr *attr);
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr);
extern void bgp_attr_default_gw(struct attr *attr);
extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag,
bool *proxy);
extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy);
extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg);

View file

@ -56,18 +56,18 @@ static void bfd_session_status_update(struct bfd_session_params *bsp,
peer->last_reset = PEER_DOWN_BFD_DOWN;
/* rfc9384 */
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_BFD_DOWN);
BGP_EVENT_ADD(peer, BGP_Stop);
BGP_EVENT_ADD(peer->connection, BGP_Stop);
}
if (bss->state == BSS_UP && bss->previous_state != BSS_UP
&& !peer_established(peer)) {
if (bss->state == BSS_UP && bss->previous_state != BSS_UP &&
!peer_established(peer->connection)) {
if (!BGP_PEER_START_SUPPRESSED(peer)) {
bgp_fsm_nht_update(peer, true);
BGP_EVENT_ADD(peer, BGP_Start);
bgp_fsm_nht_update(peer->connection, peer, true);
BGP_EVENT_ADD(peer->connection, BGP_Start);
}
}
}
@ -163,36 +163,35 @@ void bgp_peer_bfd_update_source(struct peer *p)
/* Update peer's source/destination addresses. */
bfd_sess_addresses(session, &family, &src.v6, &dst.v6);
if (family == AF_INET) {
if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr)
|| p->su.sin.sin_addr.s_addr != dst.v4.s_addr) {
if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr) ||
p->connection->su.sin.sin_addr.s_addr != dst.v4.s_addr) {
if (BGP_DEBUG(bfd, BFD_LIB))
zlog_debug(
"%s: address [%pI4->%pI4] to [%pI4->%pI4]",
__func__, &src.v4, &dst.v4,
source ? &source->sin.sin_addr
: &src.v4,
&p->su.sin.sin_addr);
zlog_debug("%s: address [%pI4->%pI4] to [%pI4->%pI4]",
__func__, &src.v4, &dst.v4,
source ? &source->sin.sin_addr
: &src.v4,
&p->connection->su.sin.sin_addr);
bfd_sess_set_ipv4_addrs(
session, source ? &source->sin.sin_addr : NULL,
&p->su.sin.sin_addr);
bfd_sess_set_ipv4_addrs(session,
source ? &source->sin.sin_addr
: NULL,
&p->connection->su.sin.sin_addr);
changed = true;
}
} else {
if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6)))
|| memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) {
if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6))) ||
memcmp(&p->connection->su.sin6, &dst.v6, sizeof(dst.v6))) {
if (BGP_DEBUG(bfd, BFD_LIB))
zlog_debug(
"%s: address [%pI6->%pI6] to [%pI6->%pI6]",
__func__, &src.v6, &dst.v6,
source ? &source->sin6.sin6_addr
: &src.v6,
&p->su.sin6.sin6_addr);
zlog_debug("%s: address [%pI6->%pI6] to [%pI6->%pI6]",
__func__, &src.v6, &dst.v6,
source ? &source->sin6.sin6_addr
: &src.v6,
&p->connection->su.sin6.sin6_addr);
bfd_sess_set_ipv6_addrs(session,
source ? &source->sin6.sin6_addr
: NULL,
&p->su.sin6.sin6_addr);
&p->connection->su.sin6.sin6_addr);
changed = true;
}
}
@ -284,16 +283,17 @@ void bgp_peer_configure_bfd(struct peer *p, bool manual)
bgp_peer_bfd_reset(p);
/* Configure session with basic BGP peer data. */
if (p->su.sa.sa_family == AF_INET)
if (p->connection->su.sa.sa_family == AF_INET)
bfd_sess_set_ipv4_addrs(p->bfd_config->session,
p->su_local ? &p->su_local->sin.sin_addr
: NULL,
&p->su.sin.sin_addr);
&p->connection->su.sin.sin_addr);
else
bfd_sess_set_ipv6_addrs(
p->bfd_config->session,
p->su_local ? &p->su_local->sin6.sin6_addr : NULL,
&p->su.sin6.sin6_addr);
bfd_sess_set_ipv6_addrs(p->bfd_config->session,
p->su_local
? &p->su_local->sin6.sin6_addr
: NULL,
&p->connection->su.sin6.sin6_addr);
bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id);
bfd_sess_set_hop_count(p->bfd_config->session,
@ -597,6 +597,9 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
if (!peer->bfd_config)
return CMD_SUCCESS;
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
bgp_group_configure_bfd(peer);
else

File diff suppressed because it is too large Load diff

View file

@ -124,6 +124,7 @@ struct bmp {
* ahead we need to make sure that refcount is decremented. Also, on
* disconnects we need to walk the queue and drop our reference.
*/
struct bmp_queue_entry *locrib_queuepos;
struct bmp_queue_entry *queuepos;
struct bmp_mirrorq *mirrorpos;
bool mirror_lost;
@ -215,12 +216,14 @@ struct bmp_targets {
int stat_msec;
/* only supporting:
* - IPv4 / unicast & multicast
* - IPv6 / unicast & multicast
* - IPv4 / unicast & multicast & VPN
* - IPv6 / unicast & multicast & VPN
* - L2VPN / EVPN
*/
#define BMP_MON_PREPOLICY (1 << 0)
#define BMP_MON_POSTPOLICY (1 << 1)
#define BMP_MON_LOC_RIB (1 << 2)
uint8_t afimon[AFI_MAX][SAFI_MAX];
bool mirror;
@ -232,8 +235,13 @@ struct bmp_targets {
struct bmp_qhash_head updhash;
struct bmp_qlist_head updlist;
struct bmp_qhash_head locupdhash;
struct bmp_qlist_head locupdlist;
uint64_t cnt_accept, cnt_aclrefused;
bool stats_send_experimental;
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bmp_targets);

View file

@ -4,6 +4,7 @@
*/
#include <zebra.h>
#include <fcntl.h>
#include "zebra.h"
#include "stream.h"
@ -68,7 +69,7 @@ static void attr_parse(struct stream *s, uint16_t len)
flag = stream_getc(s);
type = stream_getc(s);
if (flag & BGP_ATTR_FLAG_EXTLEN)
if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
length = stream_getw(s);
else
length = stream_getc(s);
@ -120,6 +121,7 @@ int main(int argc, char **argv)
struct in_addr dip;
uint16_t viewno, seq_num;
struct prefix_ipv4 p;
char tbuf[32];
s = stream_new(10000);
@ -155,7 +157,7 @@ int main(int argc, char **argv)
subtype = stream_getw(s);
len = stream_getl(s);
printf("TIME: %s", ctime(&now));
printf("TIME: %s", ctime_r(&now, tbuf));
/* printf ("TYPE: %d/%d\n", type, subtype); */
@ -239,7 +241,8 @@ int main(int argc, char **argv)
source_as = stream_getw(s);
printf("FROM: %pI4 AS%d\n", &peer, source_as);
printf("ORIGINATED: %s", ctime(&originated));
printf("ORIGINATED: %s", ctime_r(&originated,
tbuf));
attrlen = stream_getw(s);
printf("ATTRLEN: %d\n", attrlen);

View file

@ -128,6 +128,7 @@ static void community_entry_free(struct community_entry *entry)
XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
if (entry->reg)
bgp_regex_free(entry->reg);
break;
default:
break;
}
@ -449,13 +450,6 @@ static char *community_str_get(struct community *com, int i)
comval = ntohl(comval);
switch (comval) {
#if CONFDATE > 20230801
CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
#endif
case COMMUNITY_INTERNET:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet");
zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown");
break;
@ -502,8 +496,8 @@ CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
break;
default:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
as = CHECK_FLAG((comval >> 16), 0xFFFF);
val = CHECK_FLAG(comval, 0xFFFF);
snprintf(str, strlen(str), "%u:%d", as, val);
break;
}
@ -659,13 +653,7 @@ bool community_list_match(struct community *com, struct community_list *list)
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
return entry->direct == COMMUNITY_PERMIT;
if (entry->style == COMMUNITY_LIST_STANDARD) {
if (community_include(entry->u.com, COMMUNITY_INTERNET))
return entry->direct == COMMUNITY_PERMIT;
if (community_match(com, entry->u.com))
return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == COMMUNITY_LIST_EXPANDED) {
@ -681,9 +669,6 @@ bool lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
return entry->direct == COMMUNITY_PERMIT;
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
if (lcommunity_match(lcom, entry->u.lcom))
return entry->direct == COMMUNITY_PERMIT;
@ -705,9 +690,6 @@ bool lcommunity_list_exact_match(struct lcommunity *lcom,
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
return entry->direct == COMMUNITY_PERMIT;
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
if (lcommunity_cmp(lcom, entry->u.lcom))
return entry->direct == COMMUNITY_PERMIT;
@ -724,9 +706,6 @@ bool ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
return entry->direct == COMMUNITY_PERMIT;
if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
if (ecommunity_match(ecom, entry->u.ecom))
return entry->direct == COMMUNITY_PERMIT;
@ -746,13 +725,7 @@ bool community_list_exact_match(struct community *com,
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
return entry->direct == COMMUNITY_PERMIT;
if (entry->style == COMMUNITY_LIST_STANDARD) {
if (community_include(entry->u.com, COMMUNITY_INTERNET))
return entry->direct == COMMUNITY_PERMIT;
if (community_cmp(com, entry->u.com))
return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == COMMUNITY_LIST_EXPANDED) {
@ -763,6 +736,27 @@ bool community_list_exact_match(struct community *com,
return false;
}
bool community_list_any_match(struct community *com, struct community_list *list)
{
struct community_entry *entry;
uint32_t val;
int i;
for (i = 0; i < com->size; i++) {
val = community_val_get(com, i);
for (entry = list->head; entry; entry = entry->next) {
if (entry->style == COMMUNITY_LIST_STANDARD &&
community_include(entry->u.com, val))
return entry->direct == COMMUNITY_PERMIT;
if ((entry->style == COMMUNITY_LIST_EXPANDED) &&
community_regexp_include(entry->reg, com, i))
return entry->direct == COMMUNITY_PERMIT;
}
}
return false;
}
/* Delete all permitted communities in the list from com. */
struct community *community_list_match_delete(struct community *com,
struct community_list *list)
@ -781,28 +775,15 @@ struct community *community_list_match_delete(struct community *com,
val = community_val_get(com, i);
for (entry = list->head; entry; entry = entry->next) {
if (entry->any) {
if ((entry->style == COMMUNITY_LIST_STANDARD) &&
community_include(entry->u.com, val)) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == COMMUNITY_LIST_STANDARD)
&& (community_include(entry->u.com,
COMMUNITY_INTERNET)
|| community_include(entry->u.com, val))) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == COMMUNITY_LIST_EXPANDED)
&& community_regexp_include(entry->reg, com,
i)) {
} else if ((entry->style == COMMUNITY_LIST_EXPANDED) &&
community_regexp_include(entry->reg, com, i)) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
@ -836,12 +817,6 @@ static bool community_list_dup_check(struct community_list *list,
if (entry->direct != new->direct)
continue;
if (entry->any != new->any)
continue;
if (entry->any)
return true;
switch (entry->style) {
case COMMUNITY_LIST_STANDARD:
if (community_cmp(entry->u.com, new->u.com))
@ -899,20 +874,17 @@ int community_list_set(struct community_list_handler *ch, const char *name,
}
}
if (str) {
if (style == COMMUNITY_LIST_STANDARD)
com = community_str2com(str);
else
regex = bgp_regcomp(str);
if (style == COMMUNITY_LIST_STANDARD)
com = community_str2com(str);
else
regex = bgp_regcomp(str);
if (!com && !regex)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
}
if (!com && !regex)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
entry = community_entry_new();
entry->direct = direct;
entry->style = style;
entry->any = (str ? false : true);
entry->u.com = com;
entry->reg = regex;
entry->seq = seqnum;
@ -932,9 +904,9 @@ int community_list_set(struct community_list_handler *ch, const char *name,
}
/* Unset community-list */
int community_list_unset(struct community_list_handler *ch, const char *name,
const char *str, const char *seq, int direct,
int style)
void community_list_unset(struct community_list_handler *ch, const char *name,
const char *str, const char *seq, int direct,
int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@ -944,14 +916,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup community list. */
list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
return;
}
if (style == COMMUNITY_LIST_STANDARD)
@ -964,12 +936,32 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
entry = community_list_entry_lookup(list, str, direct);
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
}
return 0;
bool lcommunity_list_any_match(struct lcommunity *lcom,
struct community_list *list)
{
struct community_entry *entry;
uint8_t *ptr;
int i;
for (i = 0; i < lcom->size; i++) {
ptr = lcom->val + (i * LCOMMUNITY_SIZE);
for (entry = list->head; entry; entry = entry->next) {
if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) &&
lcommunity_include(entry->u.lcom, ptr))
return entry->direct == COMMUNITY_PERMIT;
if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED) &&
lcommunity_regexp_include(entry->reg, lcom, i))
return entry->direct == COMMUNITY_PERMIT;
}
}
return false;
}
/* Delete all permitted large communities in the list from com. */
@ -989,7 +981,8 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
for (i = 0; i < lcom->size; i++) {
ptr = lcom->val + (i * LCOMMUNITY_SIZE);
for (entry = list->head; entry; entry = entry->next) {
if (entry->any) {
if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) &&
lcommunity_include(entry->u.lcom, ptr)) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
@ -997,18 +990,10 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
break;
}
else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
&& lcommunity_include(entry->u.lcom, ptr)) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
&& lcommunity_regexp_include(entry->reg, lcom,
i)) {
else if ((entry->style ==
LARGE_COMMUNITY_LIST_EXPANDED) &&
lcommunity_regexp_include(entry->reg, lcom,
i)) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
@ -1027,6 +1012,44 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
return lcom;
}
/* Delete all permitted extended communities in the list from ecom.*/
struct ecommunity *ecommunity_list_match_delete(struct ecommunity *ecom,
struct community_list *list)
{
struct community_entry *entry;
uint32_t com_index_to_delete[ecom->size];
uint8_t *ptr;
uint32_t delete_index = 0;
uint32_t i;
struct ecommunity local_ecom = {.size = 1};
struct ecommunity_val local_eval = {0};
for (i = 0; i < ecom->size; i++) {
local_ecom.val = ecom->val + (i * ECOMMUNITY_SIZE);
for (entry = list->head; entry; entry = entry->next) {
if (((entry->style == EXTCOMMUNITY_LIST_STANDARD) &&
ecommunity_include(entry->u.ecom, &local_ecom)) ||
((entry->style == EXTCOMMUNITY_LIST_EXPANDED) &&
ecommunity_regexp_match(ecom, entry->reg))) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
}
}
/* Delete all of the extended communities we flagged for deletion */
for (i = delete_index; i > 0; i--) {
ptr = ecom->val + (com_index_to_delete[i-1] * ECOMMUNITY_SIZE);
memcpy(&local_eval.val, ptr, sizeof(local_eval.val));
ecommunity_del_val(ecom, &local_eval);
}
return ecom;
}
/* Helper to check if every octet do not exceed UINT_MAX */
bool lcommunity_list_valid(const char *community, int style)
{
@ -1127,7 +1150,6 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
entry = community_entry_new();
entry->direct = direct;
entry->style = style;
entry->any = (str ? false : true);
entry->u.lcom = lcom;
entry->reg = regex;
entry->seq = seqnum;
@ -1148,9 +1170,9 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list. When str is NULL, delete all of
community-list entry belongs to the specified name. */
int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, const char *seq, int direct,
int style)
void lcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, const char *seq, int direct,
int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@ -1161,14 +1183,14 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup community list. */
list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
return 0;
return;
}
if (style == LARGE_COMMUNITY_LIST_STANDARD)
@ -1177,7 +1199,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
regex = bgp_regcomp(str);
if (!lcom && !regex)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
return;
if (lcom)
entry = community_list_entry_lookup(list, lcom, direct);
@ -1190,12 +1212,10 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
bgp_regex_free(regex);
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
return 0;
}
/* Set extcommunity-list. */
@ -1248,7 +1268,6 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
entry = community_entry_new();
entry->direct = direct;
entry->style = style;
entry->any = false;
if (ecom)
entry->config = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
@ -1276,9 +1295,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
* When str is NULL, delete all extcommunity-list entries belonging to the
* specified name.
*/
int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, const char *seq, int direct,
int style)
void extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str, const char *seq,
int direct, int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@ -1288,14 +1307,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup extcommunity list. */
list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this extcommunity-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
return;
}
if (style == EXTCOMMUNITY_LIST_STANDARD)
@ -1308,12 +1327,10 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
entry = community_list_entry_lookup(list, str, direct);
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
/* Initializa community-list. Return community-list handler. */

View file

@ -65,9 +65,6 @@ struct community_entry {
/* Standard or expanded. */
uint8_t style;
/* Any match. */
bool any;
/* Sequence number. */
int64_t seq;
@ -112,11 +109,9 @@ struct community_list_handler {
};
/* Error code of community-list. */
#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1
#define COMMUNITY_LIST_ERR_MALFORMED_VAL -2
#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3
#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4
#define COMMUNITY_LIST_ERR_MALFORMED_VAL -1
#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -2
#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -3
/* Handler. */
extern struct community_list_handler *bgp_clist;
@ -127,22 +122,22 @@ extern void community_list_terminate(struct community_list_handler *ch);
extern int community_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern int community_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern void community_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern int extcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern int extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern void extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern int lcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern bool lcommunity_list_valid(const char *community, int style);
extern int lcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern void lcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern struct community_list_master *
community_list_master_lookup(struct community_list_handler *ch, int master);
@ -161,11 +156,18 @@ extern bool community_list_exact_match(struct community *com,
struct community_list *list);
extern bool lcommunity_list_exact_match(struct lcommunity *lcom,
struct community_list *list);
extern bool community_list_any_match(struct community *com,
struct community_list *list);
extern struct community *
community_list_match_delete(struct community *com, struct community_list *list);
extern bool lcommunity_list_any_match(struct lcommunity *lcom,
struct community_list *list);
extern struct lcommunity *
lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list);
extern struct ecommunity *
ecommunity_list_match_delete(struct ecommunity *ecom,
struct community_list *list);
static inline uint32_t bgp_clist_hash_key(char *name)
{

View file

@ -228,13 +228,6 @@ static void set_community_string(struct community *com, bool make_json,
comval = ntohl(comval);
switch (comval) {
#if CONFDATE > 20230801
CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
#endif
case COMMUNITY_INTERNET:
len += strlen(" internet");
zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
len += strlen(" graceful-shutdown");
break;
@ -298,19 +291,6 @@ CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
strlcat(str, " ", len);
switch (comval) {
#if CONFDATE > 20230801
CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
#endif
case COMMUNITY_INTERNET:
strlcat(str, "internet", len);
if (make_json) {
json_string =
json_object_new_string("internet");
json_object_array_add(json_community_list,
json_string);
}
zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
strlcat(str, "graceful-shutdown", len);
if (make_json) {
@ -436,13 +416,12 @@ CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
}
break;
default:
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
as = CHECK_FLAG((comval >> 16), 0xFFFF);
val = CHECK_FLAG(comval, 0xFFFF);
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
const char *com2alias =
translate_alias ? bgp_community2alias(buf)
: buf;
translate_alias ? bgp_community2alias(buf) : buf;
strlcat(str, com2alias, len);
if (make_json) {
@ -680,16 +659,6 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
/* Well known community string check. */
if (isalpha((unsigned char)*p)) {
#if CONFDATE > 20230801
CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
#endif
if (strncmp(p, "internet", strlen("internet")) == 0) {
*val = COMMUNITY_INTERNET;
*token = community_token_no_export;
p += strlen("internet");
zlog_warn("`internet` community is deprecated");
return p;
}
if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown"))
== 0) {
*val = COMMUNITY_GSHUT;

View file

@ -30,10 +30,6 @@ struct community {
};
/* Well-known communities value. */
#if CONFDATE > 20230801
CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
#endif
#define COMMUNITY_INTERNET 0x0
#define COMMUNITY_GSHUT 0xFFFF0000
#define COMMUNITY_ACCEPT_OWN 0xFFFF0001
#define COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 0xFFFF0002

View file

@ -90,6 +90,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
dest_p = bgp_dest_get_prefix(dest);
assert(dest_p);
@ -121,8 +122,9 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
if (update_type == UPDATE_TYPE_ADVERTISE &&
subgroup_announce_check(dest, pi, subgrp, dest_p,
&attr, &advmap_attr)) {
bgp_adj_out_set_subgroup(dest, subgrp, &attr,
pi);
if (!bgp_adj_out_set_subgroup(dest, subgrp,
&attr, pi))
bgp_attr_flush(&attr);
} else {
/* If default originate is enabled for
* the peer, do not send explicit
@ -140,8 +142,9 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
bgp_addpath_id_for_peer(
peer, afi, safi,
&pi->tx_addpath));
bgp_attr_flush(&advmap_attr);
}
bgp_attr_flush(&advmap_attr);
}
}
UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
@ -194,7 +197,7 @@ static void bgp_conditional_adv_timer(struct event *t)
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
if (!peer_established(peer))
if (!peer_established(peer->connection))
continue;
FOREACH_AFI_SAFI (afi, safi) {

View file

@ -22,19 +22,76 @@
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
/* Global variable to access damping configuration */
static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info)
{
assert(info);
SLIST_INSERT_HEAD(list, info, entry);
}
/* Utility macro to add and delete BGP dampening information to no
used list. */
#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info)
{
assert(info);
SLIST_REMOVE(list, info, bgp_damp_info, entry);
}
static void bgp_reuselist_switch(struct reuselist *source,
struct bgp_damp_info *info,
struct reuselist *target)
{
assert(source && target && info);
SLIST_REMOVE(source, info, bgp_damp_info, entry);
SLIST_INSERT_HEAD(target, info, entry);
}
static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi,
struct reuselist *list)
{
assert(bdi && bdi->config);
if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
bgp_reuselist_del(&bdi->config->no_reuse_list, bdi);
else
bgp_reuselist_del(list ? list
: &bdi->config->reuse_list[bdi->index],
bdi);
bdi->config = NULL;
}
static void bgp_damp_info_claim(struct bgp_damp_info *bdi,
struct bgp_damp_config *bdc)
{
assert(bdc && bdi);
if (bdi->config == NULL) {
bdi->config = bdc;
return;
}
bgp_damp_info_unclaim(bdi, NULL);
bdi->config = bdc;
bdi->afi = bdc->afi;
bdi->safi = bdc->safi;
}
struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
afi_t afi, safi_t safi)
{
if (!pi)
return NULL;
if (CHECK_FLAG(pi->peer->af_flags[afi][safi],
PEER_FLAG_CONFIG_DAMPENING))
return &pi->peer->damp[afi][safi];
if (peer_group_active(pi->peer))
if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi],
PEER_FLAG_CONFIG_DAMPENING))
return &pi->peer->group->conf->damp[afi][safi];
if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
return &pi->peer->bgp->damp[afi][safi];
return NULL;
}
/* Calculate reuse list index by penalty value. */
static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
{
unsigned int i;
int index;
unsigned int index;
/*
* reuse_limit can't be zero, this is for Coverity
@ -57,27 +114,28 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
struct bgp_damp_config *bdc)
{
int index;
index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
bdi->prev = NULL;
bdi->next = bdc->reuse_list[index];
if (bdc->reuse_list[index])
bdc->reuse_list[index]->prev = bdi;
bdc->reuse_list[index] = bdi;
bgp_damp_info_claim(bdi, bdc);
bdi->index = bgp_reuse_index(bdi->penalty, bdc);
bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi);
}
/* Delete BGP dampening information from reuse list. */
static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
static void bgp_reuse_list_delete(struct bgp_damp_info *bdi)
{
bgp_damp_info_unclaim(bdi, NULL);
}
static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
struct bgp_damp_config *bdc)
{
if (bdi->next)
bdi->next->prev = bdi->prev;
if (bdi->prev)
bdi->prev->next = bdi->next;
else
bdc->reuse_list[bdi->index] = bdi->next;
bgp_damp_info_claim(bdi, bdc);
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bgp_reuselist_add(&bdc->no_reuse_list, bdi);
}
static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi)
{
bgp_damp_info_unclaim(bdi, NULL);
}
/* Return decayed penalty value. */
@ -100,10 +158,10 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
is evaluated. RFC2439 Section 4.8.7. */
static void bgp_reuse_timer(struct event *t)
{
struct bgp_damp_info *bdi;
struct bgp_damp_info *next;
struct bgp_damp_info *bdi, *bdi_next;
struct reuselist plist;
struct bgp *bgp;
time_t t_now, t_diff;
struct bgp_damp_config *bdc = EVENT_ARG(t);
bdc->t_reuse = NULL;
@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t)
t_now = monotime(NULL);
/* 1. save a pointer to the current zeroth queue head and zero the
list head entry. */
bdi = bdc->reuse_list[bdc->reuse_offset];
bdc->reuse_list[bdc->reuse_offset] = NULL;
/* 1. save a pointer to the current queue head and zero the list head
* list head entry. */
assert(bdc->reuse_offset < bdc->reuse_list_size);
plist = bdc->reuse_list[bdc->reuse_offset];
SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
rotating the circular queue of list-heads. */
bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
assert(bdc->reuse_offset < bdc->reuse_list_size);
/* 3. if ( the saved list head pointer is non-empty ) */
for (; bdi; bdi = next) {
struct bgp *bgp = bdi->path->peer->bgp;
next = bdi->next;
SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) {
bgp = bdi->path->peer->bgp;
/* Set t-diff = t-now - t-updated. */
t_diff = t_now - bdi->t_updated;
@ -150,19 +208,27 @@ static void bgp_reuse_timer(struct event *t)
bgp_aggregate_increment(
bgp, bgp_dest_get_prefix(bdi->dest),
bdi->path, bdi->afi, bdi->safi);
bgp_process(bgp, bdi->dest, bdi->afi,
bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
bdi->safi);
}
if (bdi->penalty <= bdc->reuse_limit / 2.0)
bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
else
BGP_DAMP_LIST_ADD(bdc, bdi);
} else
if (bdi->penalty <= bdc->reuse_limit / 2.0) {
bgp_damp_info_free(bdi, &plist, 1);
} else {
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bgp_reuselist_switch(&plist, bdi,
&bdc->no_reuse_list);
}
} else {
/* Re-insert into another list (See RFC2439 Section
* 4.8.6). */
bgp_reuse_list_add(bdi, bdc);
bdi->index = bgp_reuse_index(bdi->penalty, bdc);
bgp_reuselist_switch(&plist, bdi,
&bdc->reuse_list[bdi->index]);
}
}
assert(SLIST_EMPTY(&plist));
}
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
time_t t_now;
struct bgp_damp_info *bdi = NULL;
unsigned int last_penalty = 0;
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc;
bdc = get_active_bdc_from_pi(path, afi, safi);
if (!bdc)
return BGP_DAMP_USED;
t_now = monotime(NULL);
/* Processing Unreachable Messages. */
if (path->extra)
bdi = path->extra->damp_info;
@ -197,12 +266,20 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
bdi->flap = 1;
bdi->start_time = t_now;
bdi->suppress_time = 0;
bdi->index = -1;
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bdi->afi = afi;
bdi->safi = safi;
(bgp_path_info_extra_get(path))->damp_info = bdi;
BGP_DAMP_LIST_ADD(bdc, bdi);
bgp_no_reuse_list_add(bdi, bdc);
} else {
if (bdi->config != bdc) {
bgp_damp_info_claim(bdi, bdc);
if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
bgp_reuselist_add(&bdc->no_reuse_list, bdi);
else
bgp_reuselist_add(&bdc->reuse_list[bdi->index],
bdi);
}
last_penalty = bdi->penalty;
/* 1. Set t-diff = t-now - t-updated. */
@ -228,8 +305,8 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
/* Remove the route from a reuse list if it is on one. */
if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
/* If decay rate isn't equal to 0, reinsert brn. */
if (bdi->penalty != last_penalty && bdi->index >= 0) {
bgp_reuse_list_delete(bdi, bdc);
if (bdi->penalty != last_penalty) {
bgp_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
return BGP_DAMP_SUPPRESSED;
@ -240,10 +317,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
if (bdi->penalty >= bdc->suppress_value) {
bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
bdi->suppress_time = t_now;
BGP_DAMP_LIST_DEL(bdc, bdi);
bgp_no_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
return BGP_DAMP_USED;
}
@ -253,7 +329,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
time_t t_now;
struct bgp_damp_info *bdi;
int status;
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc;
bdc = get_active_bdc_from_pi(path, afi, safi);
assert(bdc);
if (!path->extra || !((bdi = path->extra->damp_info)))
return BGP_DAMP_USED;
@ -271,8 +350,8 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
&& (bdi->penalty < bdc->reuse_limit)) {
bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
bgp_reuse_list_delete(bdi, bdc);
BGP_DAMP_LIST_ADD(bdc, bdi);
bgp_reuse_list_delete(bdi);
bgp_no_reuse_list_add(bdi, bdc);
bdi->suppress_time = 0;
status = BGP_DAMP_USED;
} else
@ -281,33 +360,32 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
if (bdi->penalty > bdc->reuse_limit / 2.0)
bdi->t_updated = t_now;
else
bgp_damp_info_free(bdi, 0, afi, safi);
bgp_damp_info_free(bdi, NULL, 0);
return status;
}
void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
safi_t safi)
void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list,
int withdraw)
{
struct bgp_path_info *path;
struct bgp_damp_config *bdc = &damp[afi][safi];
assert(bdi);
if (!bdi)
return;
afi_t afi = bdi->afi;
safi_t safi = bdi->safi;
struct bgp_path_info *bpi = bdi->path;
struct bgp_dest *dest = bdi->dest;
struct bgp *bgp = bpi->peer->bgp;
const struct prefix *p = bgp_dest_get_prefix(bdi->dest);
path = bdi->path;
path->extra->damp_info = NULL;
bgp_damp_info_unclaim(bdi, list);
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
bgp_reuse_list_delete(bdi, bdc);
else
BGP_DAMP_LIST_DEL(bdc, bdi);
bgp_path_info_unset_flag(bdi->dest, path,
BGP_PATH_HISTORY | BGP_PATH_DAMPED);
if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
bgp_path_info_delete(bdi->dest, path);
bpi->extra->damp_info = NULL;
bgp_path_info_unset_flag(dest, bpi, BGP_PATH_HISTORY | BGP_PATH_DAMPED);
if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) {
bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST);
bgp_path_info_delete(dest, bpi);
bgp_process(bgp, dest, bpi, afi, safi);
}
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
}
@ -353,8 +431,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
bdc->reuse_list =
XCALLOC(MTYPE_BGP_DAMP_ARRAY,
bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
bdc->reuse_list_size * sizeof(struct reuselist));
/* Reuse-array computations */
bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
sizeof(int) * bdc->reuse_index_size);
@ -381,7 +458,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
unsigned int reuse, unsigned int suppress, time_t max)
{
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
if (bdc->half_life == half && bdc->reuse_limit == reuse
@ -393,6 +470,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
bdc->afi = afi;
bdc->safi = safi;
/* Register reuse timer. */
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
@ -401,8 +480,34 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
return 0;
}
static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */
void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
afi_t afi, safi_t safi)
{
struct bgp_damp_info *bdi;
struct reuselist *list;
unsigned int i;
bdc->reuse_offset = 0;
for (i = 0; i < bdc->reuse_list_size; ++i) {
list = &bdc->reuse_list[i];
while ((bdi = SLIST_FIRST(list)) != NULL) {
if (bdi->lastrecord == BGP_RECORD_UPDATE) {
bgp_aggregate_increment(bgp,
bgp_dest_get_prefix(
bdi->dest),
bdi->path, bdi->afi,
bdi->safi);
bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
bdi->safi);
}
bgp_damp_info_free(bdi, list, 1);
}
}
while ((bdi = SLIST_FIRST(&bdc->no_reuse_list)) != NULL)
bgp_damp_info_free(bdi, &bdc->no_reuse_list, 1);
/* Free decay array */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
bdc->decay_array_size = 0;
@ -411,41 +516,25 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
bdc->reuse_index_size = 0;
/* Free reuse list array. */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
bdc->reuse_list_size = 0;
EVENT_OFF(bdc->t_reuse);
}
/* Clean all the bgp_damp_info stored in reuse_list. */
void bgp_damp_info_clean(afi_t afi, safi_t safi)
{
unsigned int i;
struct bgp_damp_info *bdi, *next;
struct bgp_damp_config *bdc = &damp[afi][safi];
bdc->reuse_offset = 0;
for (i = 0; i < bdc->reuse_list_size; i++) {
if (!bdc->reuse_list[i])
continue;
for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
next = bdi->next;
bgp_damp_info_free(bdi, 1, afi, safi);
}
bdc->reuse_list[i] = NULL;
}
for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
next = bdi->next;
bgp_damp_info_free(bdi, 1, afi, safi);
}
bdc->no_reuse_list = NULL;
}
/* Disable route flap dampening for a bgp instance.
*
* Please note that this function also gets used to free memory when deleting a
* bgp instance.
*/
int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
{
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc;
bdc = &bgp->damp[afi][safi];
if (!bdc)
return 0;
/* If it wasn't enabled, there's nothing to do. */
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
return 0;
@ -454,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
EVENT_OFF(bdc->t_reuse);
/* Clean BGP dampening information. */
bgp_damp_info_clean(afi, safi);
/* Clear configuration */
bgp_damp_config_clean(bdc);
bgp_damp_info_clean(bgp, bdc, afi, safi);
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
return 0;
}
void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
{
if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
&& damp[afi][safi].reuse_limit == DEFAULT_REUSE
&& damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
&& damp[afi][safi].max_suppress_time
== damp[afi][safi].half_life * 4)
struct bgp_damp_config *bdc;
bdc = &bgp->damp[afi][safi];
if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
bdc->reuse_limit == DEFAULT_REUSE &&
bdc->suppress_value == DEFAULT_SUPPRESS &&
bdc->max_suppress_time == bdc->half_life * 4)
vty_out(vty, " bgp dampening\n");
else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
&& damp[afi][safi].reuse_limit == DEFAULT_REUSE
&& damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
&& damp[afi][safi].max_suppress_time
== damp[afi][safi].half_life * 4)
vty_out(vty, " bgp dampening %lld\n",
damp[afi][safi].half_life / 60LL);
else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
bdc->reuse_limit == DEFAULT_REUSE &&
bdc->suppress_value == DEFAULT_SUPPRESS &&
bdc->max_suppress_time == bdc->half_life * 4)
vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL);
else
vty_out(vty, " bgp dampening %lld %d %d %lld\n",
damp[afi][safi].half_life / 60LL,
damp[afi][safi].reuse_limit,
damp[afi][safi].suppress_value,
damp[afi][safi].max_suppress_time / 60LL);
bdc->half_life / 60LL, bdc->reuse_limit,
bdc->suppress_value, bdc->max_suppress_time / 60LL);
}
static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
size_t len, afi_t afi, safi_t safi,
bool use_json, json_object *json)
static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
unsigned int penalty, char *buf,
size_t len, bool use_json,
json_object *json)
{
time_t reuse_time = 0;
struct tm tm;
int time_store = 0;
if (penalty > damp[afi][safi].reuse_limit) {
reuse_time = (int)(DELTA_T
* ((log((double)damp[afi][safi].reuse_limit
/ penalty))
/ (log(damp[afi][safi].decay_array[1]))));
if (penalty > bdc->reuse_limit) {
reuse_time = (int)(DELTA_T *
((log((double)bdc->reuse_limit / penalty)) /
(log(bdc->decay_array[1]))));
if (reuse_time > damp[afi][safi].max_suppress_time)
reuse_time = damp[afi][safi].max_suppress_time;
if (reuse_time > bdc->max_suppress_time)
reuse_time = bdc->max_suppress_time;
gmtime_r(&reuse_time, &tm);
} else
@ -553,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
return buf;
}
void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
safi_t safi, json_object *json_path)
void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
struct bgp_path_info *path, afi_t afi, safi_t safi,
json_object *json_path)
{
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
char timebuf[BGP_UPTIME_LEN];
char timebuf[BGP_UPTIME_LEN] = {};
int penalty;
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (!path->extra)
return;
@ -570,7 +657,9 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
/* If dampening is not enabled or there is no dampening information,
return immediately. */
if (!bdc || !bdi)
if (!CHECK_FLAG(path->peer->bgp->af_flags[afi][safi],
BGP_CONFIG_DAMPENING) ||
!bdi)
return;
/* Calculate new penalty. */
@ -586,8 +675,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
afi, safi, 1, json_path);
bgp_get_reuse_time(bdc, penalty, timebuf,
BGP_UPTIME_LEN, 1, json_path);
} else {
vty_out(vty,
" Dampinfo: penalty %d, flapped %d times in %s",
@ -598,14 +687,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
vty_out(vty, ", reuse in %s",
bgp_get_reuse_time(penalty, timebuf,
BGP_UPTIME_LEN, afi, safi, 0,
bgp_get_reuse_time(bdc, penalty, timebuf,
BGP_UPTIME_LEN, 0,
json_path));
vty_out(vty, "\n");
}
}
const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
char *timebuf, size_t len, afi_t afi,
safi_t safi, bool use_json,
@ -614,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
int penalty;
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc;
bdc = get_active_bdc_from_pi(path, afi, safi);
if (!bdc)
return NULL;
if (!path->extra)
return NULL;
@ -624,7 +718,9 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
/* If dampening is not enabled or there is no dampening information,
return immediately. */
if (!bdc || !bdi)
if (!CHECK_FLAG(path->peer->bgp->af_flags[afi][safi],
BGP_CONFIG_DAMPENING) ||
!bdi)
return NULL;
/* Calculate new penalty. */
@ -632,15 +728,15 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
t_diff = t_now - bdi->t_updated;
penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
json);
return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
}
static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
afi_t afi, safi_t safi, bool use_json)
{
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
struct bgp_damp_config *bdc = &damp[afi][safi];
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (use_json) {
json_object *json = json_object_new_object();
@ -684,7 +780,7 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
bgp = bgp_get_default();
if (bgp == NULL) {
if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "No BGP process is configured\n");
return CMD_WARNING;
}
@ -725,3 +821,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
}
return CMD_SUCCESS;
}
void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, time_t half,
unsigned int reuse, unsigned int suppress, time_t max)
{
struct bgp_damp_config *bdc;
if (!peer)
return;
bdc = &peer->damp[afi][safi];
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) {
if (bdc->half_life == half && bdc->reuse_limit == reuse &&
bdc->suppress_value == suppress &&
bdc->max_suppress_time == max)
return;
bgp_peer_damp_disable(peer, afi, safi);
}
SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
bdc->afi = afi;
bdc->safi = safi;
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
&bdc->t_reuse);
}
/* Disable route flap dampening for a peer.
*
* Please note that this function also gets used to free memory when deleting a
* peer or peer group.
*/
void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi)
{
struct bgp_damp_config *bdc;
if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
return;
bdc = &peer->damp[afi][safi];
if (!bdc)
return;
bgp_damp_info_clean(peer->bgp, bdc, afi, safi);
UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
}
void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi)
{
struct bgp_damp_config *bdc;
bdc = &peer->damp[afi][safi];
if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
bdc->reuse_limit == DEFAULT_REUSE &&
bdc->suppress_value == DEFAULT_SUPPRESS &&
bdc->max_suppress_time == bdc->half_life * 4)
vty_out(vty, " neighbor %s dampening\n", peer->host);
else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
bdc->reuse_limit == DEFAULT_REUSE &&
bdc->suppress_value == DEFAULT_SUPPRESS &&
bdc->max_suppress_time == bdc->half_life * 4)
vty_out(vty, " neighbor %s dampening %lld\n", peer->host,
bdc->half_life / 60LL);
else
vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n",
peer->host, bdc->half_life / 60LL, bdc->reuse_limit,
bdc->suppress_value, bdc->max_suppress_time / 60LL);
}
static void bgp_print_peer_dampening_parameters(struct vty *vty,
struct peer *peer, afi_t afi,
safi_t safi, bool use_json,
json_object *json)
{
struct bgp_damp_config *bdc;
if (!peer)
return;
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) {
bdc = &peer->damp[afi][safi];
if (!bdc)
return;
if (use_json) {
json_object_int_add(json, "halfLifeSecs",
bdc->half_life);
json_object_int_add(json, "reusePenalty",
bdc->reuse_limit);
json_object_int_add(json, "suppressPenalty",
bdc->suppress_value);
json_object_int_add(json, "maxSuppressTimeSecs",
bdc->max_suppress_time);
json_object_int_add(json, "maxSuppressPenalty",
bdc->ceiling);
} else {
vty_out(vty, "Half-life time: %lld min\n",
(long long)bdc->half_life / 60);
vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
vty_out(vty, "Suppress penalty: %d\n",
bdc->suppress_value);
vty_out(vty, "Max suppress time: %lld min\n",
(long long)bdc->max_suppress_time / 60);
vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
vty_out(vty, "\n");
}
} else if (!use_json)
vty_out(vty, "neighbor dampening not enabled for %s\n",
get_afi_safi_str(afi, safi, false));
}
void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi, bool use_json)
{
json_object *json;
if (use_json) {
json = json_object_new_object();
json_object_string_add(json, "addressFamily",
get_afi_safi_str(afi, safi, false));
bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true,
json);
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
vty_out(vty, "\nFor address family: %s\n",
get_afi_safi_str(afi, safi, false));
bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false,
NULL);
}
}

View file

@ -10,11 +10,6 @@
/* Structure maintained on a per-route basis. */
struct bgp_damp_info {
/* Doubly linked list. This information must be linked to
reuse_list or no_reuse_list. */
struct bgp_damp_info *next;
struct bgp_damp_info *prev;
/* Figure-of-merit. */
unsigned int penalty;
@ -30,6 +25,9 @@ struct bgp_damp_info {
/* Time of route start to be suppressed. */
time_t suppress_time;
/* Back reference to associated dampening configuration. */
struct bgp_damp_config *config;
/* Back reference to bgp_path_info. */
struct bgp_path_info *path;
@ -38,6 +36,8 @@ struct bgp_damp_info {
/* Current index in the reuse_list. */
int index;
#define BGP_DAMP_NO_REUSE_LIST_INDEX \
(-1) /* index for elements on no_reuse_list */
/* Last time message type. */
uint8_t lastrecord;
@ -46,8 +46,12 @@ struct bgp_damp_info {
afi_t afi;
safi_t safi;
SLIST_ENTRY(bgp_damp_info) entry;
};
SLIST_HEAD(reuselist, bgp_damp_info);
/* Specified parameter set configuration. */
struct bgp_damp_config {
/* Value over which routes suppressed. */
@ -65,7 +69,6 @@ struct bgp_damp_config {
/* Non-configurable parameters but fixed at implementation time.
* To change this values, init_bgp_damp() should be modified.
*/
time_t tmax; /* Max time previous instability retained */
unsigned int reuse_list_size; /* Number of reuse lists */
unsigned int reuse_index_size; /* Size of reuse index array */
@ -75,8 +78,8 @@ struct bgp_damp_config {
unsigned int ceiling; /* Max value a penalty can attain */
unsigned int decay_rate_per_tick; /* Calculated from half-life */
unsigned int decay_array_size; /* Calculated using config parameters */
double scale_factor;
unsigned int reuse_scale_factor;
double scale_factor;
/* Decay array per-set based. */
double *decay_array;
@ -85,17 +88,17 @@ struct bgp_damp_config {
int *reuse_index;
/* Reuse list array per-set based. */
struct bgp_damp_info **reuse_list;
int reuse_offset;
struct reuselist *reuse_list;
unsigned int reuse_offset;
safi_t safi;
/* All dampening information which is not on reuse list. */
struct bgp_damp_info *no_reuse_list;
struct reuselist no_reuse_list;
/* Reuse timer thread per-set base. */
struct event *t_reuse;
afi_t afi;
safi_t safi;
};
#define BGP_DAMP_NONE 0
@ -117,6 +120,8 @@ struct bgp_damp_config {
#define REUSE_LIST_SIZE 256
#define REUSE_ARRAY_SIZE 1024
extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
afi_t afi, safi_t safi);
extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
unsigned int reuse, unsigned int suppress,
time_t max);
@ -125,14 +130,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
afi_t afi, safi_t safi, int attr_change);
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
afi_t afi, safi_t saff);
extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw,
afi_t afi, safi_t safi);
extern void bgp_damp_info_clean(afi_t afi, safi_t safi);
extern void bgp_damp_info_free(struct bgp_damp_info *bdi,
struct reuselist *list, int withdraw);
extern void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
afi_t afi, safi_t safi);
extern void bgp_damp_config_clean(struct bgp_damp_config *bdc);
extern int bgp_damp_decay(time_t tdiff, int penalty,
struct bgp_damp_config *damp);
extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi);
extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
afi_t afi, safi_t safi, json_object *json_path);
struct bgp_damp_config *bdc);
extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi);
extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
struct bgp_path_info *path, afi_t afi,
safi_t safi, json_object *json_path);
extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
struct bgp_path_info *path,
char *timebuf, size_t len, afi_t afi,
@ -140,5 +149,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
json_object *json);
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi,
safi_t safi, uint16_t show_flags);
extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
time_t half, unsigned int reuse,
unsigned int suppress, time_t max);
extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi);
extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi);
extern void bgp_show_peer_dampening_parameters(struct vty *vty,
struct peer *peer, afi_t afi,
safi_t safi, bool use_json);
#endif /* _QUAGGA_BGP_DAMP_H */

View file

@ -16,6 +16,7 @@
#include "memory.h"
#include "queue.h"
#include "filter.h"
#include "hook.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
@ -37,6 +38,9 @@
#include "bgpd/bgp_debug_clippy.c"
DEFINE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running),
(vty, running));
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
unsigned long conf_bgp_debug_events;
@ -46,7 +50,6 @@ unsigned long conf_bgp_debug_keepalive;
unsigned long conf_bgp_debug_update;
unsigned long conf_bgp_debug_bestpath;
unsigned long conf_bgp_debug_zebra;
unsigned long conf_bgp_debug_allow_martians;
unsigned long conf_bgp_debug_nht;
unsigned long conf_bgp_debug_update_groups;
unsigned long conf_bgp_debug_vpn;
@ -67,7 +70,6 @@ unsigned long term_bgp_debug_keepalive;
unsigned long term_bgp_debug_update;
unsigned long term_bgp_debug_bestpath;
unsigned long term_bgp_debug_zebra;
unsigned long term_bgp_debug_allow_martians;
unsigned long term_bgp_debug_nht;
unsigned long term_bgp_debug_update_groups;
unsigned long term_bgp_debug_vpn;
@ -112,6 +114,7 @@ static const struct message bgp_notify_msg[] = {
{BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"},
{BGP_NOTIFY_CEASE, "Cease"},
{BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"},
{BGP_NOTIFY_SEND_HOLD_ERR, "Send Hold Timer Expired"},
{0}};
static const struct message bgp_notify_head_msg[] = {
@ -216,6 +219,7 @@ static void bgp_debug_list_free(struct list *list)
listnode_delete(list, filter);
prefix_free(&filter->p);
XFREE(MTYPE_BGP_DEBUG_STR, filter->host);
XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name);
XFREE(MTYPE_BGP_DEBUG_FILTER, filter);
}
}
@ -233,15 +237,21 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc,
vty_out(vty, "%s", desc);
if (list && !list_isempty(list)) {
vty_out(vty, " for");
vty_out(vty, " for:\n");
for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) {
if (filter->host)
vty_out(vty, " %s", filter->host);
vty_out(vty, " %s", filter->host);
if (filter->plist_name)
vty_out(vty, " with prefix-list %s",
filter->plist_name);
if (filter->p && filter->p->family == AF_EVPN)
bgp_debug_print_evpn_prefix(vty, "", filter->p);
else if (filter->p)
vty_out(vty, " %pFX", filter->p);
vty_out(vty, "\n");
}
}
@ -261,7 +271,11 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc,
if (list && !list_isempty(list)) {
for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) {
if (filter->host) {
if (filter->host && filter->plist_name) {
vty_out(vty, "%s %s prefix-list %s\n", desc,
filter->host, filter->plist_name);
write++;
} else if (filter->host) {
vty_out(vty, "%s %s\n", desc, filter->host);
write++;
}
@ -286,7 +300,8 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc,
}
static void bgp_debug_list_add_entry(struct list *list, const char *host,
const struct prefix *p)
const struct prefix *p,
const char *plist_name)
{
struct bgp_debug_filter *filter;
@ -295,13 +310,27 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host,
if (host) {
filter->host = XSTRDUP(MTYPE_BGP_DEBUG_STR, host);
filter->plist_name = NULL;
filter->plist_v4 = NULL;
filter->plist_v6 = NULL;
filter->p = NULL;
} else if (p) {
filter->host = NULL;
filter->plist_name = NULL;
filter->plist_v4 = NULL;
filter->plist_v6 = NULL;
filter->p = prefix_new();
prefix_copy(filter->p, p);
}
if (plist_name) {
filter->plist_name = XSTRDUP(MTYPE_BGP_DEBUG_STR, plist_name);
filter->plist_v4 = prefix_list_lookup(AFI_IP,
filter->plist_name);
filter->plist_v6 = prefix_list_lookup(AFI_IP6,
filter->plist_name);
}
listnode_add(list, filter);
}
@ -315,6 +344,7 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host,
if (host && strcmp(filter->host, host) == 0) {
listnode_delete(list, filter);
XFREE(MTYPE_BGP_DEBUG_STR, filter->host);
XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name);
XFREE(MTYPE_BGP_DEBUG_FILTER, filter);
return true;
} else if (p && filter->p->prefixlen == p->prefixlen
@ -330,16 +360,20 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host,
}
static bool bgp_debug_list_has_entry(struct list *list, const char *host,
const struct prefix *p)
const struct prefix *p,
const char *plist_name)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) {
if (host) {
if (strcmp(filter->host, host) == 0) {
if (host && plist_name) {
if (strmatch(filter->host, host) && filter->plist_name &&
strmatch(filter->plist_name, plist_name))
return true;
} else if (host) {
if (strmatch(filter->host, host))
return true;
}
} else if (p) {
if (filter->p->prefixlen == p->prefixlen
&& prefix_match(filter->p, p)) {
@ -353,7 +387,7 @@ static bool bgp_debug_list_has_entry(struct list *list, const char *host,
bool bgp_debug_peer_updout_enabled(char *host)
{
return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host,
return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, NULL,
NULL));
}
@ -480,6 +514,7 @@ const char *bgp_notify_subcode_str(char code, char subcode)
return lookup_msg(bgp_notify_update_msg, subcode,
"Unrecognized Error Subcode");
case BGP_NOTIFY_HOLD_ERR:
case BGP_NOTIFY_SEND_HOLD_ERR:
break;
case BGP_NOTIFY_FSM_ERR:
return lookup_msg(bgp_notify_fsm_msg, subcode,
@ -498,12 +533,13 @@ const char *bgp_notify_subcode_str(char code, char subcode)
const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
size_t datalen)
{
memset(buf, 0, bufsz);
if (!data || datalen < 1)
return NULL;
return buf;
uint8_t len = data[0];
if (!len || len > datalen - 1)
return NULL;
return buf;
return zlog_sanitize(buf, bufsz, data + 1, len);
}
@ -779,14 +815,15 @@ DEFUN (debug_bgp_neighbor_events_peer,
bgp_debug_neighbor_events_peers = list_new();
if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, host,
NULL)) {
NULL, NULL)) {
vty_out(vty,
"BGP neighbor-events debugging is already enabled for %s\n",
host);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL);
bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL,
NULL);
if (vty->node == CONFIG_NODE)
DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS);
@ -926,14 +963,15 @@ DEFUN (debug_bgp_keepalive_peer,
if (!bgp_debug_keepalive_peers)
bgp_debug_keepalive_peers = list_new();
if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL)) {
if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL,
NULL)) {
vty_out(vty,
"BGP keepalive debugging is already enabled for %s\n",
host);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL);
bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL, NULL);
if (vty->node == CONFIG_NODE)
DEBUG_ON(keepalive, KEEPALIVE);
@ -1014,15 +1052,16 @@ DEFPY (debug_bgp_bestpath_prefix,
if (!bgp_debug_bestpath_prefixes)
bgp_debug_bestpath_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL,
prefix)) {
if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, prefix,
NULL)) {
vty_out(vty,
"BGP bestpath debugging is already enabled for %s\n",
prefix_str);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix);
bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix,
NULL);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(bestpath, BESTPATH);
@ -1115,6 +1154,31 @@ DEFUN (debug_bgp_update,
return CMD_SUCCESS;
}
DEFPY (debug_bgp_update_detail,
debug_bgp_update_detail_cmd,
"[no] debug bgp updates detail",
NO_STR
DEBUG_STR
BGP_STR
"BGP updates\n"
"Show detailed information about updates\n")
{
if (vty->node == CONFIG_NODE) {
if (no)
DEBUG_OFF(update, UPDATE_DETAIL);
else
DEBUG_ON(update, UPDATE_DETAIL);
} else {
if (no)
TERM_DEBUG_OFF(update, UPDATE_DETAIL);
else
TERM_DEBUG_ON(update, UPDATE_DETAIL);
vty_out(vty, "BGP updates detail debugging is on\n");
}
return CMD_SUCCESS;
}
DEFUN (debug_bgp_update_direct,
debug_bgp_update_direct_cmd,
"debug bgp updates <in|out>",
@ -1149,9 +1213,9 @@ DEFUN (debug_bgp_update_direct,
return CMD_SUCCESS;
}
DEFUN (debug_bgp_update_direct_peer,
DEFPY (debug_bgp_update_direct_peer,
debug_bgp_update_direct_peer_cmd,
"debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>",
"debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD> [prefix-list PREFIXLIST_NAME$plist]",
DEBUG_STR
BGP_STR
"BGP updates\n"
@ -1159,7 +1223,9 @@ DEFUN (debug_bgp_update_direct_peer,
"Outbound updates\n"
"BGP neighbor IP address to debug\n"
"BGP IPv6 neighbor to debug\n"
"BGP neighbor on interface to debug\n")
"BGP neighbor on interface to debug\n"
"Use prefix-list to filter prefixes to debug\n"
"Name of prefix-list\n")
{
int idx_in_out = 3;
int idx_peer = 4;
@ -1179,7 +1245,7 @@ DEFUN (debug_bgp_update_direct_peer,
if (inbound) {
if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, host,
NULL)) {
NULL, plist)) {
vty_out(vty,
"BGP inbound update debugging is already enabled for %s\n",
host);
@ -1189,7 +1255,7 @@ DEFUN (debug_bgp_update_direct_peer,
else {
if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host,
NULL)) {
NULL, plist)) {
vty_out(vty,
"BGP outbound update debugging is already enabled for %s\n",
host);
@ -1198,14 +1264,15 @@ DEFUN (debug_bgp_update_direct_peer,
}
if (inbound)
bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL);
bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL,
plist);
else {
struct peer *peer;
struct peer_af *paf;
int afidx;
bgp_debug_list_add_entry(bgp_debug_update_out_peers, host,
NULL);
bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, NULL,
plist);
peer = bgp_find_peer(vty, host);
if (peer) {
@ -1282,7 +1349,7 @@ DEFUN (no_debug_bgp_update_direct,
DEFUN (no_debug_bgp_update_direct_peer,
no_debug_bgp_update_direct_peer_cmd,
"no debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>",
"no debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD> [prefix-list PREFIXLIST_NAME]",
NO_STR
DEBUG_STR
BGP_STR
@ -1291,7 +1358,9 @@ DEFUN (no_debug_bgp_update_direct_peer,
"Outbound updates\n"
"BGP neighbor IP address to debug\n"
"BGP IPv6 neighbor to debug\n"
"BGP neighbor on interface to debug\n")
"BGP neighbor on interface to debug\n"
"Use prefix-list to filter prefixes to debug\n"
"Name of prefix-list\n")
{
int idx_in_out = 4;
int idx_peer = 5;
@ -1413,15 +1482,15 @@ DEFPY (debug_bgp_update_prefix_afi_safi,
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL,
&argv_p)) {
if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, &argv_p,
NULL)) {
vty_out(vty,
"BGP updates debugging is already enabled for %pFX\n",
&argv_p);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p);
bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p, NULL);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
@ -1509,14 +1578,15 @@ DEFPY (debug_bgp_update_prefix,
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) {
if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix,
NULL)) {
vty_out(vty,
"BGP updates debugging is already enabled for %s\n",
prefix_str);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix);
bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix, NULL);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
@ -1646,13 +1716,14 @@ DEFPY (debug_bgp_zebra_prefix,
if (!bgp_debug_zebra_prefixes)
bgp_debug_zebra_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) {
if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix,
NULL)) {
vty_out(vty, "BGP zebra debugging is already enabled for %s\n",
prefix_str);
return CMD_SUCCESS;
}
bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix);
bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix, NULL);
if (vty->node == CONFIG_NODE)
DEBUG_ON(zebra, ZEBRA);
@ -2092,7 +2163,6 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(as4, AS4_SEGMENT);
TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS);
TERM_DEBUG_OFF(zebra, ZEBRA);
TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
TERM_DEBUG_OFF(nht, NHT);
TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
@ -2168,9 +2238,6 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
vty_out(vty, " BGP graceful-restart debugging is on\n");
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
vty_out(vty, " BGP allow martian next hop debugging is on\n");
if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
vty_out(vty,
" BGP route leak from vrf to vpn debugging is on\n");
@ -2205,6 +2272,8 @@ DEFUN_NOSH (show_debugging_bgp,
cmd_show_lib_debugs(vty);
hook_call(bgp_hook_config_write_debug, vty, false);
return CMD_SUCCESS;
}
@ -2264,6 +2333,11 @@ static int bgp_config_write_debug(struct vty *vty)
bgp_debug_update_out_peers);
}
if (CONF_BGP_DEBUG(update, UPDATE_DETAIL)) {
vty_out(vty, "debug bgp updates detail\n");
write++;
}
if (CONF_BGP_DEBUG(zebra, ZEBRA)) {
if (!bgp_debug_zebra_prefixes
|| list_isempty(bgp_debug_zebra_prefixes)) {
@ -2276,11 +2350,6 @@ static int bgp_config_write_debug(struct vty *vty)
}
}
if (CONF_BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) {
vty_out(vty, "debug bgp allow-martians\n");
write++;
}
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) {
vty_out(vty, "debug bgp vpn leak-from-vrf\n");
write++;
@ -2339,6 +2408,9 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
if (hook_call(bgp_hook_config_write_debug, vty, true))
write++;
return write;
}
@ -2369,6 +2441,8 @@ void bgp_debug_init(void)
install_element(CONFIG_NODE, &debug_bgp_keepalive_cmd);
install_element(ENABLE_NODE, &debug_bgp_update_cmd);
install_element(CONFIG_NODE, &debug_bgp_update_cmd);
install_element(ENABLE_NODE, &debug_bgp_update_detail_cmd);
install_element(CONFIG_NODE, &debug_bgp_update_detail_cmd);
install_element(ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element(CONFIG_NODE, &debug_bgp_zebra_cmd);
install_element(ENABLE_NODE, &debug_bgp_update_groups_cmd);
@ -2484,7 +2558,7 @@ static int bgp_debug_per_prefix(const struct prefix *p,
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
if (term_bgp_debug_type & BGP_DEBUG_TYPE) {
if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all prefixes so return true */
if (!per_prefix_list || list_isempty(per_prefix_list))
return 1;
@ -2509,29 +2583,41 @@ static int bgp_debug_per_prefix(const struct prefix *p,
/* Return true if this peer is on the per_peer_list of peers to debug
* for BGP_DEBUG_TYPE
*/
static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type,
static bool bgp_debug_per_peer(char *host, const struct prefix *p,
unsigned long term_bgp_debug_type,
unsigned int BGP_DEBUG_TYPE,
struct list *per_peer_list)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
if (term_bgp_debug_type & BGP_DEBUG_TYPE) {
if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all peers so return true */
if (!per_peer_list || list_isempty(per_peer_list))
return true;
else {
if (!host)
return false;
for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode,
filter))
if (strcmp(filter->host, host) == 0)
return true;
if (!host)
return false;
}
for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, filter))
if (strmatch(filter->host, host) &&
filter->plist_name && p) {
struct prefix_list *plist;
afi_t afi = family2afi(p->family);
plist = (afi == AFI_IP) ? filter->plist_v4
: filter->plist_v6;
if (!plist)
continue;
return prefix_list_apply(plist, p) ==
PREFIX_PERMIT;
} else if (strmatch(filter->host, host)) {
return true;
}
return false;
}
return false;
@ -2544,7 +2630,7 @@ bool bgp_debug_neighbor_events(const struct peer *peer)
if (peer)
host = peer->host;
return bgp_debug_per_peer(host, term_bgp_debug_neighbor_events,
return bgp_debug_per_peer(host, NULL, term_bgp_debug_neighbor_events,
BGP_DEBUG_NEIGHBOR_EVENTS,
bgp_debug_neighbor_events_peers);
}
@ -2556,7 +2642,7 @@ bool bgp_debug_keepalive(const struct peer *peer)
if (peer)
host = peer->host;
return bgp_debug_per_peer(host, term_bgp_debug_keepalive,
return bgp_debug_per_peer(host, NULL, term_bgp_debug_keepalive,
BGP_DEBUG_KEEPALIVE,
bgp_debug_keepalive_peers);
}
@ -2570,7 +2656,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p,
host = peer->host;
if (inbound) {
if (bgp_debug_per_peer(host, term_bgp_debug_update,
if (bgp_debug_per_peer(host, p, term_bgp_debug_update,
BGP_DEBUG_UPDATE_IN,
bgp_debug_update_in_peers))
return true;
@ -2578,7 +2664,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p,
/* outbound */
else {
if (bgp_debug_per_peer(host, term_bgp_debug_update,
if (bgp_debug_per_peer(host, p, term_bgp_debug_update,
BGP_DEBUG_UPDATE_OUT,
bgp_debug_update_out_peers))
return true;
@ -2627,7 +2713,7 @@ bool bgp_debug_zebra(const struct prefix *p)
const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
const struct prefix_rd *prd,
union prefixconstptr pu,
mpls_label_t *label, uint32_t num_labels,
mpls_label_t *label, uint8_t num_labels,
int addpath_valid, uint32_t addpath_id,
struct bgp_route_evpn *overlay_index,
char *str, int size)

View file

@ -6,9 +6,15 @@
#ifndef _QUAGGA_BGP_DEBUG_H
#define _QUAGGA_BGP_DEBUG_H
#include "hook.h"
#include "vty.h"
#include "bgp_attr.h"
#include "bgp_updgrp.h"
DECLARE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running),
(vty, running));
/* sort of packet direction */
#define DUMP_ON 1
#define DUMP_SEND 2
@ -55,7 +61,6 @@ extern unsigned long conf_bgp_debug_keepalive;
extern unsigned long conf_bgp_debug_update;
extern unsigned long conf_bgp_debug_bestpath;
extern unsigned long conf_bgp_debug_zebra;
extern unsigned long conf_bgp_debug_allow_martians;
extern unsigned long conf_bgp_debug_nht;
extern unsigned long conf_bgp_debug_update_groups;
extern unsigned long conf_bgp_debug_vpn;
@ -74,7 +79,6 @@ extern unsigned long term_bgp_debug_keepalive;
extern unsigned long term_bgp_debug_update;
extern unsigned long term_bgp_debug_bestpath;
extern unsigned long term_bgp_debug_zebra;
extern unsigned long term_bgp_debug_allow_martians;
extern unsigned long term_bgp_debug_nht;
extern unsigned long term_bgp_debug_update_groups;
extern unsigned long term_bgp_debug_vpn;
@ -96,6 +100,9 @@ extern struct list *bgp_debug_zebra_prefixes;
struct bgp_debug_filter {
char *host;
char *plist_name;
struct prefix_list *plist_v4;
struct prefix_list *plist_v6;
struct prefix *p;
};
@ -109,8 +116,8 @@ struct bgp_debug_filter {
#define BGP_DEBUG_UPDATE_IN 0x01
#define BGP_DEBUG_UPDATE_OUT 0x02
#define BGP_DEBUG_UPDATE_PREFIX 0x04
#define BGP_DEBUG_UPDATE_DETAIL 0x08
#define BGP_DEBUG_ZEBRA 0x01
#define BGP_DEBUG_ALLOW_MARTIANS 0x01
#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_UPDATE_GROUPS 0x01
#define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01
@ -124,9 +131,6 @@ struct bgp_debug_filter {
#define BGP_DEBUG_EVPN_MH_ES 0x01
#define BGP_DEBUG_EVPN_MH_RT 0x02
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
#define BGP_DEBUG_GRACEFUL_RESTART 0x01
#define BGP_DEBUG_BFD_LIB 0x01
@ -149,8 +153,8 @@ struct bgp_debug_filter {
TERM_DEBUG_OFF(a, b); \
} while (0)
#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b)
#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
#define BGP_DEBUG(a, b) (unlikely(term_bgp_debug_##a & BGP_DEBUG_##b))
#define CONF_BGP_DEBUG(a, b) (unlikely(conf_bgp_debug_##a & BGP_DEBUG_##b))
extern const char *const bgp_type_str[];
@ -171,7 +175,7 @@ extern bool bgp_debug_zebra(const struct prefix *p);
extern const char *bgp_debug_rdpfxpath2str(
afi_t afi, safi_t safi, const struct prefix_rd *prd,
union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels,
union prefixconstptr pu, mpls_label_t *label, uint8_t num_labels,
int addpath_valid, uint32_t addpath_id,
struct bgp_route_evpn *overlay_index, char *str, int size);
const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,

View file

@ -4,6 +4,7 @@
*/
#include <zebra.h>
#include <sys/stat.h>
#include "log.h"
#include "stream.h"
@ -246,14 +247,15 @@ static void bgp_dump_routes_index_table(struct bgp *bgp)
/* Walk down all peers */
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
int family = sockunion_family(&peer->connection->su);
/* Peer's type */
if (sockunion_family(&peer->su) == AF_INET) {
if (family == AF_INET) {
stream_putc(
obuf,
TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
+ TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
} else if (sockunion_family(&peer->su) == AF_INET6) {
} else if (family == AF_INET6) {
stream_putc(
obuf,
TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
@ -264,10 +266,13 @@ static void bgp_dump_routes_index_table(struct bgp *bgp)
stream_put_in_addr(obuf, &peer->remote_id);
/* Peer's IP address */
if (sockunion_family(&peer->su) == AF_INET) {
stream_put_in_addr(obuf, &peer->su.sin.sin_addr);
} else if (sockunion_family(&peer->su) == AF_INET6) {
stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr,
if (family == AF_INET) {
stream_put_in_addr(obuf,
&peer->connection->su.sin.sin_addr);
} else if (family == AF_INET6) {
stream_write(obuf,
(uint8_t *)&peer->connection->su.sin6
.sin6_addr,
IPV6_MAX_BYTELEN);
}
@ -468,24 +473,26 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer,
stream_putw(obuf, peer->local_as);
}
if (peer->su.sa.sa_family == AF_INET) {
if (peer->connection->su.sa.sa_family == AF_INET) {
stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
stream_putw(obuf, AFI_IP);
stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
stream_put(obuf, &peer->connection->su.sin.sin_addr,
IPV4_MAX_BYTELEN);
if (peer->su_local)
stream_put(obuf, &peer->su_local->sin.sin_addr,
IPV4_MAX_BYTELEN);
else
stream_put(obuf, empty, IPV4_MAX_BYTELEN);
} else if (peer->su.sa.sa_family == AF_INET6) {
} else if (peer->connection->su.sa.sa_family == AF_INET6) {
/* Interface Index and Address family. */
stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
stream_putw(obuf, AFI_IP6);
/* Source IP Address and Destination IP Address. */
stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
stream_put(obuf, &peer->connection->su.sin6.sin6_addr,
IPV6_MAX_BYTELEN);
if (peer->su_local)
stream_put(obuf, &peer->su_local->sin6.sin6_addr,
@ -512,8 +519,8 @@ int bgp_dump_state(struct peer *peer)
bgp_dump_all.type);
bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
stream_putw(obuf, peer->ostatus);
stream_putw(obuf, peer->status);
stream_putw(obuf, peer->connection->ostatus);
stream_putw(obuf, peer->connection->status);
/* Set length. */
bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
@ -532,10 +539,10 @@ static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
/* If dump file pointer is disabled return immediately. */
if (bgp_dump->fp == NULL)
return;
if (peer->su.sa.sa_family == AF_INET) {
if (peer->connection->su.sa.sa_family == AF_INET) {
addpath_capable =
bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST);
} else if (peer->su.sa.sa_family == AF_INET6) {
} else if (peer->connection->su.sa.sa_family == AF_INET6) {
addpath_capable =
bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST);
}

View file

@ -237,11 +237,10 @@ struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length,
disable_ieee_floating);
}
struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length,
bool disable_ieee_floating)
struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length)
{
return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE,
disable_ieee_floating);
false);
}
/* Duplicate the Extended Communities Attribute structure. */
@ -263,8 +262,11 @@ struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
}
/* Return string representation of ecommunities attribute. */
char *ecommunity_str(struct ecommunity *ecom)
const char *ecommunity_str(struct ecommunity *ecom)
{
if (!ecom)
return "(null)";
if (!ecom->str)
ecom->str =
ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
@ -355,6 +357,22 @@ bool ecommunity_cmp(const void *arg1, const void *arg2)
ecom1->unit_size) == 0);
}
static void ecommunity_color_str(char *buf, size_t bufsz, uint8_t *ptr)
{
/*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0x03 | Sub-Type(0x0b) | Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Color Value |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
uint32_t colorid;
memcpy(&colorid, ptr + 3, 4);
colorid = ntohl(colorid);
snprintf(buf, bufsz, "Color:%d", colorid);
}
/* Initialize Extended Comminities related hash. */
void ecommunity_init(void)
{
@ -371,7 +389,9 @@ void ecommunity_finish(void)
enum ecommunity_token {
ecommunity_token_unknown = 0,
ecommunity_token_rt,
ecommunity_token_nt,
ecommunity_token_soo,
ecommunity_token_color,
ecommunity_token_val,
ecommunity_token_rt6,
ecommunity_token_val6,
@ -415,6 +435,58 @@ static void ecommunity_origin_validation_state_str(char *buf, size_t bufsz,
(void)ptr; /* consume value */
}
bool ecommunity_node_target_match(struct ecommunity *ecom,
struct in_addr *local_id)
{
uint32_t i;
bool match = false;
if (!ecom || !ecom->size)
return NULL;
for (i = 0; i < ecom->size; i++) {
const uint8_t *pnt;
uint8_t type, sub_type;
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
type = *pnt++;
sub_type = *pnt++;
if (type == ECOMMUNITY_ENCODE_IP &&
sub_type == ECOMMUNITY_NODE_TARGET) {
/* Node Target ID is encoded as A.B.C.D:0 */
if (IPV4_ADDR_SAME((struct in_addr *)pnt, local_id))
match = true;
(void)pnt;
}
}
return match;
}
static void ecommunity_node_target_str(char *buf, size_t bufsz, uint8_t *ptr,
int format)
{
/*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0x01 or 0x41 | Sub-Type(0x09) | Target BGP Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Target BGP Identifier (cont.) | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct in_addr node_id = {};
IPV4_ADDR_COPY(&node_id, (struct in_addr *)ptr);
snprintfrr(buf, bufsz, "%s%pI4%s",
format == ECOMMUNITY_FORMAT_COMMUNITY_LIST ? "nt " : "NT:",
&node_id,
format == ECOMMUNITY_FORMAT_COMMUNITY_LIST ? ":0" : "");
(void)ptr; /* consume value */
}
static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
int trans, as_t as,
struct in_addr *ip,
@ -443,31 +515,25 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
/* Fill in the values. */
eval->val[0] = type;
if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
SET_FLAG(eval->val[0], ECOMMUNITY_FLAG_NON_TRANSITIVE);
eval->val[1] = sub_type;
if (type == ECOMMUNITY_ENCODE_AS) {
eval->val[2] = (as >> 8) & 0xff;
eval->val[3] = as & 0xff;
eval->val[4] = (val >> 24) & 0xff;
eval->val[5] = (val >> 16) & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
encode_route_target_as(as, val, eval, trans);
} else if (type == ECOMMUNITY_ENCODE_IP) {
memcpy(&eval->val[2], ip, sizeof(struct in_addr));
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
if (sub_type == ECOMMUNITY_NODE_TARGET)
encode_node_target(ip, eval, trans);
else
encode_route_target_ip(ip, val, eval, trans);
} else if (type == ECOMMUNITY_ENCODE_TRANS_EXP &&
sub_type == ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) {
memcpy(&eval6->val[2], ip6, sizeof(struct in6_addr));
eval6->val[18] = (val >> 8) & 0xff;
eval6->val[19] = val & 0xff;
} else if (type == ECOMMUNITY_ENCODE_OPAQUE &&
sub_type == ECOMMUNITY_COLOR) {
encode_color(val, eval);
} else {
eval->val[2] = (as >> 24) & 0xff;
eval->val[3] = (as >> 16) & 0xff;
eval->val[4] = (as >> 8) & 0xff;
eval->val[5] = as & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
encode_route_target_as4(as, val, eval, trans);
}
return 0;
@ -486,9 +552,8 @@ static int ecommunity_encode(uint8_t type, uint8_t sub_type, int trans, as_t as,
}
/* Get next Extended Communities token from the string. */
static const char *ecommunity_gettoken(const char *str,
void *eval_ptr,
enum ecommunity_token *token)
static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
enum ecommunity_token *token, int type)
{
int ret;
int dot = 0;
@ -500,10 +565,15 @@ static const char *ecommunity_gettoken(const char *str,
struct in6_addr ip6;
as_t as = 0;
uint32_t val = 0;
uint8_t ecomm_type;
uint32_t val_color = 0;
uint8_t ecomm_type = 0;
uint8_t sub_type = 0;
char buf[INET_ADDRSTRLEN + 1];
struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr;
uint64_t tmp_as = 0;
static const char str_color[5] = "color";
const char *ptr_color;
bool val_color_set = false;
/* Skip white space. */
while (isspace((unsigned char)*p)) {
@ -515,40 +585,49 @@ static const char *ecommunity_gettoken(const char *str,
if (*p == '\0')
return NULL;
/* "rt" and "soo" keyword parse. */
if (!isdigit((unsigned char)*p)) {
/* "rt" match check. */
if (tolower((unsigned char)*p) == 'r') {
/* "rt", "nt", "soo", and "color" keyword parse. */
/* "rt" */
if (tolower((unsigned char)*p) == 'r') {
p++;
if (tolower((unsigned char)*p) == 't') {
p++;
if (tolower((unsigned char)*p) == 't') {
p++;
if (*p != '\0' && tolower((int)*p) == '6')
*token = ecommunity_token_rt6;
else
*token = ecommunity_token_rt;
return p;
}
if (isspace((unsigned char)*p) || *p == '\0') {
if (*p != '\0' && tolower((int)*p) == '6')
*token = ecommunity_token_rt6;
else
*token = ecommunity_token_rt;
return p;
}
goto error;
return p;
}
/* "soo" match check. */
else if (tolower((unsigned char)*p) == 's') {
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_rt;
return p;
}
goto error;
}
/* "nt" */
if (tolower((unsigned char)*p) == 'n') {
p++;
if (tolower((unsigned char)*p) == 't') {
p++;
*token = ecommunity_token_nt;
return p;
}
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_nt;
return p;
}
goto error;
}
/* "soo" */
if (tolower((unsigned char)*p) == 's') {
p++;
if (tolower((unsigned char)*p) == 'o') {
p++;
if (tolower((unsigned char)*p) == 'o') {
p++;
if (tolower((unsigned char)*p) == 'o') {
p++;
*token = ecommunity_token_soo;
return p;
}
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_soo;
return p;
}
goto error;
*token = ecommunity_token_soo;
return p;
}
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_soo;
@ -556,9 +635,29 @@ static const char *ecommunity_gettoken(const char *str,
}
goto error;
}
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_soo;
return p;
}
goto error;
}
/* "color" */
if (tolower((unsigned char)*p) == 'c') {
ptr_color = &str_color[0];
for (unsigned int i = 0; i < 5; i++) {
if (tolower((unsigned char)*p) != *ptr_color)
break;
p++;
ptr_color++;
}
if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_color;
return p;
}
goto error;
}
/* What a mess, there are several possibilities:
*
* a) A.B.C.D:MN
@ -627,15 +726,21 @@ static const char *ecommunity_gettoken(const char *str,
memset(buf, 0, INET_ADDRSTRLEN + 1);
memcpy(buf, str, p - str);
if (dot) {
if (dot == 3) {
/* Parsing A.B.C.D in:
* A.B.C.D:MN
*/
ret = inet_aton(buf, &ip);
if (ret == 0)
goto error;
} else if (dot == 1) {
/* Parsing A.B AS number in:
* A.B:MN
*/
if (!asn_str2asn(buf, &as))
goto error;
} else {
/* ASN */
/* Parsing A AS number in A:MN */
errno = 0;
tmp_as = strtoul(buf, &endptr, 10);
/* 'unsigned long' is a uint64 on 64-bit
@ -653,33 +758,48 @@ static const char *ecommunity_gettoken(const char *str,
} else if (*p == '.') {
if (separator)
goto error;
/* either IP or AS format */
dot++;
if (dot > 4)
if (dot > 1)
ecomm_type = ECOMMUNITY_ENCODE_IP;
if (dot >= 4)
goto error;
} else {
digit = 1;
/* We're past the IP/ASN part */
/* We're past the IP/ASN part,
* or we have a color
*/
if (separator) {
val *= 10;
val += (*p - '0');
val_color_set = false;
} else {
val_color *= 10;
val_color += (*p - '0');
val_color_set = true;
}
}
p++;
}
/* Low digit part must be there. */
if (!digit || !separator)
if (!digit && (!separator || !val_color_set))
goto error;
/* Encode result into extended community. */
if (dot)
ecomm_type = ECOMMUNITY_ENCODE_IP;
else if (as > BGP_AS_MAX)
ecomm_type = ECOMMUNITY_ENCODE_AS4;
else
ecomm_type = ECOMMUNITY_ENCODE_AS;
if (ecommunity_encode(ecomm_type, 0, 1, as, ip, val, eval))
if (ecomm_type != ECOMMUNITY_ENCODE_IP) {
/* Encode result into extended community for AS format or color. */
if (as > BGP_AS_MAX)
ecomm_type = ECOMMUNITY_ENCODE_AS4;
else if (as > 0)
ecomm_type = ECOMMUNITY_ENCODE_AS;
else if (val_color) {
ecomm_type = ECOMMUNITY_ENCODE_OPAQUE;
sub_type = ECOMMUNITY_COLOR;
val = val_color;
}
}
if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval))
goto error;
*token = ecommunity_token_val;
return p;
@ -700,11 +820,13 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,
if (is_ipv6_extcomm)
token = ecommunity_token_rt6;
while ((str = ecommunity_gettoken(str, (void *)&eval, &token))) {
while ((str = ecommunity_gettoken(str, (void *)&eval, &token, type))) {
switch (token) {
case ecommunity_token_rt:
case ecommunity_token_nt:
case ecommunity_token_rt6:
case ecommunity_token_soo:
case ecommunity_token_color:
if (!keyword_included || keyword) {
if (ecom)
ecommunity_free(&ecom);
@ -713,12 +835,14 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,
keyword = 1;
if (token == ecommunity_token_rt ||
token == ecommunity_token_rt6) {
token == ecommunity_token_rt6)
type = ECOMMUNITY_ROUTE_TARGET;
}
if (token == ecommunity_token_soo) {
if (token == ecommunity_token_soo)
type = ECOMMUNITY_SITE_ORIGIN;
}
if (token == ecommunity_token_nt)
type = ECOMMUNITY_NODE_TARGET;
if (token == ecommunity_token_color)
type = ECOMMUNITY_COLOR;
break;
case ecommunity_token_val:
if (keyword_included) {
@ -901,10 +1025,6 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
uint32_t bw_tmp, bw;
char bps_buf[20] = {0};
#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
#define ONE_MBPS_BYTES (1000 * 1000 / 8)
#define ONE_KBPS_BYTES (1000 / 8)
as = (*pnt++ << 8);
as |= (*pnt++);
(void)ptr_get_be32(pnt, &bw_tmp);
@ -928,27 +1048,87 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
return len;
}
static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
size_t length)
{
int len = 0;
as_t as = 0;
uint64_t bw = 0;
char bps_buf[20] = { 0 };
if (length < IPV6_ECOMMUNITY_SIZE)
goto done;
pnt += 2; /* Reserved */
pnt = ptr_get_be64(pnt, &bw);
(void)ptr_get_be32(pnt, &as);
if (bw >= ONE_GBPS_BYTES)
snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps",
(float)(bw / ONE_GBPS_BYTES));
else if (bw >= ONE_MBPS_BYTES)
snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps",
(float)(bw / ONE_MBPS_BYTES));
else if (bw >= ONE_KBPS_BYTES)
snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps",
(float)(bw / ONE_KBPS_BYTES));
else
snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8);
done:
len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf);
return len;
}
bool ecommunity_has_route_target(struct ecommunity *ecom)
{
uint32_t i;
uint8_t *pnt;
uint8_t type = 0;
uint8_t sub_type = 0;
if (!ecom)
return false;
for (i = 0; i < ecom->size; i++) {
/* Retrieve value field */
pnt = ecom->val + (i * ecom->unit_size);
/* High-order octet is the type */
type = *pnt++;
if (type == ECOMMUNITY_ENCODE_AS ||
type == ECOMMUNITY_ENCODE_IP ||
type == ECOMMUNITY_ENCODE_AS4) {
/* Low-order octet of type. */
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_ROUTE_TARGET)
return true;
}
}
return false;
}
/* Convert extended community attribute to string.
Due to historical reason of industry standard implementation, there
are three types of format.
route-map set extcommunity format
"rt 100:1 100:2soo 100:3"
extcommunity-list
"rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
"RT:100:1 RT:100:2 SoO:100:3"
For each formath please use below definition for format:
ECOMMUNITY_FORMAT_ROUTE_MAP
ECOMMUNITY_FORMAT_COMMUNITY_LIST
ECOMMUNITY_FORMAT_DISPLAY
Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
0 value displays all
*/
* Due to historical reason of industry standard implementation, there
* are three types of format:
*
* route-map set extcommunity format:
* "rt 100:1 100:2soo 100:3"
*
* extcommunity-list:
* "rt 100:1 rt 100:2 soo 100:3"
*
* show bgp:
* "RT:100:1 RT:100:2 SoO:100:3"
*
* For each format please use below definition for format:
* ECOMMUNITY_FORMAT_ROUTE_MAP
* ECOMMUNITY_FORMAT_COMMUNITY_LIST
* ECOMMUNITY_FORMAT_DISPLAY
*
* Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
* 0 value displays all.
*/
char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
{
uint32_t i;
@ -968,7 +1148,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char encbuf[128];
for (i = 0; i < ecom->size; i++) {
int unk_ecom = 0;
bool unk_ecom = false;
memset(encbuf, 0x00, sizeof(encbuf));
/* Space between each value. */
@ -978,6 +1158,18 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
/* Retrieve value field */
pnt = ecom->val + (i * ecom->unit_size);
uint8_t *data = pnt;
uint8_t *end = data + ecom->unit_size;
size_t len = end - data;
/* Sanity check for extended communities lenght, to avoid
* overrun when dealing with bits, e.g. ptr_get_be64().
*/
if (len < ecom->unit_size) {
unk_ecom = true;
goto unknown;
}
/* High-order octet is the type */
type = *pnt++;
@ -1000,8 +1192,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecommunity_lb_str(
encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
} else if (sub_type ==
ECOMMUNITY_EXTENDED_LINK_BANDWIDTH &&
type == ECOMMUNITY_ENCODE_AS4) {
ipv6_ecommunity_lb_str(encbuf,
sizeof(encbuf),
pnt, len);
} else if (sub_type == ECOMMUNITY_NODE_TARGET &&
type == ECOMMUNITY_ENCODE_IP) {
ecommunity_node_target_str(
encbuf, sizeof(encbuf), pnt,
format);
} else
unk_ecom = 1;
unk_ecom = true;
} else {
ecommunity_rt_soo_str(encbuf, sizeof(encbuf),
pnt, type, sub_type,
@ -1020,8 +1223,11 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
strlcpy(encbuf, "Default Gateway",
sizeof(encbuf));
} else if (*pnt == ECOMMUNITY_COLOR) {
ecommunity_color_str(encbuf, sizeof(encbuf),
pnt);
} else {
unk_ecom = 1;
unk_ecom = true;
}
} else if (type == ECOMMUNITY_ENCODE_EVPN) {
if (filter == ECOMMUNITY_ROUTE_TARGET)
@ -1087,11 +1293,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
== ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) {
uint8_t flags = *++pnt;
snprintf(encbuf,
sizeof(encbuf), "ESI-label-Rt:%s",
(flags &
ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ?
"SA":"AA");
snprintf(encbuf, sizeof(encbuf),
"ESI-label-Rt:%s",
CHECK_FLAG(flags,
ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG)
? "SA"
: "AA");
} else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) {
uint8_t alg;
@ -1114,14 +1321,14 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
"DF: (alg: %u, pref: %u)", alg,
pref);
} else
unk_ecom = 1;
unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
snprintf(encbuf, sizeof(encbuf),
"FS:redirect IP 0x%x", *(pnt + 5));
} else
unk_ecom = 1;
unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
@ -1131,44 +1338,43 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char buf[ECOMMUNITY_STRLEN];
memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str_internal(buf, sizeof(buf),
(const uint8_t *)pnt,
type &
~ECOMMUNITY_ENCODE_TRANS_EXP,
ECOMMUNITY_ROUTE_TARGET,
format,
ecom->unit_size);
ecommunity_rt_soo_str_internal(
buf, sizeof(buf), (const uint8_t *)pnt,
CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET, format,
ecom->unit_size);
snprintf(encbuf, sizeof(encbuf), "%s", buf);
} else if (sub_type ==
ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) {
char buf[64];
memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str_internal(buf, sizeof(buf),
(const uint8_t *)pnt,
type &
~ECOMMUNITY_ENCODE_TRANS_EXP,
ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY,
ecom->unit_size);
ecommunity_rt_soo_str_internal(
buf, sizeof(buf), (const uint8_t *)pnt,
CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY,
ecom->unit_size);
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
} else if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
char buf[16];
memset(buf, 0, sizeof(buf));
ecommunity_rt_soo_str(buf, sizeof(buf),
(const uint8_t *)pnt,
type &
~ECOMMUNITY_ENCODE_TRANS_EXP,
ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY);
ecommunity_rt_soo_str(
buf, sizeof(buf), (const uint8_t *)pnt,
CHECK_FLAG(type,
~ECOMMUNITY_ENCODE_TRANS_EXP),
ECOMMUNITY_ROUTE_TARGET,
ECOMMUNITY_FORMAT_DISPLAY);
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
} else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
unk_ecom = 1;
unk_ecom = true;
else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
char action[64];
@ -1201,26 +1407,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
snprintf(encbuf, sizeof(encbuf),
"FS:marking %u", *(pnt + 5));
} else
unk_ecom = 1;
unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
ecommunity_lb_str(encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH)
ipv6_ecommunity_lb_str(encbuf, sizeof(encbuf),
pnt, len);
else
unk_ecom = 1;
unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_NODE_TARGET)
ecommunity_node_target_str(
encbuf, sizeof(encbuf), pnt, format);
else
unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
ecommunity_origin_validation_state_str(
encbuf, sizeof(encbuf), pnt);
else
unk_ecom = 1;
unk_ecom = true;
} else {
sub_type = *pnt++;
unk_ecom = 1;
unk_ecom = true;
}
unknown:
if (unk_ecom)
snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type,
sub_type);
@ -1280,6 +1497,29 @@ bool ecommunity_match(const struct ecommunity *ecom1,
return false;
}
/* return last occurence of color */
/* it will be the greatest color value */
extern uint32_t ecommunity_select_color(const struct ecommunity *ecom)
{
uint32_t aux_color = 0;
uint8_t *p;
uint32_t c = 0;
/* If the value already exists in the structure return 0. */
for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) {
if (p == NULL)
break;
if (p[0] == ECOMMUNITY_ENCODE_OPAQUE &&
p[1] == ECOMMUNITY_COLOR)
ptr_get_be32((const uint8_t *)&p[4], &aux_color);
}
return aux_color;
}
/* return first occurence of type */
extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
uint8_t type, uint8_t subtype)
@ -1400,12 +1640,13 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
api->action = ACTION_TRAFFIC_ACTION;
/* else distribute code is set by default */
if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
if (CHECK_FLAG(ecom_eval->val[5],
(1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)))
SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_TERMINATE);
else
api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE;
SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_DISTRIBUTE);
if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
api->u.za.filter |= TRAFFIC_ACTION_SAMPLE;
SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_SAMPLE);
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
api->action = ACTION_MARKING;
@ -1429,8 +1670,8 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
* in the 'Network Address of Next- Hop'
* field of the associated MP_REACH_NLRI.
*/
struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *)
ecom_eval + 2;
struct ecommunity_ip *ip_ecom =
(struct ecommunity_ip *)&ecom_eval->val[2];
api->u.zr.redirect_ip_v4 = ip_ecom->ip;
} else
@ -1614,9 +1855,9 @@ ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
* return the BGP link bandwidth extended community, if present;
* the actual bandwidth is returned via param
*/
const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw)
{
const uint8_t *eval;
const uint8_t *data;
uint32_t i;
if (bw)
@ -1628,24 +1869,49 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
for (i = 0; i < ecom->size; i++) {
const uint8_t *pnt;
uint8_t type, sub_type;
uint32_t bwval;
eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
data = pnt = (ecom->val + (i * ecom->unit_size));
type = *pnt++;
sub_type = *pnt++;
const uint8_t *end = data + ecom->unit_size;
size_t len = end - data;
/* Sanity check for extended communities lenght, to avoid
* overrun when dealing with bits, e.g. ptr_get_be64().
*/
if (len < ecom->unit_size)
return NULL;
if ((type == ECOMMUNITY_ENCODE_AS ||
type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
uint32_t bwval;
pnt += 2; /* bandwidth is encoded as AS:val */
pnt = ptr_get_be32(pnt, &bwval);
(void)pnt; /* consume value */
if (bw)
*bw = ecom->disable_ieee_floating
? bwval
: ieee_float_uint32_to_uint32(
bwval);
return eval;
*bw = (uint64_t)(ecom->disable_ieee_floating
? bwval
: ieee_float_uint32_to_uint32(
bwval));
return data;
} else if (type == ECOMMUNITY_ENCODE_AS4 &&
sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) {
uint64_t bwval;
if (len < IPV6_ECOMMUNITY_SIZE)
return NULL;
pnt += 2; /* Reserved */
pnt = ptr_get_be64(pnt, &bwval);
(void)pnt;
if (bw)
*bw = bwval;
return data;
}
}
@ -1655,13 +1921,13 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
uint64_t cum_bw,
bool disable_ieee_floating)
bool disable_ieee_floating,
bool extended)
{
struct ecommunity *new;
struct ecommunity_val lb_eval;
const uint8_t *eval;
uint8_t type;
uint32_t cur_bw;
uint64_t cur_bw;
/* Nothing to replace if link-bandwidth doesn't exist or
* is non-transitive - just return existing extcommunity.
@ -1675,7 +1941,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
return new;
type = *eval;
if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE)
if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE))
return new;
/* Transitive link-bandwidth exists, replace with the passed
@ -1685,10 +1951,36 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
*/
if (cum_bw > 0xFFFFFFFF)
cum_bw = 0xFFFFFFFF;
encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false,
&lb_eval, disable_ieee_floating);
new = ecommunity_dup(ecom);
ecommunity_add_val(new, &lb_eval, true, true);
if (extended) {
struct ecommunity_val_ipv6 lb_eval;
encode_lb_extended_extcomm(as, cum_bw, false, &lb_eval);
new = ecommunity_dup(ecom);
ecommunity_add_val_ipv6(new, &lb_eval, true, true);
} else {
struct ecommunity_val lb_eval;
encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw,
false, &lb_eval, disable_ieee_floating);
new = ecommunity_dup(ecom);
ecommunity_add_val(new, &lb_eval, true, true);
}
return new;
}
bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo)
{
if (ecom && soo) {
if ((ecommunity_lookup(ecom, ECOMMUNITY_ENCODE_AS,
ECOMMUNITY_SITE_ORIGIN) ||
ecommunity_lookup(ecom, ECOMMUNITY_ENCODE_AS4,
ECOMMUNITY_SITE_ORIGIN) ||
ecommunity_lookup(ecom, ECOMMUNITY_ENCODE_IP,
ECOMMUNITY_SITE_ORIGIN)) &&
ecommunity_include(ecom, soo))
return true;
}
return false;
}

View file

@ -10,6 +10,10 @@
#include "bgpd/bgp_rpki.h"
#include "bgpd/bgpd.h"
#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
#define ONE_MBPS_BYTES (1000 * 1000 / 8)
#define ONE_KBPS_BYTES (1000 / 8)
/* Refer to rfc7153 for the IANA registry definitions. These are
* updated by other standards like rfc7674.
*/
@ -46,14 +50,20 @@
#define ECOMMUNITY_REDIRECT_VRF 0x08
#define ECOMMUNITY_TRAFFIC_MARKING 0x09
#define ECOMMUNITY_REDIRECT_IP_NH 0x00
#define ECOMMUNITY_COLOR 0x0b /* RFC9012 - color */
/* from IANA: bgp-extended-communities/bgp-extended-communities.xhtml
* 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect
*/
#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c
/* from draft-ietf-idr-flow-spec-v6-09
* 0x0b Flow-spec Redirect to IPv6
/* RFC 8956 */
#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d
/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01
* Sub-type is allocated by IANA, just the draft is not yet updated with the
* new value.
*/
#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b
#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006
/* Low-order octet of the Extended Communities type field for EVPN types */
#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00
@ -101,6 +111,10 @@ enum ecommunity_origin_validation_states {
/* Extended Community readable string length */
#define ECOMMUNITY_STRLEN 64
/* Node Target Extended Communities */
#define ECOMMUNITY_NODE_TARGET 0x09
#define ECOMMUNITY_NODE_TARGET_RESERVED 0
/* Extended Communities attribute. */
struct ecommunity {
/* Reference counter. */
@ -111,6 +125,9 @@ struct ecommunity {
*/
uint8_t unit_size;
/* Disable IEEE floating-point encoding for extended community */
bool disable_ieee_floating;
/* Size of Extended Communities attribute. */
uint32_t size;
@ -119,9 +136,6 @@ struct ecommunity {
/* Human readable format string. */
char *str;
/* Disable IEEE floating-point encoding for extended community */
bool disable_ieee_floating;
};
struct ecommunity_as {
@ -141,12 +155,12 @@ struct ecommunity_ip6 {
/* Extended community value is eight octet. */
struct ecommunity_val {
char val[ECOMMUNITY_SIZE];
uint8_t val[ECOMMUNITY_SIZE];
};
/* IPv6 Extended community value is eight octet. */
struct ecommunity_val_ipv6 {
char val[IPV6_ECOMMUNITY_SIZE];
uint8_t val[IPV6_ECOMMUNITY_SIZE];
};
#define ecom_length_size(X, Y) ((X)->size * (Y))
@ -155,9 +169,12 @@ struct ecommunity_val_ipv6 {
* Encode BGP Route Target AS:nn.
*/
static inline void encode_route_target_as(as_t as, uint32_t val,
struct ecommunity_val *eval)
struct ecommunity_val *eval,
bool trans)
{
eval->val[0] = ECOMMUNITY_ENCODE_AS;
if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
eval->val[2] = (as >> 8) & 0xff;
eval->val[3] = as & 0xff;
@ -170,12 +187,15 @@ static inline void encode_route_target_as(as_t as, uint32_t val,
/*
* Encode BGP Route Target IP:nn.
*/
static inline void encode_route_target_ip(struct in_addr ip, uint16_t val,
struct ecommunity_val *eval)
static inline void encode_route_target_ip(struct in_addr *ip, uint16_t val,
struct ecommunity_val *eval,
bool trans)
{
eval->val[0] = ECOMMUNITY_ENCODE_IP;
if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
memcpy(&eval->val[2], &ip, sizeof(struct in_addr));
memcpy(&eval->val[2], ip, sizeof(struct in_addr));
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
@ -184,9 +204,12 @@ static inline void encode_route_target_ip(struct in_addr ip, uint16_t val,
* Encode BGP Route Target AS4:nn.
*/
static inline void encode_route_target_as4(as_t as, uint16_t val,
struct ecommunity_val *eval)
struct ecommunity_val *eval,
bool trans)
{
eval->val[0] = ECOMMUNITY_ENCODE_AS4;
if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
eval->val[2] = (as >> 24) & 0xff;
eval->val[3] = (as >> 16) & 0xff;
@ -211,12 +234,13 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u)
* Encode BGP Link Bandwidth extended community
* bandwidth (bw) is in bytes-per-sec
*/
static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
static inline void encode_lb_extcomm(as_t as, uint64_t bw, bool non_trans,
struct ecommunity_val *eval,
bool disable_ieee_floating)
{
uint32_t bandwidth =
disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw);
uint64_t bandwidth = disable_ieee_floating
? bw
: uint32_to_ieee_float_uint32(bw);
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_AS;
@ -231,6 +255,33 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
eval->val[7] = bandwidth & 0xff;
}
/*
* Encode BGP Link Bandwidth inside IPv6 Extended Community,
* bandwidth is in bytes per second.
*/
static inline void encode_lb_extended_extcomm(as_t as, uint64_t bandwidth,
bool non_trans,
struct ecommunity_val_ipv6 *eval)
{
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_AS4;
if (non_trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
eval->val[1] = ECOMMUNITY_EXTENDED_LINK_BANDWIDTH;
eval->val[4] = (bandwidth >> 56) & 0xff;
eval->val[5] = (bandwidth >> 48) & 0xff;
eval->val[6] = (bandwidth >> 40) & 0xff;
eval->val[7] = (bandwidth >> 32) & 0xff;
eval->val[8] = (bandwidth >> 24) & 0xff;
eval->val[9] = (bandwidth >> 16) & 0xff;
eval->val[10] = (bandwidth >> 8) & 0xff;
eval->val[11] = bandwidth & 0xff;
eval->val[12] = (as >> 24) & 0xff;
eval->val[13] = (as >> 16) & 0xff;
eval->val[14] = (as >> 8) & 0xff;
eval->val[15] = as & 0xff;
}
static inline void encode_origin_validation_state(enum rpki_states state,
struct ecommunity_val *eval)
{
@ -257,14 +308,62 @@ static inline void encode_origin_validation_state(enum rpki_states state,
eval->val[7] = ovs_state;
}
static inline void encode_node_target(struct in_addr *node_id,
struct ecommunity_val *eval, bool trans)
{
/*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0x01 or 0x41 | Sub-Type(0x09) | Target BGP Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Target BGP Identifier (cont.) | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_IP;
if (!trans)
eval->val[0] |= ECOMMUNITY_ENCODE_IP_NON_TRANS;
eval->val[1] = ECOMMUNITY_NODE_TARGET;
memcpy(&eval->val[2], node_id, sizeof(*node_id));
eval->val[6] = ECOMMUNITY_NODE_TARGET_RESERVED;
eval->val[7] = ECOMMUNITY_NODE_TARGET_RESERVED;
}
/*
* Encode BGP Color extended community
* is's a transitive opaque Extended community (RFC 9012 4.3)
* flag is set to 0
* RFC 9012 14.10: No values have currently been registered.
* 4.3: this field MUST be set to zero by the originator
* and ignored by the receiver;
*
*/
static inline void encode_color(uint32_t color_id, struct ecommunity_val *eval)
{
/*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0x03 | Sub-Type(0x0b) | Flags |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Color Value |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
eval->val[1] = ECOMMUNITY_COLOR;
eval->val[2] = 0x00;
eval->val[3] = 0x00;
eval->val[4] = (color_id >> 24) & 0xff;
eval->val[5] = (color_id >> 16) & 0xff;
eval->val[6] = (color_id >> 8) & 0xff;
eval->val[7] = color_id & 0xff;
}
extern void ecommunity_init(void);
extern void ecommunity_finish(void);
extern void ecommunity_free(struct ecommunity **);
extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short,
bool disable_ieee_floating);
extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt,
unsigned short length,
bool disable_ieee_floating);
unsigned short length);
extern struct ecommunity *ecommunity_dup(struct ecommunity *);
extern struct ecommunity *ecommunity_merge(struct ecommunity *,
struct ecommunity *);
@ -277,14 +376,16 @@ extern struct ecommunity *ecommunity_str2com(const char *, int, int);
extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type,
int keyword_included);
extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
extern bool ecommunity_has_route_target(struct ecommunity *ecom);
extern void ecommunity_strfree(char **s);
extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);
extern bool ecommunity_match(const struct ecommunity *,
const struct ecommunity *);
extern char *ecommunity_str(struct ecommunity *);
extern const char *ecommunity_str(struct ecommunity *ecom);
extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,
uint8_t, uint8_t);
extern uint32_t ecommunity_select_color(const struct ecommunity *ecom);
extern bool ecommunity_add_val(struct ecommunity *ecom,
struct ecommunity_val *eval,
bool unique, bool overwrite);
@ -321,11 +422,12 @@ extern void bgp_remove_ecomm_from_aggregate_hash(
struct ecommunity *ecommunity);
extern void bgp_aggr_ecommunity_remove(void *arg);
extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom,
uint32_t *bw);
extern struct ecommunity *ecommunity_replace_linkbw(as_t as,
struct ecommunity *ecom,
uint64_t cum_bw,
bool disable_ieee_floating);
uint64_t *bw);
extern struct ecommunity *
ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw,
bool disable_ieee_floating, bool extended);
extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo);
static inline void ecommunity_strip_rts(struct ecommunity *ecom)
{
@ -338,4 +440,9 @@ static inline void ecommunity_strip_rts(struct ecommunity *ecom)
extern struct ecommunity *
ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
struct ecommunity *ecom);
extern struct ecommunity *ecommunity_add_node_target(struct in_addr *node_id,
struct ecommunity *old,
bool non_trans);
extern bool ecommunity_node_target_match(struct ecommunity *ecomm,
struct in_addr *local_id);
#endif /* _QUAGGA_BGP_ECOMMUNITY_H */

File diff suppressed because it is too large Load diff

View file

@ -51,15 +51,15 @@ get_route_parent_evpn(struct bgp_path_info *ri)
struct bgp_path_info *parent_ri;
/* If not imported (or doesn't have a parent), bail. */
if (ri->sub_type != BGP_ROUTE_IMPORTED ||
!ri->extra ||
!ri->extra->parent)
if (ri->sub_type != BGP_ROUTE_IMPORTED || !ri->extra ||
!ri->extra->vrfleak || !ri->extra->vrfleak->parent)
return NULL;
/* Determine parent recursively */
for (parent_ri = ri->extra->parent;
parent_ri->extra && parent_ri->extra->parent;
parent_ri = parent_ri->extra->parent)
for (parent_ri = ri->extra->vrfleak->parent;
parent_ri->extra && parent_ri->extra->vrfleak &&
parent_ri->extra->vrfleak->parent;
parent_ri = parent_ri->extra->vrfleak->parent)
;
return parent_ri;
@ -94,32 +94,6 @@ static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
}
/* Flag if the route is injectable into EVPN. This would be either a
* non-imported route or a non-EVPN imported route.
*/
static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
{
struct bgp_path_info *parent_pi;
struct bgp_table *table;
struct bgp_dest *dest;
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
!pi->extra ||
!pi->extra->parent)
return true;
parent_pi = (struct bgp_path_info *)pi->extra->parent;
dest = parent_pi->net;
if (!dest)
return true;
table = bgp_dest_table(dest);
if (table &&
table->afi == AFI_L2VPN &&
table->safi == SAFI_EVPN)
return false;
return true;
}
static inline bool evpn_resolve_overlay_index(void)
{
struct bgp *bgp = NULL;
@ -141,12 +115,12 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
safi_t safi);
extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels,
extern char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels,
char *buf, int len);
extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json);
extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
const struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels,
mpls_label_t *label, uint8_t num_labels,
struct attr *attr, bool addpath_capable,
uint32_t addpath_tx_id);
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
@ -157,7 +131,16 @@ extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
const struct prefix *p,
struct bgp_path_info *ri);
extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
extern void
bgp_reimport_evpn_routes_upon_macvrf_soo_change(struct bgp *bgp,
struct ecommunity *old_soo,
struct ecommunity *new_soo);
extern void bgp_reimport_evpn_routes_upon_martian_change(
struct bgp *bgp, enum bgp_martian_type martian_type, void *old_martian,
void *new_martian);
extern void
bgp_filter_evpn_routes_upon_martian_change(struct bgp *bgp,
enum bgp_martian_type martian_type);
extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
int state);
@ -170,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct in_addr originator_ip, int filter,
ifindex_t svi_ifindex, bool is_anycast_mac);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
extern void bgp_evpn_instance_down(struct bgp *bgp);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
@ -194,9 +178,21 @@ extern void
bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
void *arg);
extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
uint32_t num_labels);
uint8_t num_labels);
extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi);
extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
struct bgp_path_info *mpinfo);
extern bool is_route_injectable_into_evpn(struct bgp_path_info *pi);
extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi);
extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi,
safi_t safi);
extern enum zclient_send_status evpn_zebra_install(struct bgp *bgp,
struct bgpevpn *vpn,
const struct prefix_evpn *p,
struct bgp_path_info *pi);
extern enum zclient_send_status
evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p, struct bgp_path_info *pi,
bool is_sync);
#endif /* _QUAGGA_BGP_EVPN_H */

File diff suppressed because it is too large Load diff

View file

@ -388,11 +388,6 @@ static inline bool bgp_evpn_attr_is_local_es(struct attr *attr)
return attr ? !!(attr->es_flags & ATTR_ES_IS_LOCAL) : false;
}
static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr)
{
return (attr) ? attr->df_pref : 0;
}
static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es)
{
return (es->flags & BGP_EVPNES_OPER_UP)
@ -423,10 +418,12 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi);
extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni);
extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni);
extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern enum zclient_send_status
bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern enum zclient_send_status
bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p);
extern void bgp_evpn_mh_init(void);
extern void bgp_evpn_mh_finish(void);
void bgp_evpn_vni_es_init(struct bgpevpn *vpn);

View file

@ -162,6 +162,13 @@ struct bgp_evpn_info {
/* EVPN enable - advertise svi macip routes */
int advertise_svi_macip;
/* MAC-VRF Site-of-Origin
* - added to all routes exported from L2VNI
* - Type-2/3 routes with matching SoO not imported into L2VNI
* - Type-2/5 routes with matching SoO not imported into L3VNI
*/
struct ecommunity *soo;
/* PIP feature knob */
bool advertise_pip;
/* PIP IP (sys ip) */
@ -375,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq,
}
static inline void encode_na_flag_extcomm(struct ecommunity_val *eval,
uint8_t na_flag, bool proxy)
bool na_flag, bool proxy)
{
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
@ -574,32 +581,32 @@ evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p,
static inline struct ethaddr *
evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi)
{
assert(local_pi->extra);
return &local_pi->extra->vni_info.mac;
assert(local_pi->extra && local_pi->extra->evpn);
return &local_pi->extra->evpn->vni_info.mac;
}
/* Get IP of path_info prefix */
static inline struct ipaddr *
evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi)
{
assert(local_pi->extra);
return &local_pi->extra->vni_info.ip;
assert(local_pi->extra && local_pi->extra->evpn);
return &local_pi->extra->evpn->vni_info.ip;
}
/* Set MAC of path_info prefix */
static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi,
const struct ethaddr mac)
{
assert(local_pi->extra);
local_pi->extra->vni_info.mac = mac;
assert(local_pi->extra && local_pi->extra->evpn);
local_pi->extra->evpn->vni_info.mac = mac;
}
/* Set IP of path_info prefix */
static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi,
const struct ipaddr ip)
{
assert(local_pi->extra);
local_pi->extra->vni_info.ip = ip;
assert(local_pi->extra && local_pi->extra->evpn);
local_pi->extra->evpn->vni_info.ip = ip;
}
/* Is the IP empty for the RT's dest? */
@ -680,6 +687,8 @@ extern void bgp_evpn_handle_autort_change(struct bgp *bgp);
extern void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw);
extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
int withdraw);
void bgp_evpn_handle_global_macvrf_soo_change(struct bgp *bgp,
struct ecommunity *new_soo);
extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf);
@ -707,7 +716,8 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_path_info **pi);
int vni_list_cmp(void *p1, void *p2);
extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_dest *dest);
struct bgp_dest *dest,
struct bgp_path_info *pi);
extern struct bgp_dest *
bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi,
const struct prefix_evpn *evp, struct prefix_rd *prd,
@ -741,7 +751,7 @@ bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p,
extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp,
struct bgpevpn *vpn,
struct bgp_node *rn,
struct bgp_dest *rn,
struct bgp_path_info *local_pi,
const char *caller);
extern int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,

View file

@ -362,10 +362,11 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
char *ecom_str;
struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
struct bgp *bgp_evpn = NULL;
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
char buf2[ETHER_ADDR_STRLEN];
bgp_evpn = bgp_get_evpn();
json_import_rtl = json_export_rtl = 0;
if (json) {
@ -379,19 +380,26 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
&bgp_vrf->vrf_prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&bgp_vrf->originator_ip);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
json_object_string_add(json, "siteOfOrigin", ecom_str);
ecommunity_strfree(&ecom_str);
}
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
json_object_string_add(json, "advertiseSviMacIp", "n/a");
json_object_string_add(json, "advertisePip",
bgp_vrf->evpn_info->advertise_pip ?
"Enabled" : "Disabled");
json_object_string_addf(json, "sysIP", "%pI4",
&bgp_vrf->evpn_info->pip_ip);
json_object_string_add(json, "sysMac",
prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
buf2, sizeof(buf2)));
json_object_string_add(json, "rmac",
prefix_mac2str(&bgp_vrf->rmac,
buf2, sizeof(buf2)));
if (bgp_vrf->evpn_info) {
json_object_string_add(json, "advertisePip",
bgp_vrf->evpn_info->advertise_pip
? "Enabled"
: "Disabled");
json_object_string_addf(json, "sysIP", "%pI4",
&bgp_vrf->evpn_info->pip_ip);
json_object_string_addf(json, "sysMac", "%pEA",
&bgp_vrf->evpn_info->pip_rmac);
}
json_object_string_addf(json, "rmac", "%pEA", &bgp_vrf->rmac);
} else {
vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
vty_out(vty, " (known to the kernel)");
@ -406,18 +414,26 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n",
&bgp_vrf->originator_ip);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " MAC-VRF Site-of-Origin: %s\n",
ecom_str);
ecommunity_strfree(&ecom_str);
}
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
vty_out(vty, " Advertise-svi-macip : %s\n", "n/a");
vty_out(vty, " Advertise-pip: %s\n",
bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No");
vty_out(vty, " System-IP: %pI4\n",
&bgp_vrf->evpn_info->pip_ip);
vty_out(vty, " System-MAC: %s\n",
prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
buf2, sizeof(buf2)));
vty_out(vty, " Router-MAC: %s\n",
prefix_mac2str(&bgp_vrf->rmac,
buf2, sizeof(buf2)));
if (bgp_vrf->evpn_info) {
vty_out(vty, " Advertise-pip: %s\n",
bgp_vrf->evpn_info->advertise_pip ? "Yes"
: "No");
vty_out(vty, " System-IP: %pI4\n",
&bgp_vrf->evpn_info->pip_ip);
vty_out(vty, " System-MAC: %pEA\n",
&bgp_vrf->evpn_info->pip_rmac);
}
vty_out(vty, " Router-MAC: %pEA\n", &bgp_vrf->rmac);
}
if (!json)
@ -433,7 +449,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
else
vty_out(vty, " %s\n", ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
}
if (json)
@ -451,7 +467,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
else
vty_out(vty, " %s\n", ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
}
if (json)
@ -484,6 +500,13 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
&vpn->originator_ip);
json_object_string_addf(json, "mcastGroup", "%pI4",
&vpn->mcast_grp);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
json_object_string_add(json, "siteOfOrigin", ecom_str);
ecommunity_strfree(&ecom_str);
}
/* per vni knob is enabled -- Enabled
* Global knob is enabled -- Active
* default -- Disabled
@ -499,6 +522,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_string_add(json, "advertiseGatewayMacip",
"Disabled");
if (!vpn->advertise_svi_macip && bgp_evpn &&
bgp_evpn->evpn_info &&
bgp_evpn->evpn_info->advertise_svi_macip)
json_object_string_add(json, "advertiseSviMacIp",
"Active");
@ -525,6 +549,14 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n", &vpn->originator_ip);
vty_out(vty, " Mcast group: %pI4\n", &vpn->mcast_grp);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " MAC-VRF Site-of-Origin: %s\n",
ecom_str);
ecommunity_strfree(&ecom_str);
}
if (!vpn->advertise_gw_macip &&
bgp_evpn && bgp_evpn->advertise_gw_macip)
vty_out(vty, " Advertise-gw-macip : %s\n",
@ -536,6 +568,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
vty_out(vty, " Advertise-gw-macip : %s\n",
"Disabled");
if (!vpn->advertise_svi_macip && bgp_evpn &&
bgp_evpn->evpn_info &&
bgp_evpn->evpn_info->advertise_svi_macip)
vty_out(vty, " Advertise-svi-macip : %s\n",
"Active");
@ -562,7 +595,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
else
vty_out(vty, " %s\n", ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
}
if (json)
@ -580,7 +613,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
else
vty_out(vty, " %s\n", ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
}
if (json)
@ -681,7 +714,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
json_object *json, int detail,
bool global_table)
{
struct bgp_node *rn;
struct bgp_dest *bd;
struct bgp_path_info *pi;
int header = detail ? 0 : 1;
uint32_t path_cnt;
@ -714,7 +747,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
json_object *json_path = NULL;
pi = es_info->pi;
rn = pi->net;
bd = pi->net;
if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
continue;
@ -732,11 +765,11 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
if (detail)
route_vty_out_detail(
vty, bgp, rn, bgp_dest_get_prefix(rn),
vty, bgp, bd, bgp_dest_get_prefix(bd),
pi, AFI_L2VPN, SAFI_EVPN,
RPKI_NOT_BEING_USED, json_path);
else
route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN,
json_path, false);
if (json)
@ -981,10 +1014,13 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
char *ecom_str;
struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
struct bgp *bgp_evpn;
if (!bgp->l3vni)
return;
bgp_evpn = bgp_get_evpn();
if (json) {
json_vni = json_object_new_object();
json_import_rtl = json_object_new_array();
@ -1041,7 +1077,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
vty_out(vty, " %-25s", rt_buf);
}
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
/* If there are multiple import RTs we break here and show only
* one */
@ -1069,12 +1105,19 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
vty_out(vty, " %-25s", rt_buf);
}
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
ecommunity_strfree(&ecom_str);
/* If there are multiple export RTs we break here and show only
* one */
if (!json) {
vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id));
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " %-25s", ecom_str);
ecommunity_strfree(&ecom_str);
}
vty_out(vty, " %-37s", vrf_id_to_name(bgp->vrf_id));
break;
}
}
@ -1083,11 +1126,18 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
char vni_str[VNI_STR_LEN];
json_object_object_add(json_vni, "exportRTs", json_export_rtl);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
json_object_string_add(json_vni, "siteOfOrigin",
ecom_str);
ecommunity_strfree(&ecom_str);
}
snprintf(vni_str, sizeof(vni_str), "%u", bgp->l3vni);
json_object_object_add(json, vni_str, json_vni);
} else {
} else
vty_out(vty, "\n");
}
}
static void show_vni_entry(struct hash_bucket *bucket, void *args[])
@ -1213,7 +1263,14 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
/* If there are multiple export RTs we break here and show only
* one */
if (!json) {
vty_out(vty, "%-37s",
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " %-25s", ecom_str);
ecommunity_strfree(&ecom_str);
}
vty_out(vty, " %-37s",
vrf_id_to_name(vpn->tenant_vrf_id));
break;
}
@ -1223,11 +1280,18 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
char vni_str[VNI_STR_LEN];
json_object_object_add(json_vni, "exportRTs", json_export_rtl);
if (bgp_evpn && bgp_evpn->evpn_info) {
ecom_str = ecommunity_ecom2str(
bgp_evpn->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
json_object_string_add(json_vni, "siteOfOrigin",
ecom_str);
ecommunity_strfree(&ecom_str);
}
snprintf(vni_str, sizeof(vni_str), "%u", vpn->vni);
json_object_object_add(json, vni_str, json_vni);
} else {
} else
vty_out(vty, "\n");
}
}
static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
@ -2017,12 +2081,12 @@ DEFUN(evpnrt5_network,
int idx_ethtag = 5;
int idx_routermac = 13;
return bgp_static_set_safi(
AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
argv[idx_route_distinguisher]->arg, argv[idx_label]->arg, NULL,
BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
argv[idx_routermac]->arg);
return bgp_static_set(vty, false, argv[idx_ipv4_prefixlen]->arg,
argv[idx_route_distinguisher]->arg,
argv[idx_label]->arg, AFI_L2VPN, SAFI_EVPN, NULL,
0, 0, BGP_EVPN_IP_PREFIX_ROUTE,
argv[idx_esi]->arg, argv[idx_gwip]->arg,
argv[idx_ethtag]->arg, argv[idx_routermac]->arg);
}
/* For testing purpose, static route of EVPN RT-5. */
@ -2049,11 +2113,12 @@ DEFUN(no_evpnrt5_network,
int idx_ethtag = 6;
int idx_esi = 10;
int idx_gwip = 12;
return bgp_static_unset_safi(
AFI_L2VPN, SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg,
argv[idx_ext_community]->arg, argv[idx_label]->arg,
BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
argv[idx_gwip]->arg, argv[idx_ethtag]->arg);
return bgp_static_set(vty, true, argv[idx_ipv4_prefixlen]->arg,
argv[idx_ext_community]->arg,
argv[idx_label]->arg, AFI_L2VPN, SAFI_EVPN, NULL,
0, 0, BGP_EVPN_IP_PREFIX_ROUTE, argv[idx_esi]->arg,
argv[idx_gwip]->arg, argv[idx_ethtag]->arg, NULL);
}
static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
@ -2228,9 +2293,12 @@ static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd,
*/
bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
if (bgp_vrf->vrf_prd_pretty)
XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty);
/* update RD */
memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty);
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
/* We have a new RD for VRF.
@ -2253,7 +2321,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
if (bgp_vrf->vrf_prd_pretty)
XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty);
XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty);
/* We have a new RD for VRF.
* Advertise all type-5 routes again with the new RD
*/
@ -2275,7 +2343,7 @@ static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
/* update RD */
memcpy(&vpn->prd, rd, sizeof(struct prefix_rd));
vpn->prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
vpn->prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty);
SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
if (is_vni_live(vpn))
@ -2493,7 +2561,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
NULL, afi, safi, json, false);
NULL, afi, safi, json, false, true);
/* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
@ -2595,7 +2663,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
afi, safi, json, false);
afi, safi, json, false, true);
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
@ -2619,16 +2687,16 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
*/
if (is_evpn_prefix_ipaddr_none(evp)) {
/* VNI MAC -> Global */
evpn_type2_prefix_global_copy(
(struct prefix_evpn *)&tmp_p, evp,
NULL /* mac */,
evpn_type2_path_info_get_ip(pi));
evpn_type2_prefix_global_copy(&tmp_p, evp,
NULL /* mac */,
evpn_type2_path_info_get_ip(
pi));
} else {
/* VNI IP -> Global */
evpn_type2_prefix_global_copy(
(struct prefix_evpn *)&tmp_p, evp,
evpn_type2_path_info_get_mac(pi),
NULL /* ip */);
evpn_type2_prefix_global_copy(&tmp_p, evp,
evpn_type2_path_info_get_mac(
pi),
NULL /* ip */);
}
route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p,
@ -2730,7 +2798,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
prd, afi, safi, json, false);
prd, afi, safi, json, false, false);
if (json)
json_paths = json_object_new_array();
@ -2752,9 +2820,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
path_cnt++;
}
if (json && path_cnt) {
if (json) {
if (path_cnt)
json_object_object_addf(json, json_paths, "%pFX", &p);
json_object_object_add(json, "paths", json_paths);
json_object_int_add(json, "numPaths", path_cnt);
} else {
vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
@ -2837,9 +2905,10 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
}
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(
vty, bgp, dest, bgp_dest_get_prefix(dest), prd,
afi, safi, json_prefix, false);
route_vty_out_detail_header(vty, bgp, dest,
bgp_dest_get_prefix(dest),
prd, afi, safi, json_prefix,
false, false);
prefix_cnt++;
}
@ -2974,9 +3043,10 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
p->prefixlen);
} else
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(
vty, bgp, dest, p, (struct prefix_rd *)rd_destp,
AFI_L2VPN, SAFI_EVPN, json_prefix, false);
route_vty_out_detail_header(vty, bgp, dest, p,
(struct prefix_rd *)rd_destp,
AFI_L2VPN, SAFI_EVPN,
json_prefix, false, false);
/* For EVPN, the prefix is displayed for each path (to
* fit in with code that already exists).
@ -3129,11 +3199,14 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* Prefix and num paths displayed once per prefix. */
if (detail)
route_vty_out_detail_header(
vty, bgp, dest,
bgp_dest_get_prefix(dest),
(struct prefix_rd *)rd_destp, AFI_L2VPN,
SAFI_EVPN, json_prefix, false);
route_vty_out_detail_header(vty, bgp, dest,
bgp_dest_get_prefix(
dest),
(struct prefix_rd *)
rd_destp,
AFI_L2VPN, SAFI_EVPN,
json_prefix, false,
false);
/* For EVPN, the prefix is displayed for each path (to
* fit in
@ -3217,7 +3290,14 @@ int bgp_evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
evpn_show_all_routes(vty, bgp, type, json, detail, false);
if (use_json)
vty_json(vty, json);
/*
* We are using no_pretty here because under extremely high
* settings (lots of routes with many different paths) this can
* save several minutes of output when FRR is run on older cpu's
* or more underperforming routers out there. So for route
* scale, we need to use no_pretty json.
*/
vty_json_no_pretty(vty, json);
return CMD_SUCCESS;
}
@ -3269,8 +3349,9 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
if (!json) {
vty_out(vty, "Flags: * - Kernel\n");
vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
"Type", "RD", "Import RT", "Export RT", "Tenant VRF");
vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-25s %-37s\n",
"VNI", "Type", "RD", "Import RT", "Export RT",
"MAC-VRF Site-of-Origin", "Tenant VRF");
}
/* print all L2 VNIS */
@ -3916,6 +3997,58 @@ DEFPY(bgp_evpn_advertise_svi_ip_vni,
return CMD_SUCCESS;
}
DEFPY(macvrf_soo_global, macvrf_soo_global_cmd,
"mac-vrf soo ASN:NN_OR_IP-ADDRESS:NN$soo",
"EVPN MAC-VRF\n"
"Site-of-Origin extended community\n"
"VPN extended community\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
struct bgp *bgp_evpn = bgp_get_evpn();
struct ecommunity *ecomm_soo;
if (!bgp || !bgp_evpn || !bgp_evpn->evpn_info)
return CMD_WARNING;
if (bgp != bgp_evpn) {
vty_out(vty,
"%% Please configure MAC-VRF SoO in the EVPN underlay: %s\n",
bgp_evpn->name_pretty);
return CMD_WARNING_CONFIG_FAILED;
}
ecomm_soo = ecommunity_str2com(soo, ECOMMUNITY_SITE_ORIGIN, 0);
if (!ecomm_soo) {
vty_out(vty, "%% Malformed SoO extended community\n");
return CMD_WARNING_CONFIG_FAILED;
}
ecommunity_str(ecomm_soo);
bgp_evpn_handle_global_macvrf_soo_change(bgp_evpn, ecomm_soo);
return CMD_SUCCESS;
}
DEFPY(no_macvrf_soo_global, no_macvrf_soo_global_cmd,
"no mac-vrf soo [ASN:NN_OR_IP-ADDRESS:NN$soo]",
NO_STR
"EVPN MAC-VRF\n"
"Site-of-Origin extended community\n"
"VPN extended community\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
struct bgp *bgp_evpn = bgp_get_evpn();
if (!bgp || !bgp_evpn || !bgp_evpn->evpn_info)
return CMD_WARNING;
if (bgp_evpn)
bgp_evpn_handle_global_macvrf_soo_change(bgp_evpn,
NULL /* new_soo */);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet,
bgp_evpn_advertise_vni_subnet_cmd,
"advertise-subnet",
@ -4712,7 +4845,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
char *vrf = NULL;
char *neighbor = NULL;
as_t as = 0; /* 0 means AS filter not set */
int as_type = AS_UNSPECIFIED;
enum peer_asn_type as_type = AS_UNSPECIFIED;
uint16_t show_flags = 0;
if (argv_find(argv, argc, "vrf", &idx_vrf))
@ -6846,6 +6979,8 @@ DEFUN(bgp_evpn_ead_es_rt, bgp_evpn_ead_es_rt_cmd,
if (!bgp_evpn_rt_matches_existing(bgp_mh_info->ead_es_export_rtl,
ecomadd))
bgp_evpn_mh_config_ead_export_rt(bgp, ecomadd, false);
else
ecommunity_free(&ecomadd);
return CMD_SUCCESS;
}
@ -6883,6 +7018,7 @@ DEFUN(no_bgp_evpn_ead_es_rt, no_bgp_evpn_ead_es_rt_cmd,
}
bgp_evpn_mh_config_ead_export_rt(bgp, ecomdel, true);
ecommunity_free(&ecomdel);
return CMD_SUCCESS;
}
@ -6934,6 +7070,8 @@ DEFUN (bgp_evpn_vni_rt,
/* Do nothing if we already have this import route-target */
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd))
evpn_configure_import_rt(bgp, vpn, ecomadd);
else
ecommunity_free(&ecomadd);
}
/* Add/update the export route-target */
@ -6950,6 +7088,8 @@ DEFUN (bgp_evpn_vni_rt,
/* Do nothing if we already have this export route-target */
if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd))
evpn_configure_export_rt(bgp, vpn, ecomadd);
else
ecommunity_free(&ecomadd);
}
return CMD_SUCCESS;
@ -7057,6 +7197,7 @@ DEFUN (no_bgp_evpn_vni_rt,
}
}
ecommunity_free(&ecomdel);
return CMD_SUCCESS;
}
@ -7151,6 +7292,15 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->evpn_info->advertise_svi_macip)
vty_out(vty, " advertise-svi-ip\n");
if (bgp->evpn_info->soo) {
char *ecom_str;
ecom_str = ecommunity_ecom2str(bgp->evpn_info->soo,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " mac-vrf soo %s\n", ecom_str);
ecommunity_strfree(&ecom_str);
}
if (bgp->resolve_overlay_index)
vty_out(vty, " enable-resolve-overlay-index\n");
@ -7383,6 +7533,8 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_svi_ip_cmd);
install_element(BGP_EVPN_NODE, &macvrf_soo_global_cmd);
install_element(BGP_EVPN_NODE, &no_macvrf_soo_global_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);

View file

@ -15,9 +15,8 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_filter.h"
/* List of AS filter list. */
/* List of AS list. */
struct as_list_list {
struct as_list *head;
struct as_list *tail;
@ -35,30 +34,6 @@ struct as_list_master {
void (*delete_hook)(const char *);
};
/* Element of AS path filter. */
struct as_filter {
struct as_filter *next;
struct as_filter *prev;
enum as_filter_type type;
regex_t *reg;
char *reg_str;
/* Sequence number. */
int64_t seq;
};
/* AS path filter list. */
struct as_list {
char *name;
struct as_list *next;
struct as_list *prev;
struct as_filter *head;
struct as_filter *tail;
};
/* Calculate new sequential number. */
@ -220,7 +195,6 @@ struct as_list *as_list_lookup(const char *name)
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
if (strcmp(aslist->name, name) == 0)
return aslist;
return NULL;
}
@ -231,8 +205,9 @@ static struct as_list *as_list_new(void)
static void as_list_free(struct as_list *aslist)
{
XFREE(MTYPE_AS_STR, aslist->name);
XFREE(MTYPE_AS_LIST, aslist);
XFREE (MTYPE_AS_STR, aslist->name);
XFREE (MTYPE_AS_LIST, aslist);
}
/* Insert new AS list to list of as_list. Each as_list is sorted by
@ -441,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
struct aspath_exclude *ase;
regex_t *regex;
char *regstr;
int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO;
@ -492,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd,
else
as_list_filter_add(aslist, asfilter);
/* init the exclude rule list*/
as_list_list_init(&aslist->exclude_rule);
/* get aspath orphan exclude that are using this acl */
ase = as_exclude_lookup_orphan(alname);
if (ase) {
as_list_list_add_head(&aslist->exclude_rule, ase);
/* set reverse pointer */
ase->exclude_aspath_acl = aslist;
/* set list of aspath excludes using that acl */
while ((ase = as_exclude_lookup_orphan(alname))) {
as_list_list_add_head(&aslist->exclude_rule, ase);
ase->exclude_aspath_acl = aslist;
}
}
return CMD_SUCCESS;
}
@ -512,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
struct aspath_exclude *ase;
char *regstr;
regex_t *regex;
@ -566,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
XFREE(MTYPE_TMP, regstr);
/* put aspath exclude list into orphan */
if (as_list_list_count(&aslist->exclude_rule))
while ((ase = as_list_list_pop(&aslist->exclude_rule)))
as_exclude_set_orphan(ase);
as_list_list_fini(&aslist->exclude_rule);
as_list_filter_delete(aslist, asfilter);
return CMD_SUCCESS;

View file

@ -6,10 +6,42 @@
#ifndef _QUAGGA_BGP_FILTER_H
#define _QUAGGA_BGP_FILTER_H
#include <typesafe.h>
#define ASPATH_SEQ_NUMBER_AUTO -1
enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT };
/* Element of AS path filter. */
struct as_filter {
struct as_filter *next;
struct as_filter *prev;
enum as_filter_type type;
regex_t *reg;
char *reg_str;
/* Sequence number. */
int64_t seq;
};
PREDECL_DLIST(as_list_list);
/* AS path filter list. */
struct as_list {
char *name;
struct as_list *next;
struct as_list *prev;
struct as_filter *head;
struct as_filter *tail;
/* Changes in AS path */
struct as_list_list_head exclude_rule;
};
extern void bgp_filter_init(void);
extern void bgp_filter_reset(void);

View file

@ -189,13 +189,16 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
zlog_info("%s", local_string);
}
/* Process the route. */
if (!withdraw)
if (!withdraw) {
bgp_update(peer, &p, 0, attr, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
NULL, 0, 0, NULL);
else
} else {
bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
BGP_ROUTE_NORMAL, NULL, NULL, 0);
}
XFREE(MTYPE_TMP, temp);
}
return BGP_NLRI_PARSE_OK;
}

View file

@ -185,16 +185,23 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
offset++;
}
/* Prefix length check. */
if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8) {
*error = -1;
return offset;
}
/* When packet overflow occur return immediately. */
if (psize + offset > max_len)
if (psize + offset > max_len) {
*error = -1;
return offset;
}
/* Defensive coding, double-check
* the psize fits in a struct prefix
*/
if (psize > (ssize_t)sizeof(prefix_local.u))
if (psize > (ssize_t)sizeof(prefix_local.u)) {
*error = -1;
return offset;
}
memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
offset += psize;
switch (type) {
@ -298,14 +305,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
break;
mval->value = value;
if (op[5] == 1)
mval->compare_operator |=
OPERATOR_COMPARE_LESS_THAN;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_LESS_THAN);
if (op[6] == 1)
mval->compare_operator |=
OPERATOR_COMPARE_GREATER_THAN;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_GREATER_THAN);
if (op[7] == 1)
mval->compare_operator |=
OPERATOR_COMPARE_EQUAL_TO;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EQUAL_TO);
if (op[1] == 1)
mval->unary_operator = OPERATOR_UNARY_AND;
else
@ -352,8 +359,10 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
*error = 0;
do {
if (loop > BGP_PBR_MATCH_VAL_MAX)
if (loop > BGP_PBR_MATCH_VAL_MAX) {
*error = -2;
return offset;
}
hex2bin(&nlri_ptr[offset], op);
/* if first element, AND bit can not be set */
if (op[1] == 1 && loop == 0)
@ -404,16 +413,16 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
mval->value = value;
if (op[6] == 1) {
/* different from */
mval->compare_operator |=
OPERATOR_COMPARE_LESS_THAN;
mval->compare_operator |=
OPERATOR_COMPARE_GREATER_THAN;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_LESS_THAN);
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_GREATER_THAN);
} else
mval->compare_operator |=
OPERATOR_COMPARE_EQUAL_TO;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EQUAL_TO);
if (op[7] == 1)
mval->compare_operator |=
OPERATOR_COMPARE_EXACT_MATCH;
SET_FLAG(mval->compare_operator,
OPERATOR_COMPARE_EXACT_MATCH);
if (op[1] == 1)
mval->unary_operator =
OPERATOR_UNARY_AND;
@ -458,11 +467,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
case FLOWSPEC_SRC_PREFIX:
bitmask = 0;
if (type == FLOWSPEC_DEST_PREFIX) {
bitmask |= PREFIX_DST_PRESENT;
SET_FLAG(bitmask, PREFIX_DST_PRESENT);
prefix = &bpem->dst_prefix;
prefix_offset = &bpem->dst_prefix_offset;
} else {
bitmask |= PREFIX_SRC_PRESENT;
SET_FLAG(bitmask, PREFIX_SRC_PRESENT);
prefix = &bpem->src_prefix;
prefix_offset = &bpem->src_prefix_offset;
}
@ -482,14 +491,16 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
*/
if (prefix->family == AF_INET
&& prefix->u.prefix4.s_addr == INADDR_ANY)
bpem->match_bitmask_iprule |= bitmask;
SET_FLAG(bpem->match_bitmask_iprule,
bitmask);
else if (prefix->family == AF_INET6
&& !memcmp(&prefix->u.prefix6,
&in6addr_any,
sizeof(struct in6_addr)))
bpem->match_bitmask_iprule |= bitmask;
SET_FLAG(bpem->match_bitmask_iprule,
bitmask);
else
bpem->match_bitmask |= bitmask;
SET_FLAG(bpem->match_bitmask, bitmask);
}
offset += ret;
break;
@ -631,8 +642,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
|| bpem->match_dst_port_num || bpem->match_protocol_num
|| bpem->match_bitmask || bpem->match_flowlabel_num)
bpem->type = BGP_PBR_IPSET;
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
else if (CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_SRC_PRESENT) ||
CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_DST_PRESENT))
/* the extracted policy rule may not need an
* iptables/ipset filtering. check this may not be
* a standard ip rule : permit any to any ( eg)

View file

@ -355,7 +355,8 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
bgp_path_info_extra_get(path);
bool list_began = false;
if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) {
if (extra->flowspec && extra->flowspec->bgp_fs_pbr &&
listcount(extra->flowspec->bgp_fs_pbr)) {
struct listnode *node;
struct bgp_pbr_match_entry *bpme;
struct bgp_pbr_match *bpm;
@ -363,8 +364,8 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
list_bpm = list_new();
vty_out(vty, "\tinstalled in PBR");
for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr,
node, bpme)) {
for (ALL_LIST_ELEMENTS_RO(extra->flowspec->bgp_fs_pbr, node,
bpme)) {
bpm = bpme->backpointer;
if (listnode_lookup(list_bpm, bpm))
continue;
@ -378,13 +379,14 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
}
list_delete(&list_bpm);
}
if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) {
if (extra->flowspec && extra->flowspec->bgp_fs_iprule &&
listcount(extra->flowspec->bgp_fs_iprule)) {
struct listnode *node;
struct bgp_pbr_rule *bpr;
if (!list_began)
vty_out(vty, "\tinstalled in PBR");
for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule,
for (ALL_LIST_ELEMENTS_RO(extra->flowspec->bgp_fs_iprule,
node, bpr)) {
if (!bpr->action)
continue;
@ -545,7 +547,7 @@ static int bgp_fs_local_install_interface(struct bgp *bgp,
return CMD_SUCCESS;
pbr_if = XCALLOC(MTYPE_TMP,
sizeof(struct bgp_pbr_interface));
strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ);
strlcpy(pbr_if->name, ifname, IFNAMSIZ);
RB_INSERT(bgp_pbr_interface_head, head, pbr_if);
*bgp_pbr_interface_any = false;
} else {

File diff suppressed because it is too large Load diff

View file

@ -7,37 +7,38 @@
#ifndef _QUAGGA_BGP_FSM_H
#define _QUAGGA_BGP_FSM_H
enum bgp_fsm_state_progress {
BGP_FSM_FAILURE_AND_DELETE = -2,
BGP_FSM_FAILURE = -1,
BGP_FSM_SUCCESS = 0,
BGP_FSM_SUCCESS_STATE_TRANSFER = 1,
};
/* Macro for BGP read, write and timer thread. */
#define BGP_TIMER_ON(T, F, V) \
do { \
if ((peer->status != Deleted)) \
event_add_timer(bm->master, (F), peer, (V), &(T)); \
if ((connection->status != Deleted)) \
event_add_timer(bm->master, (F), connection, (V), \
&(T)); \
} while (0)
#define BGP_EVENT_ADD(P, E) \
do { \
if ((P)->status != Deleted) \
event_add_event(bm->master, bgp_event, (P), (E), \
NULL); \
#define BGP_EVENT_ADD(C, E) \
do { \
if ((C)->status != Deleted) \
event_add_event(bm->master, bgp_event, (C), (E), NULL); \
} while (0)
#define BGP_EVENT_FLUSH(P) \
do { \
assert(peer); \
event_cancel_event_ready(bm->master, (P)); \
} while (0)
#define BGP_UPDATE_GROUP_TIMER_ON(T, F) \
do { \
if (BGP_SUPPRESS_FIB_ENABLED(peer->bgp) && \
PEER_ROUTE_ADV_DELAY(peer)) \
event_add_timer_msec( \
bm->master, (F), peer, \
(BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * \
1000), \
(T)); \
else \
event_add_timer_msec(bm->master, (F), peer, 0, (T)); \
#define BGP_UPDATE_GROUP_TIMER_ON(T, F) \
do { \
if (BGP_SUPPRESS_FIB_ENABLED(peer->bgp) && \
PEER_ROUTE_ADV_DELAY(peer)) \
event_add_timer_msec(bm->master, (F), connection, \
(BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * \
1000), \
(T)); \
else \
event_add_timer_msec(bm->master, (F), connection, 0, \
(T)); \
} while (0)
#define BGP_MSEC_JITTER 10
@ -105,13 +106,15 @@
/*
* Update FSM for peer based on whether we have valid nexthops or not.
*/
extern void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops);
extern void bgp_fsm_nht_update(struct peer_connection *connection,
struct peer *peer, bool has_valid_nexthops);
extern void bgp_event(struct event *event);
extern int bgp_event_update(struct peer *, enum bgp_fsm_events event);
extern int bgp_stop(struct peer *peer);
extern void bgp_timer_set(struct peer *);
extern int bgp_event_update(struct peer_connection *connection,
enum bgp_fsm_events event);
extern enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection);
extern void bgp_timer_set(struct peer_connection *connection);
extern void bgp_routeadv_timer(struct event *event);
extern void bgp_fsm_change_status(struct peer *peer,
extern void bgp_fsm_change_status(struct peer_connection *connection,
enum bgp_fsm_status status);
extern const char *const peer_down_str[];
extern void bgp_update_delay_end(struct bgp *);
@ -119,6 +122,9 @@ extern void bgp_maxmed_update(struct bgp *);
extern bool bgp_maxmed_onstartup_configured(struct bgp *);
extern bool bgp_maxmed_onstartup_active(struct bgp *);
extern int bgp_fsm_error_subcode(int status);
extern enum bgp_fsm_state_progress
bgp_stop_with_notify(struct peer_connection *connection, uint8_t code,
uint8_t sub_code);
/**
* Start the route advertisement timer (that honors MRAI) for all the
@ -140,11 +146,12 @@ extern void bgp_adjust_routeadv(struct peer *);
DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer));
DECLARE_HOOK(peer_established, (struct peer *peer), (peer));
int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd);
unsigned int bgp_peer_gr_action(struct peer *peer,
int old_peer_state, int new_peer_state);
void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state);
int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd);
int bgp_neighbor_graceful_restart(struct peer *peer,
enum peer_gr_command peer_gr_cmd);
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state,
enum peer_mode new_peer_state);
void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state);
unsigned int bgp_peer_gr_helper_enable(struct peer *peer);
unsigned int bgp_peer_gr_enable(struct peer *peer);
unsigned int bgp_peer_gr_global_inherit(struct peer *peer);
@ -153,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer);
enum global_mode bgp_global_gr_mode_get(struct bgp *bgp);
enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer);
unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer);
int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
enum global_mode global_new_state,
enum global_mode global_old_state);
void bgp_peer_gr_flags_update(struct peer *peer);
const char *print_peer_gr_mode(enum peer_mode pr_mode);
const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);

View file

@ -29,11 +29,11 @@
/* clang-format on */
/* forward declarations */
static uint16_t bgp_write(struct peer *);
static uint16_t bgp_read(struct peer *peer, int *code_p);
static uint16_t bgp_write(struct peer_connection *connection);
static uint16_t bgp_read(struct peer_connection *connection, int *code_p);
static void bgp_process_writes(struct event *event);
static void bgp_process_reads(struct event *event);
static bool validate_header(struct peer *);
static bool validate_header(struct peer_connection *connection);
/* generic i/o status codes */
#define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */
@ -42,65 +42,67 @@ static bool validate_header(struct peer *);
/* Thread external API ----------------------------------------------------- */
void bgp_writes_on(struct peer *peer)
void bgp_writes_on(struct peer_connection *connection)
{
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
assert(peer->status != Deleted);
assert(peer->obuf);
assert(peer->ibuf);
assert(peer->ibuf_work);
assert(!peer->t_connect_check_r);
assert(!peer->t_connect_check_w);
assert(peer->fd);
assert(connection->status != Deleted);
assert(connection->obuf);
assert(connection->ibuf);
assert(connection->ibuf_work);
assert(!connection->t_connect_check_r);
assert(!connection->t_connect_check_w);
assert(connection->fd);
event_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
&peer->t_write);
SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
event_add_write(fpt->master, bgp_process_writes, connection,
connection->fd, &connection->t_write);
SET_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON);
}
void bgp_writes_off(struct peer *peer)
void bgp_writes_off(struct peer_connection *connection)
{
struct peer *peer = connection->peer;
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
event_cancel_async(fpt->master, &peer->t_write, NULL);
EVENT_OFF(peer->t_generate_updgrp_packets);
event_cancel_async(fpt->master, &connection->t_write, NULL);
EVENT_OFF(connection->t_generate_updgrp_packets);
UNSET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
UNSET_FLAG(peer->connection->thread_flags, PEER_THREAD_WRITES_ON);
}
void bgp_reads_on(struct peer *peer)
void bgp_reads_on(struct peer_connection *connection)
{
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
assert(peer->status != Deleted);
assert(peer->ibuf);
assert(peer->fd);
assert(peer->ibuf_work);
assert(peer->obuf);
assert(!peer->t_connect_check_r);
assert(!peer->t_connect_check_w);
assert(peer->fd);
assert(connection->status != Deleted);
assert(connection->ibuf);
assert(connection->fd);
assert(connection->ibuf_work);
assert(connection->obuf);
assert(!connection->t_connect_check_r);
assert(!connection->t_connect_check_w);
assert(connection->fd);
event_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
event_add_read(fpt->master, bgp_process_reads, connection,
connection->fd, &connection->t_read);
SET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
SET_FLAG(connection->thread_flags, PEER_THREAD_READS_ON);
}
void bgp_reads_off(struct peer *peer)
void bgp_reads_off(struct peer_connection *connection)
{
struct frr_pthread *fpt = bgp_pth_io;
assert(fpt->running);
event_cancel_async(fpt->master, &peer->t_read, NULL);
EVENT_OFF(peer->t_process_packet);
EVENT_OFF(peer->t_process_packet_error);
event_cancel_async(fpt->master, &connection->t_read, NULL);
EVENT_OFF(connection->t_process_packet);
EVENT_OFF(connection->t_process_packet_error);
UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
UNSET_FLAG(connection->thread_flags, PEER_THREAD_READS_ON);
}
/* Thread internal functions ----------------------------------------------- */
@ -111,19 +113,21 @@ void bgp_reads_off(struct peer *peer)
static void bgp_process_writes(struct event *thread)
{
static struct peer *peer;
peer = EVENT_ARG(thread);
struct peer_connection *connection = EVENT_ARG(thread);
uint16_t status;
bool reschedule;
bool fatal = false;
if (peer->fd < 0)
peer = connection->peer;
if (connection->fd < 0)
return;
struct frr_pthread *fpt = bgp_pth_io;
frr_with_mutex (&peer->io_mtx) {
status = bgp_write(peer);
reschedule = (stream_fifo_head(peer->obuf) != NULL);
frr_with_mutex (&connection->io_mtx) {
status = bgp_write(connection);
reschedule = (stream_fifo_head(connection->obuf) != NULL);
}
/* no problem */
@ -142,26 +146,26 @@ static void bgp_process_writes(struct event *thread)
* sent in the update message
*/
if (reschedule) {
event_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
&peer->t_write);
event_add_write(fpt->master, bgp_process_writes, connection,
connection->fd, &connection->t_write);
} else if (!fatal) {
BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
BGP_UPDATE_GROUP_TIMER_ON(&connection->t_generate_updgrp_packets,
bgp_generate_updgrp_packets);
}
}
static int read_ibuf_work(struct peer *peer)
static int read_ibuf_work(struct peer_connection *connection)
{
/* static buffer for transferring packets */
/* shorter alias to peer's input buffer */
struct ringbuf *ibw = peer->ibuf_work;
struct ringbuf *ibw = connection->ibuf_work;
/* packet size as given by header */
uint16_t pktsize = 0;
struct stream *pkt;
/* ============================================== */
frr_with_mutex (&peer->io_mtx) {
if (peer->ibuf->count >= bm->inq_limit)
frr_with_mutex (&connection->io_mtx) {
if (connection->ibuf->count >= bm->inq_limit)
return -ENOMEM;
}
@ -170,7 +174,7 @@ static int read_ibuf_work(struct peer *peer)
return 0;
/* check that header is valid */
if (!validate_header(peer))
if (!validate_header(connection))
return -EBADMSG;
/* header is valid; retrieve packet size */
@ -179,7 +183,7 @@ static int read_ibuf_work(struct peer *peer)
pktsize = ntohs(pktsize);
/* if this fails we are seriously screwed */
assert(pktsize <= peer->max_packet_size);
assert(pktsize <= connection->peer->max_packet_size);
/*
* If we have that much data, chuck it into its own
@ -195,9 +199,9 @@ static int read_ibuf_work(struct peer *peer)
assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
stream_set_endp(pkt, pktsize);
frrtrace(2, frr_bgp, packet_read, peer, pkt);
frr_with_mutex (&peer->io_mtx) {
stream_fifo_push(peer->ibuf, pkt);
frrtrace(2, frr_bgp, packet_read, connection->peer, pkt);
frr_with_mutex (&connection->io_mtx) {
stream_fifo_push(connection->ibuf, pkt);
}
return pktsize;
@ -208,30 +212,31 @@ static int read_ibuf_work(struct peer *peer)
* or has hung up.
*
* We read as much data as possible, process as many packets as we can and
* place them on peer->ibuf for secondary processing by the main thread.
* place them on peer->connection.ibuf for secondary processing by the main
* thread.
*/
static void bgp_process_reads(struct event *thread)
{
/* clang-format off */
struct peer_connection *connection = EVENT_ARG(thread);
static struct peer *peer; /* peer to read from */
uint16_t status; /* bgp_read status code */
bool fatal = false; /* whether fatal error occurred */
bool added_pkt = false; /* whether we pushed onto ->ibuf */
bool added_pkt = false; /* whether we pushed onto ->connection.ibuf */
int code = 0; /* FSM code if error occurred */
bool ibuf_full = false; /* Is peer fifo IN Buffer full */
static bool ibuf_full_logged; /* Have we logged full already */
int ret = 1;
/* clang-format on */
peer = EVENT_ARG(thread);
peer = connection->peer;
if (peer->fd < 0 || bm->terminating)
if (bm->terminating || connection->fd < 0)
return;
struct frr_pthread *fpt = bgp_pth_io;
frr_with_mutex (&peer->io_mtx) {
status = bgp_read(peer, &code);
frr_with_mutex (&connection->io_mtx) {
status = bgp_read(connection, &code);
}
/* error checking phase */
@ -247,13 +252,13 @@ static void bgp_process_reads(struct event *thread)
/* Handle the error in the main pthread, include the
* specific state change from 'bgp_read'.
*/
event_add_event(bm->master, bgp_packet_process_error, peer,
code, &peer->t_process_packet_error);
event_add_event(bm->master, bgp_packet_process_error, connection,
code, &connection->t_process_packet_error);
goto done;
}
while (true) {
ret = read_ibuf_work(peer);
ret = read_ibuf_work(connection);
if (ret <= 0)
break;
@ -265,7 +270,6 @@ static void bgp_process_reads(struct event *thread)
fatal = true;
break;
case -ENOMEM:
ibuf_full = true;
if (!ibuf_full_logged) {
if (bgp_debug_neighbor_events(peer))
zlog_debug(
@ -284,35 +288,33 @@ done:
/* handle invalid header */
if (fatal) {
/* wipe buffer just in case someone screwed up */
ringbuf_wipe(peer->ibuf_work);
ringbuf_wipe(connection->ibuf_work);
return;
}
/* ringbuf should be fully drained unless ibuf is full */
if (!ibuf_full)
assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size);
event_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
event_add_read(fpt->master, bgp_process_reads, connection,
connection->fd, &connection->t_read);
if (added_pkt)
event_add_event(bm->master, bgp_process_packet, peer, 0,
&peer->t_process_packet);
event_add_event(bm->master, bgp_process_packet, connection, 0,
&connection->t_process_packet);
}
/*
* Flush peer output buffer.
*
* This function pops packets off of peer->obuf and writes them to peer->fd.
* The amount of packets written is equal to the minimum of peer->wpkt_quanta
* and the number of packets on the output buffer, unless an error occurs.
* This function pops packets off of peer->connection.obuf and writes them to
* peer->connection.fd. The amount of packets written is equal to the minimum of
* peer->wpkt_quanta and the number of packets on the output buffer, unless an
* error occurs.
*
* If write() returns an error, the appropriate FSM event is generated.
*
* The return value is equal to the number of packets written
* (which may be zero).
*/
static uint16_t bgp_write(struct peer *peer)
static uint16_t bgp_write(struct peer_connection *connection)
{
struct peer *peer = connection->peer;
uint8_t type;
struct stream *s;
int update_last_write = 0;
@ -334,7 +336,7 @@ static uint16_t bgp_write(struct peer *peer)
struct stream **streams = ostreams;
struct iovec iov[wpkt_quanta_old];
s = stream_fifo_head(peer->obuf);
s = stream_fifo_head(connection->obuf);
if (!s)
goto done;
@ -354,11 +356,11 @@ static uint16_t bgp_write(struct peer *peer)
total_written = 0;
do {
num = writev(peer->fd, iov, iovsz);
num = writev(connection->fd, iov, iovsz);
if (num < 0) {
if (!ERRNO_IO_RETRY(errno)) {
BGP_EVENT_ADD(peer, TCP_fatal_error);
BGP_EVENT_ADD(connection, TCP_fatal_error);
SET_FLAG(status, BGP_IO_FATAL_ERR);
} else {
SET_FLAG(status, BGP_IO_TRANS_ERR);
@ -403,7 +405,7 @@ static uint16_t bgp_write(struct peer *peer)
/* Handle statistics */
for (unsigned int i = 0; i < total_written; i++) {
s = stream_fifo_pop(peer->obuf);
s = stream_fifo_pop(connection->obuf);
assert(s == ostreams[i]);
@ -435,7 +437,7 @@ static uint16_t bgp_write(struct peer *peer)
* Handle Graceful Restart case where the state changes
* to Connect instead of Idle.
*/
BGP_EVENT_ADD(peer, BGP_Stop);
BGP_EVENT_ADD(connection, BGP_Stop);
goto done;
case BGP_MSG_KEEPALIVE:
@ -480,31 +482,37 @@ done : {
return status;
}
uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX];
/*
* Reads a chunk of data from peer->fd into peer->ibuf_work.
* Reads a chunk of data from peer->connection.fd into
* peer->connection.ibuf_work.
*
* code_p
* Pointer to location to store FSM event code in case of fatal error.
*
* @return status flag (see top-of-file)
*
* PLEASE NOTE: If we ever transform the bgp_read to be a pthread
* per peer then we need to rethink the global ibuf_scratch
* data structure above.
*/
static uint16_t bgp_read(struct peer *peer, int *code_p)
static uint16_t bgp_read(struct peer_connection *connection, int *code_p)
{
size_t readsize; /* how many bytes we want to read */
ssize_t nbytes; /* how many bytes we actually read */
size_t ibuf_work_space; /* space we can read into the work buf */
uint16_t status = 0;
ibuf_work_space = ringbuf_space(peer->ibuf_work);
ibuf_work_space = ringbuf_space(connection->ibuf_work);
if (ibuf_work_space == 0) {
SET_FLAG(status, BGP_IO_WORK_FULL_ERR);
return status;
}
readsize = MIN(ibuf_work_space, sizeof(peer->ibuf_scratch));
readsize = MIN(ibuf_work_space, sizeof(ibuf_scratch));
nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
nbytes = read(connection->fd, ibuf_scratch, readsize);
/* EAGAIN or EWOULDBLOCK; come back later */
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
@ -512,8 +520,8 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
} else if (nbytes < 0) {
/* Fatal error; tear down session */
flog_err(EC_BGP_UPDATE_RCV,
"%s [Error] bgp_read_packet error: %s", peer->host,
safe_strerror(errno));
"%s [Error] bgp_read_packet error: %s",
connection->peer->host, safe_strerror(errno));
/* Handle the error in the main pthread. */
if (code_p)
@ -523,9 +531,9 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
} else if (nbytes == 0) {
/* Received EOF / TCP session closed */
if (bgp_debug_neighbor_events(peer))
if (bgp_debug_neighbor_events(connection->peer))
zlog_debug("%s [Event] BGP connection closed fd %d",
peer->host, peer->fd);
connection->peer->host, connection->fd);
/* Handle the error in the main pthread. */
if (code_p)
@ -533,8 +541,8 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
SET_FLAG(status, BGP_IO_FATAL_ERR);
} else {
assert(ringbuf_put(peer->ibuf_work, peer->ibuf_scratch, nbytes)
== (size_t)nbytes);
assert(ringbuf_put(connection->ibuf_work, ibuf_scratch,
nbytes) == (size_t)nbytes);
}
return status;
@ -547,11 +555,12 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
* Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
* buffer.
*/
static bool validate_header(struct peer *peer)
static bool validate_header(struct peer_connection *connection)
{
struct peer *peer = connection->peer;
uint16_t size;
uint8_t type;
struct ringbuf *pkt = peer->ibuf_work;
struct ringbuf *pkt = connection->ibuf_work;
static const uint8_t m_correct[BGP_MARKER_SIZE] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

View file

@ -14,6 +14,8 @@
#include "bgpd/bgpd.h"
#include "frr_pthread.h"
struct peer_connection;
/**
* Start function for write thread.
*
@ -33,57 +35,57 @@ extern int bgp_io_stop(void **result, struct frr_pthread *fpt);
/**
* Turns on packet writing for a peer.
*
* After this function is called, any packets placed on peer->obuf will be
* written to peer->fd until no more packets remain.
* After this function is called, any packets placed on connection->obuf will be
* written to connection->fd until no more packets remain.
*
* Additionally, it becomes unsafe to perform socket actions on peer->fd.
* Additionally, it becomes unsafe to perform socket actions on connection->fd.
*
* @param peer - peer to register
*/
extern void bgp_writes_on(struct peer *peer);
extern void bgp_writes_on(struct peer_connection *peer);
/**
* Turns off packet writing for a peer.
*
* After this function returns, packets placed on peer->obuf will not be
* written to peer->fd by the I/O thread.
* After this function returns, packets placed on connection->obuf will not be
* written to connection->fd by the I/O thread.
*
* After this function returns it becomes safe to perform socket actions on
* peer->fd.
* connection->fd.
*
* @param peer - peer to deregister
* @param connection - connection to deregister
* @param flush - as described
*/
extern void bgp_writes_off(struct peer *peer);
extern void bgp_writes_off(struct peer_connection *connection);
/**
* Turns on packet reading for a peer.
*
* After this function is called, any packets received on peer->fd will be read
* and copied into the FIFO queue peer->ibuf.
* After this function is called, any packets received on connection->fd
* will be read and copied into the FIFO queue connection->ibuf.
*
* Additionally, it becomes unsafe to perform socket actions on peer->fd.
* Additionally, it becomes unsafe to perform socket actions on connection->fd.
*
* Whenever one or more packets are placed onto peer->ibuf, a task of type
* Whenever one or more packets are placed onto connection->ibuf, a task of type
* THREAD_EVENT will be placed on the main thread whose handler is
*
* bgp_packet.c:bgp_process_packet()
*
* @param peer - peer to register
* @param connection - The connection to register
*/
extern void bgp_reads_on(struct peer *peer);
extern void bgp_reads_on(struct peer_connection *connection);
/**
* Turns off packet reading for a peer.
*
* After this function is called, any packets received on peer->fd will not be
* read by the I/O thread.
* After this function is called, any packets received on connection->fd
* will not be read by the I/O thread.
*
* After this function returns it becomes safe to perform socket actions on
* peer->fd.
* connection->fd.
*
* @param peer - peer to deregister
* @param connection - The connection to register for
*/
extern void bgp_reads_off(struct peer *peer);
extern void bgp_reads_off(struct peer_connection *connection);
#endif /* _FRR_BGP_IO_H */

View file

@ -229,8 +229,10 @@ void *bgp_keepalives_start(void *arg)
/* --- thread external functions ------------------------------------------- */
void bgp_keepalives_on(struct peer *peer)
void bgp_keepalives_on(struct peer_connection *connection)
{
struct peer *peer = connection->peer;
if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;
@ -258,8 +260,10 @@ void bgp_keepalives_on(struct peer *peer)
}
}
void bgp_keepalives_off(struct peer *peer)
void bgp_keepalives_off(struct peer_connection *connection)
{
struct peer *peer = connection->peer;
if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;

View file

@ -27,7 +27,7 @@
* If the peer is already registered for keepalives via this function, nothing
* happens.
*/
extern void bgp_keepalives_on(struct peer *);
extern void bgp_keepalives_on(struct peer_connection *connection);
/**
* Turns off keepalives for a peer.
@ -36,7 +36,7 @@ extern void bgp_keepalives_on(struct peer *);
*
* If the peer is already unregistered for keepalives, nothing happens.
*/
extern void bgp_keepalives_off(struct peer *);
extern void bgp_keepalives_off(struct peer_connection *connection);
/**
* Pre-run initialization function for keepalives pthread.

View file

@ -15,6 +15,7 @@
#include "memory.h"
#include "nexthop.h"
#include "mpls.h"
#include "jhash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -27,6 +28,124 @@
extern struct zclient *zclient;
/* MPLS Labels hash routines. */
static struct hash *labels_hash;
static void *bgp_labels_hash_alloc(void *p)
{
const struct bgp_labels *labels = p;
struct bgp_labels *new;
uint8_t i;
new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels));
new->num_labels = labels->num_labels;
for (i = 0; i < labels->num_labels; i++)
new->label[i] = labels->label[i];
return new;
}
static uint32_t bgp_labels_hash_key_make(const void *p)
{
const struct bgp_labels *labels = p;
uint32_t key = 0;
if (labels->num_labels)
key = jhash(&labels->label,
labels->num_labels * sizeof(mpls_label_t), key);
return key;
}
static bool bgp_labels_hash_cmp(const void *p1, const void *p2)
{
return bgp_labels_cmp(p1, p2);
}
void bgp_labels_init(void)
{
labels_hash = hash_create(bgp_labels_hash_key_make, bgp_labels_hash_cmp,
"BGP Labels hash");
}
/*
* special for hash_clean below
*/
static void bgp_labels_free(void *labels)
{
XFREE(MTYPE_BGP_LABELS, labels);
}
void bgp_labels_finish(void)
{
hash_clean_and_free(&labels_hash, bgp_labels_free);
}
struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels)
{
struct bgp_labels *find;
if (!labels)
return NULL;
if (!labels->num_labels)
/* do not intern void labels structure */
return NULL;
find = (struct bgp_labels *)hash_get(labels_hash, labels,
bgp_labels_hash_alloc);
find->refcnt++;
return find;
}
void bgp_labels_unintern(struct bgp_labels **plabels)
{
struct bgp_labels *labels = *plabels;
struct bgp_labels *ret;
if (!*plabels)
return;
/* Decrement labels reference. */
labels->refcnt--;
/* If reference becomes zero then free labels object. */
if (labels->refcnt == 0) {
ret = hash_release(labels_hash, labels);
assert(ret != NULL);
bgp_labels_free(labels);
*plabels = NULL;
}
}
bool bgp_labels_cmp(const struct bgp_labels *labels1,
const struct bgp_labels *labels2)
{
uint8_t i;
if (!labels1 && !labels2)
return true;
if (!labels1 && labels2)
return false;
if (labels1 && !labels2)
return false;
if (labels1->num_labels != labels2->num_labels)
return false;
for (i = 0; i < labels1->num_labels; i++) {
if (labels1->label[i] != labels2->label[i])
return false;
}
return true;
}
int bgp_parse_fec_update(void)
{
struct stream *s;
@ -74,7 +193,7 @@ int bgp_parse_fec_update(void)
bgp_set_valid_label(&dest->local_label);
}
SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED);
bgp_process(bgp, dest, afi, safi);
bgp_process(bgp, dest, NULL, afi, safi);
bgp_dest_unlock_node(dest);
return 1;
}
@ -89,7 +208,9 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
if (!dest || !pi || !to)
return MPLS_INVALID_LABEL;
remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL;
remote_label = BGP_PATH_INFO_NUM_LABELS(pi)
? pi->extra->labels->label[0]
: MPLS_INVALID_LABEL;
from = pi->peer;
reflect =
((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
@ -132,9 +253,8 @@ static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg,
return;
if (BGP_DEBUG(labelpool, LABELPOOL))
zlog_debug("%s: FEC %sregister %pRN label_index=%u label=%u",
__func__, reg ? "" : "un", bgp_dest_to_rnode(dest),
label_index, label);
zlog_debug("%s: FEC %sregister %pBD label_index=%u label=%u",
__func__, reg ? "" : "un", dest, label_index, label);
/* If the route node has a local_label assigned or the
* path node has an MPLS SR label index allowing zebra to
* derive the label, proceed with registration. */
@ -195,11 +315,12 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
return -1;
}
bgp_dest_unlock_node(dest);
dest = bgp_dest_unlock_node(dest);
assert(dest);
if (BGP_DEBUG(labelpool, LABELPOOL))
zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__,
bgp_dest_to_rnode(dest), new_label, allocated);
zlog_debug("%s: FEC %pBD label=%u, allocated=%d", __func__,
dest, new_label, allocated);
if (!allocated) {
/*
@ -455,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
} else {
bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
BGP_ROUTE_NORMAL, NULL, &label, 1);
}
}
@ -470,3 +591,20 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
return BGP_NLRI_PARSE_OK;
}
bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a,
const mpls_label_t *tbl_b, const uint8_t num_labels_b)
{
uint32_t i;
if (num_labels_a != num_labels_b)
return false;
if (num_labels_a == 0)
return true;
for (i = 0; i < num_labels_a; i++) {
if (tbl_a[i] != tbl_b[i])
return false;
}
return true;
}

View file

@ -15,6 +15,26 @@ struct bgp_dest;
struct bgp_path_info;
struct peer;
/* Maximum number of labels we can process or send with a prefix. We
* really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
*/
#define BGP_MAX_LABELS 2
/* MPLS label(s) - VNI(s) for EVPN-VxLAN */
struct bgp_labels {
mpls_label_t label[BGP_MAX_LABELS];
uint8_t num_labels;
unsigned long refcnt;
};
extern void bgp_labels_init(void);
extern void bgp_labels_finish(void);
extern struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels);
extern void bgp_labels_unintern(struct bgp_labels **plabels);
extern bool bgp_labels_cmp(const struct bgp_labels *labels1,
const struct bgp_labels *labels2);
extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
bool allocated);
extern void bgp_reg_dereg_for_label(struct bgp_dest *dest,
@ -26,6 +46,10 @@ extern mpls_label_t bgp_adv_label(struct bgp_dest *dest,
extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet);
extern bool bgp_labels_same(const mpls_label_t *tbl_a,
const uint8_t num_labels_a,
const mpls_label_t *tbl_b,
const uint8_t num_labels_b);
static inline int bgp_labeled_safi(safi_t safi)
{

View file

@ -15,7 +15,6 @@
#include "linklist.h"
#include "skiplist.h"
#include "workqueue.h"
#include "zclient.h"
#include "mpls.h"
#include "bgpd/bgpd.h"
@ -23,22 +22,22 @@
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_rd.h"
#define BGP_LABELPOOL_ENABLE_TESTS 0
#include "bgpd/bgp_labelpool_clippy.c"
/*
* Definitions and external declarations.
*/
extern struct zclient *zclient;
#if BGP_LABELPOOL_ENABLE_TESTS
static void lptest_init(void);
static void lptest_finish(void);
#endif
static void bgp_sync_label_manager(struct event *e);
/*
* Remember where pool data are kept
*/
@ -220,6 +219,8 @@ void bgp_lp_finish(void)
{
struct lp_fifo *lf;
struct work_queue_item *item, *titem;
struct listnode *node;
struct lp_chunk *chunk;
#if BGP_LABELPOOL_ENABLE_TESTS
lptest_finish();
@ -233,6 +234,9 @@ void bgp_lp_finish(void)
skiplist_free(lp->inuse);
lp->inuse = NULL;
for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk))
bgp_zebra_release_label_range(chunk->first, chunk->last);
list_delete(&lp->chunks);
while ((lf = lp_fifo_pop(&lp->requests))) {
@ -445,16 +449,17 @@ void bgp_lp_get(
lp_fifo_add_tail(&lp->requests, lf);
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
if (!zclient || zclient->sock < 0)
if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY,
lp->next_chunksize, true))
return;
if (zclient_send_get_label_chunk(zclient, 0, lp->next_chunksize,
MPLS_LABEL_BASE_ANY) !=
ZCLIENT_SEND_FAILURE) {
lp->pending_count += lp->next_chunksize;
if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX)
lp->next_chunksize <<= 1;
}
lp->pending_count += lp->next_chunksize;
if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX)
lp->next_chunksize <<= 1;
}
event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1,
&bm->t_bgp_sync_label_manager);
}
void bgp_lp_release(
@ -494,20 +499,103 @@ void bgp_lp_release(
bf_release_index(chunk->allocated_map, index);
chunk->nfree += 1;
deallocated = true;
break;
}
assert(deallocated);
if (deallocated &&
chunk->nfree == chunk->last - chunk->first + 1 &&
lp_fifo_count(&lp->requests) == 0) {
bgp_zebra_release_label_range(chunk->first,
chunk->last);
list_delete_node(lp->chunks, node);
lp_chunk_free(chunk);
lp->next_chunksize = LP_CHUNK_SIZE_MIN;
}
}
}
}
/*
* zebra response giving us a chunk of labels
*/
void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
static void bgp_sync_label_manager(struct event *e)
{
struct lp_chunk *chunk;
int debug = BGP_DEBUG(labelpool, LABELPOOL);
struct lp_fifo *lf;
while ((lf = lp_fifo_pop(&lp->requests))) {
struct lp_lcb *lcb;
void *labelid = lf->lcb.labelid;
if (skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
/* request no longer in effect */
if (debug) {
zlog_debug("%s: labelid %p: request no longer in effect",
__func__, labelid);
}
/* if this was a BGP_LU request, unlock node
*/
check_bgp_lu_cb_unlock(lcb);
goto finishedrequest;
}
/* have LCB */
if (lcb->label != MPLS_LABEL_NONE) {
/* request already has a label */
if (debug) {
zlog_debug("%s: labelid %p: request already has a label: %u=0x%x, lcb=%p",
__func__, labelid, lcb->label,
lcb->label, lcb);
}
/* if this was a BGP_LU request, unlock node
*/
check_bgp_lu_cb_unlock(lcb);
goto finishedrequest;
}
lcb->label = get_label_from_pool(lcb->labelid);
if (lcb->label == MPLS_LABEL_NONE) {
/*
* Out of labels in local pool, await next chunk
*/
if (debug) {
zlog_debug("%s: out of labels, await more",
__func__);
}
lp_fifo_add_tail(&lp->requests, lf);
event_add_timer(bm->master, bgp_sync_label_manager,
NULL, 1, &bm->t_bgp_sync_label_manager);
break;
}
/*
* we filled the request from local pool.
* Enqueue response work item with new label.
*/
struct lp_cbq_item *q = XCALLOC(MTYPE_BGP_LABEL_CBQ,
sizeof(struct lp_cbq_item));
q->cbfunc = lcb->cbfunc;
q->type = lcb->type;
q->label = lcb->label;
q->labelid = lcb->labelid;
q->allocated = true;
if (debug)
zlog_debug("%s: assigning label %u to labelid %p",
__func__, q->label, q->labelid);
work_queue_add(lp->callback_q, q);
finishedrequest:
XFREE(MTYPE_BGP_LABEL_FIFO, lf);
}
}
void bgp_lp_event_chunk(uint32_t first, uint32_t last)
{
struct lp_chunk *chunk;
uint32_t labelcount;
if (last < first) {
@ -533,83 +621,6 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
listnode_add_head(lp->chunks, chunk);
lp->pending_count -= labelcount;
if (debug) {
zlog_debug("%s: %zu pending requests", __func__,
lp_fifo_count(&lp->requests));
}
while (labelcount && (lf = lp_fifo_first(&lp->requests))) {
struct lp_lcb *lcb;
void *labelid = lf->lcb.labelid;
if (skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
/* request no longer in effect */
if (debug) {
zlog_debug("%s: labelid %p: request no longer in effect",
__func__, labelid);
}
/* if this was a BGP_LU request, unlock node
*/
check_bgp_lu_cb_unlock(lcb);
goto finishedrequest;
}
/* have LCB */
if (lcb->label != MPLS_LABEL_NONE) {
/* request already has a label */
if (debug) {
zlog_debug("%s: labelid %p: request already has a label: %u=0x%x, lcb=%p",
__func__, labelid,
lcb->label, lcb->label, lcb);
}
/* if this was a BGP_LU request, unlock node
*/
check_bgp_lu_cb_unlock(lcb);
goto finishedrequest;
}
lcb->label = get_label_from_pool(lcb->labelid);
if (lcb->label == MPLS_LABEL_NONE) {
/*
* Out of labels in local pool, await next chunk
*/
if (debug) {
zlog_debug("%s: out of labels, await more",
__func__);
}
break;
}
labelcount -= 1;
/*
* we filled the request from local pool.
* Enqueue response work item with new label.
*/
struct lp_cbq_item *q = XCALLOC(MTYPE_BGP_LABEL_CBQ,
sizeof(struct lp_cbq_item));
q->cbfunc = lcb->cbfunc;
q->type = lcb->type;
q->label = lcb->label;
q->labelid = lcb->labelid;
q->allocated = true;
if (debug)
zlog_debug("%s: assigning label %u to labelid %p",
__func__, q->label, q->labelid);
work_queue_add(lp->callback_q, q);
finishedrequest:
lp_fifo_del(&lp->requests, lf);
XFREE(MTYPE_BGP_LABEL_FIFO, lf);
}
}
/*
@ -631,7 +642,6 @@ void bgp_lp_event_zebra_up(void)
unsigned int chunks_needed;
void *labelid;
struct lp_lcb *lcb;
int lm_init_ok;
lp->reconnect_count++;
/*
@ -648,25 +658,19 @@ void bgp_lp_event_zebra_up(void)
}
/* round up */
chunks_needed = (labels_needed / lp->next_chunksize) + 1;
chunks_needed = (labels_needed + lp->next_chunksize - 1) / lp->next_chunksize;
labels_needed = chunks_needed * lp->next_chunksize;
lm_init_ok = lm_label_manager_connect(zclient, 1) == 0;
if (!lm_init_ok) {
zlog_err("%s: label manager connection error", __func__);
return;
}
zclient_send_get_label_chunk(zclient, 0, labels_needed,
MPLS_LABEL_BASE_ANY);
lp->pending_count = labels_needed;
/*
* Invalidate current list of chunks
*/
list_delete_all_node(lp->chunks);
if (labels_needed && !bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY,
labels_needed, true))
return;
lp->pending_count += labels_needed;
/*
* Invalidate any existing labels and requeue them as requests
*/
@ -709,6 +713,9 @@ void bgp_lp_event_zebra_up(void)
skiplist_delete_first(lp->inuse);
}
event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1,
&bm->t_bgp_sync_label_manager);
}
DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd,
@ -830,6 +837,26 @@ DEFUN(show_bgp_labelpool_ledger, show_bgp_labelpool_ledger_cmd,
lcb->label);
break;
case LP_TYPE_NEXTHOP:
if (uj) {
json_object_string_add(json_elem, "prefix",
"nexthop");
json_object_int_add(json_elem, "label",
lcb->label);
} else
vty_out(vty, "%-18s %u\n", "nexthop",
lcb->label);
break;
case LP_TYPE_BGP_L3VPN_BIND:
if (uj) {
json_object_string_add(json_elem, "prefix",
"l3vpn-bind");
json_object_int_add(json_elem, "label",
lcb->label);
} else
vty_out(vty, "%-18s %u\n", "l3vpn-bind",
lcb->label);
break;
}
}
if (uj)
@ -919,6 +946,24 @@ DEFUN(show_bgp_labelpool_inuse, show_bgp_labelpool_inuse_cmd,
vty_out(vty, "%-18s %u\n", "VRF",
label);
break;
case LP_TYPE_NEXTHOP:
if (uj) {
json_object_string_add(json_elem, "prefix",
"nexthop");
json_object_int_add(json_elem, "label", label);
} else
vty_out(vty, "%-18s %u\n", "nexthop",
label);
break;
case LP_TYPE_BGP_L3VPN_BIND:
if (uj) {
json_object_string_add(json_elem, "prefix",
"l3vpn-bind");
json_object_int_add(json_elem, "label", label);
} else
vty_out(vty, "%-18s %u\n", "l3vpn-bind",
label);
break;
}
}
if (uj)
@ -991,6 +1036,20 @@ DEFUN(show_bgp_labelpool_requests, show_bgp_labelpool_requests_cmd,
else
vty_out(vty, "VRF\n");
break;
case LP_TYPE_NEXTHOP:
if (uj)
json_object_string_add(json_elem, "prefix",
"nexthop");
else
vty_out(vty, "Nexthop\n");
break;
case LP_TYPE_BGP_L3VPN_BIND:
if (uj)
json_object_string_add(json_elem, "prefix",
"l3vpn-bind");
else
vty_out(vty, "L3VPN-BIND\n");
break;
}
}
if (uj)
@ -1053,6 +1112,100 @@ DEFUN(show_bgp_labelpool_chunks, show_bgp_labelpool_chunks_cmd,
return CMD_SUCCESS;
}
static void show_bgp_nexthop_label_afi(struct vty *vty, afi_t afi,
struct bgp *bgp, bool detail)
{
struct bgp_label_per_nexthop_cache_head *tree;
struct bgp_label_per_nexthop_cache *iter;
safi_t safi;
void *src;
char buf[PREFIX2STR_BUFFER];
char labelstr[MPLS_LABEL_STRLEN];
struct bgp_dest *dest;
struct bgp_path_info *path;
struct bgp *bgp_path;
struct bgp_table *table;
time_t tbuf;
vty_out(vty, "Current BGP label nexthop cache for %s, VRF %s\n",
afi2str(afi), bgp->name_pretty);
tree = &bgp->mpls_labels_per_nexthop[afi];
frr_each (bgp_label_per_nexthop_cache, tree, iter) {
if (afi2family(afi) == AF_INET)
src = (void *)&iter->nexthop.u.prefix4;
else
src = (void *)&iter->nexthop.u.prefix6;
vty_out(vty, " %s, label %s #paths %u\n",
inet_ntop(afi2family(afi), src, buf, sizeof(buf)),
mpls_label2str(1, &iter->label, labelstr,
sizeof(labelstr), 0, true),
iter->path_count);
if (iter->nh)
vty_out(vty, " if %s\n",
ifindex2ifname(iter->nh->ifindex,
iter->nh->vrf_id));
tbuf = time(NULL) - (monotime(NULL) - iter->last_update);
vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf));
if (!detail)
continue;
vty_out(vty, " Paths:\n");
LIST_FOREACH (path, &(iter->paths),
mplsvpn.blnc.label_nh_thread) {
dest = path->net;
table = bgp_dest_table(dest);
assert(dest && table);
afi = family2afi(bgp_dest_get_prefix(dest)->family);
safi = table->safi;
bgp_path = table->bgp;
if (dest->pdest) {
vty_out(vty, " %d/%d %pBD RD ", afi, safi,
dest);
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest));
vty_out(vty, " %s flags 0x%x\n",
bgp_path->name_pretty, path->flags);
} else
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
afi, safi, dest, bgp_path->name_pretty,
path->flags);
}
}
}
DEFPY(show_bgp_nexthop_label, show_bgp_nexthop_label_cmd,
"show bgp [<view|vrf> VIEWVRFNAME] label-nexthop [detail]",
SHOW_STR BGP_STR BGP_INSTANCE_HELP_STR
"BGP label per-nexthop table\n"
"Show detailed information\n")
{
int idx = 0;
char *vrf = NULL;
struct bgp *bgp;
bool detail = false;
int afi;
if (argv_find(argv, argc, "vrf", &idx)) {
vrf = argv[++idx]->arg;
bgp = bgp_lookup_by_name(vrf);
} else
bgp = bgp_get_default();
if (!bgp)
return CMD_SUCCESS;
if (argv_find(argv, argc, "detail", &idx))
detail = true;
for (afi = AFI_IP; afi <= AFI_IP6; afi++)
show_bgp_nexthop_label_afi(vty, afi, bgp, detail);
return CMD_SUCCESS;
}
#if BGP_LABELPOOL_ENABLE_TESTS
/*------------------------------------------------------------------------
* Testing code start
@ -1532,3 +1685,66 @@ void bgp_lp_vty_init(void)
install_element(ENABLE_NODE, &clear_labelpool_perf_test_cmd);
#endif /* BGP_LABELPOOL_ENABLE_TESTS */
}
DEFINE_MTYPE_STATIC(BGPD, LABEL_PER_NEXTHOP_CACHE,
"BGP Label Per Nexthop entry");
/* The nexthops values are compared to
* find in the tree the appropriate cache entry
*/
int bgp_label_per_nexthop_cache_cmp(const struct bgp_label_per_nexthop_cache *a,
const struct bgp_label_per_nexthop_cache *b)
{
return prefix_cmp(&a->nexthop, &b->nexthop);
}
struct bgp_label_per_nexthop_cache *
bgp_label_per_nexthop_new(struct bgp_label_per_nexthop_cache_head *tree,
struct prefix *nexthop)
{
struct bgp_label_per_nexthop_cache *blnc;
blnc = XCALLOC(MTYPE_LABEL_PER_NEXTHOP_CACHE,
sizeof(struct bgp_label_per_nexthop_cache));
blnc->tree = tree;
blnc->label = MPLS_INVALID_LABEL;
prefix_copy(&blnc->nexthop, nexthop);
LIST_INIT(&(blnc->paths));
bgp_label_per_nexthop_cache_add(tree, blnc);
return blnc;
}
struct bgp_label_per_nexthop_cache *
bgp_label_per_nexthop_find(struct bgp_label_per_nexthop_cache_head *tree,
struct prefix *nexthop)
{
struct bgp_label_per_nexthop_cache blnc = {};
if (!tree)
return NULL;
memcpy(&blnc.nexthop, nexthop, sizeof(struct prefix));
return bgp_label_per_nexthop_cache_find(tree, &blnc);
}
void bgp_label_per_nexthop_free(struct bgp_label_per_nexthop_cache *blnc)
{
if (blnc->label != MPLS_INVALID_LABEL) {
bgp_zebra_send_nexthop_label(ZEBRA_MPLS_LABELS_DELETE,
blnc->label, blnc->nh->ifindex,
blnc->nh->vrf_id, ZEBRA_LSP_BGP,
&blnc->nexthop, 0, NULL);
bgp_lp_release(LP_TYPE_NEXTHOP, blnc, blnc->label);
}
bgp_label_per_nexthop_cache_del(blnc->tree, blnc);
if (blnc->nh)
nexthop_free(blnc->nh);
blnc->nh = NULL;
XFREE(MTYPE_LABEL_PER_NEXTHOP_CACHE, blnc);
}
void bgp_label_per_nexthop_init(void)
{
install_element(VIEW_NODE, &show_bgp_nexthop_label_cmd);
}

View file

@ -17,6 +17,8 @@
*/
#define LP_TYPE_VRF 0x00000001
#define LP_TYPE_BGP_LU 0x00000002
#define LP_TYPE_NEXTHOP 0x00000003
#define LP_TYPE_BGP_L3VPN_BIND 0x00000004
PREDECL_LIST(lp_fifo);
@ -36,9 +38,60 @@ extern void bgp_lp_finish(void);
extern void bgp_lp_get(int type, void *labelid,
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated));
extern void bgp_lp_release(int type, void *labelid, mpls_label_t label);
extern void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last);
extern void bgp_lp_event_chunk(uint32_t first, uint32_t last);
extern void bgp_lp_event_zebra_down(void);
extern void bgp_lp_event_zebra_up(void);
extern void bgp_lp_vty_init(void);
struct bgp_label_per_nexthop_cache;
PREDECL_RBTREE_UNIQ(bgp_label_per_nexthop_cache);
extern int
bgp_label_per_nexthop_cache_cmp(const struct bgp_label_per_nexthop_cache *a,
const struct bgp_label_per_nexthop_cache *b);
struct bgp_label_per_nexthop_cache {
/* RB-tree entry. */
struct bgp_label_per_nexthop_cache_item entry;
/* the nexthop is the key of the list */
struct prefix nexthop;
/* calculated label */
mpls_label_t label;
/* number of path_vrfs */
unsigned int path_count;
/* back pointer to bgp instance */
struct bgp *to_bgp;
/* copy a nexthop resolution from bgp nexthop tracking
* used to extract the interface nexthop
*/
struct nexthop *nh;
/* list of path_vrfs using it */
LIST_HEAD(path_lists, bgp_path_info) paths;
time_t last_update;
/* Back pointer to the cache tree this entry belongs to. */
struct bgp_label_per_nexthop_cache_head *tree;
};
DECLARE_RBTREE_UNIQ(bgp_label_per_nexthop_cache,
struct bgp_label_per_nexthop_cache, entry,
bgp_label_per_nexthop_cache_cmp);
void bgp_label_per_nexthop_free(struct bgp_label_per_nexthop_cache *blnc);
struct bgp_label_per_nexthop_cache *
bgp_label_per_nexthop_new(struct bgp_label_per_nexthop_cache_head *tree,
struct prefix *nexthop);
struct bgp_label_per_nexthop_cache *
bgp_label_per_nexthop_find(struct bgp_label_per_nexthop_cache_head *tree,
struct prefix *nexthop);
void bgp_label_per_nexthop_init(void);
#endif /* _FRR_BGP_LABELPOOL_H */

View file

@ -14,6 +14,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_memory.h"
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_rd.h"
@ -125,6 +126,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
{
struct bgp_dest *pdest, *dest;
struct bgp_path_info *pi;
uint8_t num_labels;
mpls_label_t *label_pnt;
for (pdest = bgp_table_top(table); pdest;
pdest = bgp_route_next(pdest)) {
@ -140,9 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
const struct prefix *p = bgp_dest_get_prefix(dest);
struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
struct prefix_rd prd;
uint32_t num_labels = 0;
mpls_label_t *label_pnt = NULL;
struct bgp_route_evpn *evpn;
if (pevpn->family == AF_EVPN
&& pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
@ -169,10 +169,9 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
&& !dest_affected)
continue;
if (pi->extra)
num_labels = pi->extra->num_labels;
if (num_labels)
label_pnt = &pi->extra->label[0];
num_labels = BGP_PATH_INFO_NUM_LABELS(pi);
label_pnt = num_labels ? &pi->extra->labels->label[0]
: NULL;
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
@ -195,12 +194,10 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
continue;
}
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
sizeof(evpn));
bgp_update(peer, p, pi->addpath_rx_id, pi->attr,
AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, label_pnt,
num_labels, 1, evpn);
BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels,
1, bgp_attr_get_evpn_overlay(pi->attr));
}
}
}
@ -219,7 +216,7 @@ static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
continue;
if (!peer_established(peer))
if (!peer_established(peer->connection))
continue;
if (bgp_debug_update(peer, NULL, NULL, 1))
@ -279,15 +276,29 @@ static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname,
}
}
/* Add/Update entry of the 'bgp mac hash' table.
* A rescan of the EVPN tables is only needed if
* a new hash bucket is allocated.
* Learning an existing mac on a new interface (or
* having an existing mac move from one interface to
* another) does not result in changes to self mac
* state, so we shouldn't trigger a rescan.
*/
void bgp_mac_add_mac_entry(struct interface *ifp)
{
struct bgp_self_mac lookup;
struct bgp_self_mac *bsm;
struct bgp_self_mac *old_bsm;
char *ifname;
bool mac_added = false;
memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
bsm = hash_lookup(bm->self_mac_hash, &lookup);
if (!bsm) {
bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
/* mac is new, rescan needs to be triggered */
mac_added = true;
}
/*
* Does this happen to be a move
@ -318,7 +329,8 @@ void bgp_mac_add_mac_entry(struct interface *ifp)
listnode_add(bsm->ifp_list, ifname);
}
bgp_mac_rescan_all_evpn_tables(&bsm->macaddr);
if (mac_added)
bgp_mac_rescan_all_evpn_tables(&bsm->macaddr);
}
void bgp_mac_del_mac_entry(struct interface *ifp)
@ -360,7 +372,7 @@ bool bgp_mac_exist(const struct ethaddr *mac)
return true;
}
/* This API checks EVPN type-2 prefix and comapares
/* This API checks EVPN type-2 prefix and compares
* mac against any of local assigned (SVIs) MAC
* address.
*/
@ -375,8 +387,6 @@ bool bgp_mac_entry_exists(const struct prefix *p)
return false;
return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac);
return true;
}
static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg)

View file

@ -26,6 +26,7 @@
#include "bfd.h"
#include "libfrr.h"
#include "ns.h"
#include "libagentx.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@ -47,25 +48,31 @@
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_script.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_nhg.h"
#include "bgpd/bgp_routemap_nb.h"
#include "bgpd/bgp_community_alias.h"
DEFINE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf),
(vty, vrf));
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#endif
DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled),
(vrf, enabled));
/* bgpd options, we use GNU getopt library. */
static const struct option longopts[] = {
{"bgp_port", required_argument, NULL, 'p'},
{"listenon", required_argument, NULL, 'l'},
{"no_kernel", no_argument, NULL, 'n'},
{"skip_runas", no_argument, NULL, 'S'},
{"ecmp", required_argument, NULL, 'e'},
{"int_num", required_argument, NULL, 'I'},
{"no_zebra", no_argument, NULL, 'Z'},
{"socket_size", required_argument, NULL, 's'},
{0}};
static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' },
{ "listenon", required_argument, NULL, 'l' },
{ "no_kernel", no_argument, NULL, 'n' },
{ "skip_runas", no_argument, NULL, 'S' },
{ "ecmp", required_argument, NULL, 'e' },
{ "int_num", required_argument, NULL, 'I' },
{ "no_zebra", no_argument, NULL, 'Z' },
{ "socket_size", required_argument, NULL, 's' },
{ "v6-with-v4-nexthops", no_argument, NULL, 'x' },
{ 0 } };
/* signal definitions */
void sighup(void);
@ -197,7 +204,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
bgp_delete(bgp_default);
bgp_evpn_mh_finish();
bgp_l3nhg_finish();
bgp_nhg_finish();
zebra_announce_fini(&bm->zebra_announce_head);
/* reverse bgp_dump_init */
bgp_dump_finish();
@ -214,6 +223,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
/* reverse bgp_attr_init */
bgp_attr_finish();
/* reverse bgp_labels_init */
bgp_labels_finish();
/* stop pthreads */
bgp_pthreads_finish();
@ -285,6 +297,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
bgp_instance_up(bgp);
hook_call(bgp_hook_vrf_update, vrf, true);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
@ -331,15 +344,36 @@ static int bgp_vrf_disable(struct vrf *vrf)
* "down". */
bgp_instance_down(bgp);
bgp_vrf_unlink(bgp, vrf);
hook_call(bgp_hook_vrf_update, vrf, false);
}
/* Note: This is a callback, the VRF will be deleted by the caller. */
return 0;
}
static int bgp_vrf_config_write(struct vty *vty)
{
struct vrf *vrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (vrf->vrf_id == VRF_DEFAULT) {
vty_out(vty, "!\n");
continue;
}
vty_out(vty, "vrf %s\n", vrf->name);
hook_call(bgp_hook_config_write_vrf, vty, vrf);
vty_out(vty, "exit-vrf\n!\n");
}
return 0;
}
static void bgp_vrf_init(void)
{
vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete);
vrf_cmd_init(bgp_vrf_config_write);
}
static void bgp_vrf_terminate(void)
@ -355,15 +389,20 @@ static const struct frr_yang_module_info *const bgpd_yang_modules[] = {
&frr_bgp_route_map_info,
};
FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT,
/* clang-format off */
FRR_DAEMON_INFO(bgpd, BGP,
.vty_port = BGP_VTY_PORT,
.proghelp = "Implementation of the BGP routing protocol.",
.proghelp = "Implementation of the BGP routing protocol.",
.signals = bgp_signals,
.n_signals = array_size(bgp_signals),
.signals = bgp_signals, .n_signals = array_size(bgp_signals),
.privs = &bgpd_privs,
.privs = &bgpd_privs, .yang_modules = bgpd_yang_modules,
.n_yang_modules = array_size(bgpd_yang_modules),
.yang_modules = bgpd_yang_modules,
.n_yang_modules = array_size(bgpd_yang_modules),
);
/* clang-format on */
#define DEPRECATED_OPTIONS ""
@ -383,20 +422,21 @@ int main(int argc, char **argv)
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
char *address;
struct listnode *node;
bool v6_with_v4_nexthops = false;
addresses->cmp = (int (*)(void *, void *))strcmp;
frr_preinit(&bgpd_di, argc, argv);
frr_opt_add(
"p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
" -l, --listenon Listen on specified address (implies -n)\n"
" -n, --no_kernel Do not install route to kernel.\n"
" -Z, --no_zebra Do not communicate with Zebra.\n"
" -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n"
" -e, --ecmp Specify ECMP to use.\n"
" -I, --int_num Set instance number (label-manager)\n"
" -s, --socket_size Set BGP peer socket send buffer size\n");
frr_opt_add("p:l:SnZe:I:s:x" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
" -l, --listenon Listen on specified address (implies -n)\n"
" -n, --no_kernel Do not install route to kernel.\n"
" -Z, --no_zebra Do not communicate with Zebra.\n"
" -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n"
" -e, --ecmp Specify ECMP to use.\n"
" -I, --int_num Set instance number (label-manager)\n"
" -s, --socket_size Set BGP peer socket send buffer size\n"
" -x, --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n");
/* Command line argument treatment. */
while (1) {
@ -458,6 +498,9 @@ int main(int argc, char **argv)
case 's':
buffer_size = atoi(optarg);
break;
case 'x':
v6_with_v4_nexthops = true;
break;
default:
frr_help_exit(1);
}
@ -467,17 +510,24 @@ int main(int argc, char **argv)
/* BGP master init. */
bgp_master_init(frr_init(), buffer_size, addresses);
bm->startup_time = monotime(NULL);
bm->port = bgp_port;
bm->v6_with_v4_nexthops = v6_with_v4_nexthops;
if (bgp_port == 0)
bgp_option_set(BGP_OPT_NO_LISTEN);
if (no_fib_flag || no_zebra_flag)
bgp_option_set(BGP_OPT_NO_FIB);
if (no_zebra_flag)
bgp_option_set(BGP_OPT_NO_ZEBRA);
if (bgpd_di.graceful_restart)
SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART);
bgp_error_init();
/* Initializations. */
libagentx_init();
bgp_vrf_init();
#ifdef HAVE_SCRIPTING
bgp_script_init();
#endif

View file

@ -15,8 +15,10 @@
DEFINE_MGROUP(BGPD, "bgpd");
DEFINE_MTYPE(BGPD, BGP, "BGP instance");
DEFINE_MTYPE(BGPD, BGP_NAME, "BGP Name data");
DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details");
DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer");
DEFINE_MTYPE(BGPD, BGP_PEER_CONNECTION, "BGP peer connection");
DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname");
DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname");
DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group");
@ -37,6 +39,10 @@ DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table");
DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node");
DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_EVPN, "BGP extra info for EVPN");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_FS, "BGP extra info for flowspec");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VRFLEAK, "BGP extra info for vrf leaking");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VNC, "BGP extra info for vnc");
DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected");
DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static");
DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr");
@ -85,6 +91,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface");
DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list");
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
@ -95,6 +102,8 @@ DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information");
DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information");
DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV");
DEFINE_MTYPE(BGPD, BGP_LABELS, "BGP LABELS");
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options");
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value");
@ -126,3 +135,5 @@ DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version");
DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay");

View file

@ -11,8 +11,10 @@
DECLARE_MGROUP(BGPD);
DECLARE_MTYPE(BGP);
DECLARE_MTYPE(BGP_NAME);
DECLARE_MTYPE(BGP_LISTENER);
DECLARE_MTYPE(BGP_PEER);
DECLARE_MTYPE(BGP_PEER_CONNECTION);
DECLARE_MTYPE(BGP_PEER_HOST);
DECLARE_MTYPE(BGP_PEER_IFNAME);
DECLARE_MTYPE(PEER_GROUP);
@ -33,6 +35,10 @@ DECLARE_MTYPE(BGP_TABLE);
DECLARE_MTYPE(BGP_NODE);
DECLARE_MTYPE(BGP_ROUTE);
DECLARE_MTYPE(BGP_ROUTE_EXTRA);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_EVPN);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_FS);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_VRFLEAK);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_VNC);
DECLARE_MTYPE(BGP_CONN);
DECLARE_MTYPE(BGP_STATIC);
DECLARE_MTYPE(BGP_ADVERTISE_ATTR);
@ -81,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE);
DECLARE_MTYPE(PEER_CONF_IF);
DECLARE_MTYPE(BGP_DAMP_INFO);
DECLARE_MTYPE(BGP_DAMP_ARRAY);
DECLARE_MTYPE(BGP_DAMP_REUSELIST);
DECLARE_MTYPE(BGP_REGEXP);
DECLARE_MTYPE(BGP_AGGREGATE);
DECLARE_MTYPE(BGP_ADDR);
@ -91,6 +98,8 @@ DECLARE_MTYPE(BGP_FILTER_NAME);
DECLARE_MTYPE(BGP_DUMP_STR);
DECLARE_MTYPE(ENCAP_TLV);
DECLARE_MTYPE(BGP_LABELS);
DECLARE_MTYPE(BGP_TEA_OPTIONS);
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE);
@ -125,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION);
DECLARE_MTYPE(BGP_SOFT_VERSION);
DECLARE_MTYPE(BGP_EVPN_OVERLAY);
#endif /* _QUAGGA_BGP_MEMORY_H */

View file

@ -2,8 +2,10 @@
/*
* BGP Multipath
* Copyright (C) 2010 Google Inc.
* 2024 Nvidia Corporation
* Donald Sharp
*
* This file is part of Quagga
* This file is part of FRR
*/
#include <zebra.h>
@ -129,15 +131,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
&bpi2->attr->mp_nexthop_global);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
addr1 = (bpi1->attr->mp_nexthop_prefer_global)
addr1 = (CHECK_FLAG(bpi1->attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi1->attr->mp_nexthop_global
: bpi1->attr->mp_nexthop_local;
addr2 = (bpi2->attr->mp_nexthop_prefer_global)
addr2 = (CHECK_FLAG(bpi2->attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi2->attr->mp_nexthop_global
: bpi2->attr->mp_nexthop_local;
if (!bpi1->attr->mp_nexthop_prefer_global
&& !bpi2->attr->mp_nexthop_prefer_global)
if (!CHECK_FLAG(bpi1->attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL) &&
!CHECK_FLAG(bpi2->attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
compare = !bgp_interface_same(
bpi1->peer->ifp,
bpi2->peer->ifp);
@ -173,10 +179,11 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
* if they belong to same VRF
*/
if (!compare && bpi1->attr->nh_type != NEXTHOP_TYPE_BLACKHOLE) {
if (bpi1->extra && bpi1->extra->bgp_orig && bpi2->extra
&& bpi2->extra->bgp_orig) {
if (bpi1->extra->bgp_orig->vrf_id
!= bpi2->extra->bgp_orig->vrf_id) {
if (bpi1->extra && bpi1->extra->vrfleak &&
bpi1->extra->vrfleak->bgp_orig && bpi2->extra &&
bpi2->extra->vrfleak && bpi2->extra->vrfleak->bgp_orig) {
if (bpi1->extra->vrfleak->bgp_orig->vrf_id !=
bpi2->extra->vrfleak->bgp_orig->vrf_id) {
compare = 1;
}
}
@ -185,78 +192,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
return compare;
}
/*
* bgp_path_info_mpath_cmp
*
* This function determines our multipath list ordering. By ordering
* the list we can deterministically select which paths are included
* in the multipath set. The ordering also helps in detecting changes
* in the multipath selection so we can detect whether to send an
* update to zebra.
*
* The order of paths is determined first by received nexthop, and then
* by peer address if the nexthops are the same.
*/
static int bgp_path_info_mpath_cmp(void *val1, void *val2)
{
struct bgp_path_info *bpi1, *bpi2;
int compare;
bpi1 = val1;
bpi2 = val2;
compare = bgp_path_info_nexthop_cmp(bpi1, bpi2);
if (!compare) {
if (!bpi1->peer->su_remote && !bpi2->peer->su_remote)
compare = 0;
else if (!bpi1->peer->su_remote)
compare = 1;
else if (!bpi2->peer->su_remote)
compare = -1;
else
compare = sockunion_cmp(bpi1->peer->su_remote,
bpi2->peer->su_remote);
}
return compare;
}
/*
* bgp_mp_list_init
*
* Initialize the mp_list, which holds the list of multipaths
* selected by bgp_best_selection
*/
void bgp_mp_list_init(struct list *mp_list)
{
assert(mp_list);
memset(mp_list, 0, sizeof(struct list));
mp_list->cmp = bgp_path_info_mpath_cmp;
}
/*
* bgp_mp_list_clear
*
* Clears all entries out of the mp_list
*/
void bgp_mp_list_clear(struct list *mp_list)
{
assert(mp_list);
list_delete_all_node(mp_list);
}
/*
* bgp_mp_list_add
*
* Adds a multipath entry to the mp_list
*/
void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
{
assert(mp_list && mpinfo);
listnode_add_sort(mp_list, mpinfo);
}
/*
* bgp_path_info_mpath_new
*
@ -269,6 +204,7 @@ static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath));
new_mpath->mp_count = 1;
return new_mpath;
}
@ -282,6 +218,8 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
if (mpath && *mpath) {
if ((*mpath)->mp_attr)
bgp_attr_unintern(&(*mpath)->mp_attr);
(*mpath)->mp_attr = NULL;
XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
}
}
@ -308,49 +246,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
return path->mpath;
}
/*
* bgp_path_info_mpath_enqueue
*
* Enqueue a path onto the multipath list given the previous multipath
* list entry
*/
static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info,
struct bgp_path_info *path)
{
struct bgp_path_info_mpath *prev, *mpath;
prev = bgp_path_info_mpath_get(prev_info);
mpath = bgp_path_info_mpath_get(path);
if (!prev || !mpath)
return;
mpath->mp_next = prev->mp_next;
mpath->mp_prev = prev;
if (prev->mp_next)
prev->mp_next->mp_prev = mpath;
prev->mp_next = mpath;
SET_FLAG(path->flags, BGP_PATH_MULTIPATH);
}
/*
* bgp_path_info_mpath_dequeue
*
* Remove a path from the multipath list
*/
void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
{
struct bgp_path_info_mpath *mpath = path->mpath;
if (!mpath)
return;
if (mpath->mp_prev)
mpath->mp_prev->mp_next = mpath->mp_next;
if (mpath->mp_next)
mpath->mp_next->mp_prev = mpath->mp_prev;
mpath->mp_next = mpath->mp_prev = NULL;
UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH);
}
/*
* bgp_path_info_mpath_next
*
@ -358,9 +253,16 @@ void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
*/
struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path)
{
if (!path->mpath || !path->mpath->mp_next)
return NULL;
return path->mpath->mp_next->mp_info;
path = path->next;
while (path) {
if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH))
return path;
path = path->next;
}
return NULL;
}
/*
@ -381,7 +283,8 @@ struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path)
uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path)
{
if (!path->mpath)
return 0;
return 1;
return path->mpath->mp_count;
}
@ -406,6 +309,10 @@ static void bgp_path_info_mpath_count_set(struct bgp_path_info *path,
* bgp_path_info_mpath_lb_update
*
* Update cumulative info related to link-bandwidth
*
* This is only set on the first mpath of the list
* as such we should UNSET the flags when removing
* to ensure nothing accidently happens
*/
static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set,
bool all_paths_lb, uint64_t cum_bw)
@ -467,10 +374,10 @@ bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path)
*/
if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING &&
bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING)
return (path->mpath->mp_flags & BGP_MP_LB_ALL);
return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_ALL);
/* At least one path should have bandwidth. */
return (path->mpath->mp_flags & BGP_MP_LB_PRESENT);
return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_PRESENT);
}
/*
@ -506,59 +413,51 @@ static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path,
/*
* bgp_path_info_mpath_update
*
* Compare and sync up the multipath list with the mp_list generated by
* bgp_best_selection
* Compare and sync up the multipath flags with what was choosen
* in best selection
*/
void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *new_best,
struct bgp_path_info *old_best,
struct list *mp_list,
struct bgp_maxpaths_cfg *mpath_cfg)
struct bgp_path_info *new_best, struct bgp_path_info *old_best,
uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg)
{
uint16_t maxpaths, mpath_count, old_mpath_count;
uint32_t bwval;
uint64_t bwval;
uint64_t cum_bw, old_cum_bw;
struct listnode *mp_node, *mp_next_node;
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
int mpath_changed, debug;
struct bgp_path_info *cur_iterator = NULL;
bool mpath_changed, debug;
bool all_paths_lb;
char path_buf[PATH_ADDPATH_STR_BUFFER];
bool old_mpath, new_mpath;
mpath_changed = 0;
mpath_changed = false;
maxpaths = multipath_num;
mpath_count = 0;
cur_mpath = NULL;
old_mpath_count = 0;
old_cum_bw = cum_bw = 0;
prev_mpath = new_best;
mp_node = listhead(mp_list);
debug = bgp_debug_bestpath(dest);
if (new_best) {
mpath_count++;
if (new_best != old_best)
bgp_path_info_mpath_dequeue(new_best);
maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
? mpath_cfg->maxpaths_ibgp
: mpath_cfg->maxpaths_ebgp;
}
if (old_best) {
cur_mpath = bgp_path_info_mpath_first(old_best);
old_mpath_count = bgp_path_info_mpath_count(old_best);
if (old_mpath_count == 1)
SET_FLAG(old_best->flags, BGP_PATH_MULTIPATH);
old_cum_bw = bgp_path_info_mpath_cumbw(old_best);
bgp_path_info_mpath_count_set(old_best, 0);
bgp_path_info_mpath_lb_update(old_best, false, false, 0);
bgp_path_info_mpath_dequeue(old_best);
bgp_path_info_mpath_free(&old_best->mpath);
old_best->mpath = NULL;
}
if (new_best) {
maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp
: mpath_cfg->maxpaths_ebgp;
cur_iterator = new_best;
}
if (debug)
zlog_debug(
"%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64,
bgp_dest_to_rnode(dest), bgp->name_pretty,
new_best ? new_best->peer->host : "NONE",
mp_list ? listcount(mp_list) : 0, old_mpath_count,
old_cum_bw);
zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64
" maxpaths set %u",
dest, bgp->name_pretty, new_best ? new_best->peer->host : "NONE",
num_candidates, old_mpath_count, old_cum_bw, maxpaths);
/*
* We perform an ordered walk through both lists in parallel.
@ -572,210 +471,105 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
* to skip over it
*/
all_paths_lb = true; /* We'll reset if any path doesn't have LB. */
while (mp_node || cur_mpath) {
struct bgp_path_info *tmp_info;
while (cur_iterator) {
old_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
new_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
/*
* We can bail out of this loop if all existing paths on the
* multipath list have been visited (for cleanup purposes) and
* the maxpath requirement is fulfulled
* If the current mpath count is equal to the number of
* maxpaths that can be used then we can bail, after
* we clean up the flags associated with the rest of the
* bestpaths
*/
if (!cur_mpath && (mpath_count >= maxpaths))
break;
if (mpath_count >= maxpaths) {
while (cur_iterator) {
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
next_mpath =
cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
tmp_info = mp_node ? listgetdata(mp_node) : NULL;
cur_iterator = cur_iterator->next;
}
if (debug)
zlog_debug("%pBD(%s): Mpath count %u is equal to maximum paths allowed, finished comparision for MPATHS",
dest, bgp->name_pretty, mpath_count);
break;
}
if (debug)
zlog_debug(
"%pRN(%s): comparing candidate %s with existing mpath %s",
bgp_dest_to_rnode(dest), bgp->name_pretty,
tmp_info ? tmp_info->peer->host : "NONE",
cur_mpath ? cur_mpath->peer->host : "NONE");
zlog_debug("%pBD(%s): Candidate %s old_mpath: %u new_mpath: %u, Nexthop %pI4 current mpath count: %u",
dest, bgp->name_pretty, cur_iterator->peer->host, old_mpath,
new_mpath, &cur_iterator->attr->nexthop, mpath_count);
/*
* If equal, the path was a multipath and is still a multipath.
* Insert onto new multipath list if maxpaths allows.
* There is nothing to do if the cur_iterator is neither a old path
* or a new path
*/
if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
list_delete_node(mp_list, mp_node);
bgp_path_info_mpath_dequeue(cur_mpath);
if ((mpath_count < maxpaths)
&& prev_mpath
&& bgp_path_info_nexthop_cmp(prev_mpath,
cur_mpath)) {
bgp_path_info_mpath_enqueue(prev_mpath,
cur_mpath);
prev_mpath = cur_mpath;
mpath_count++;
if (ecommunity_linkbw_present(
bgp_attr_get_ecommunity(
cur_mpath->attr),
&bwval))
cum_bw += bwval;
else
all_paths_lb = false;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf,
sizeof(path_buf));
zlog_debug(
"%pRN: %s is still multipath, cur count %d",
bgp_dest_to_rnode(dest),
path_buf, mpath_count);
}
} else {
mpath_changed = 1;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf,
sizeof(path_buf));
zlog_debug(
"%pRN: remove mpath %s nexthop %pI4, cur count %d",
bgp_dest_to_rnode(dest),
path_buf,
&cur_mpath->attr->nexthop,
mpath_count);
}
}
mp_node = mp_next_node;
cur_mpath = next_mpath;
if (!old_mpath && !new_mpath) {
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
cur_iterator = cur_iterator->next;
continue;
}
if (cur_mpath
&& (!mp_node
|| (bgp_path_info_mpath_cmp(cur_mpath,
listgetdata(mp_node))
< 0))) {
/*
* If here, we have an old multipath and either the
* mp_list
* is finished or the next mp_node points to a later
* multipath, so we need to purge this path from the
* multipath list
*/
bgp_path_info_mpath_dequeue(cur_mpath);
mpath_changed = 1;
if (new_mpath) {
mpath_count++;
if (cur_iterator != new_best)
SET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
if (!old_mpath)
mpath_changed = true;
if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(cur_iterator->attr),
&bwval) ||
ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
cur_iterator->attr),
&bwval))
cum_bw += bwval;
else
all_paths_lb = false;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf, sizeof(path_buf));
zlog_debug(
"%pRN: remove mpath %s nexthop %pI4, cur count %d",
bgp_dest_to_rnode(dest), path_buf,
&cur_mpath->attr->nexthop, mpath_count);
bgp_path_info_path_with_addpath_rx_str(cur_iterator, path_buf,
sizeof(path_buf));
zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d cum_bw: %" PRIu64
" all_paths_lb: %u",
dest, path_buf, &cur_iterator->attr->nexthop,
mpath_count, cum_bw, all_paths_lb);
}
cur_mpath = next_mpath;
} else {
/*
* If here, we have a path on the mp_list that was not
* previously
* a multipath (due to non-equivalance or maxpaths
* exceeded),
* or the matching multipath is sorted later in the
* multipath
* list. Before we enqueue the path on the new multipath
* list,
* make sure its not on the old_best multipath list or
* referenced
* via next_mpath:
* - If next_mpath points to this new path, update
* next_mpath to
* point to the multipath after this one
* - Dequeue the path from the multipath list just to
* make sure
* We know that old_mpath is true and new_mpath is false in this path
*/
new_mpath = listgetdata(mp_node);
list_delete_node(mp_list, mp_node);
assert(new_mpath);
assert(prev_mpath);
if ((mpath_count < maxpaths) && (new_mpath != new_best)
&& bgp_path_info_nexthop_cmp(prev_mpath,
new_mpath)) {
bgp_path_info_mpath_dequeue(new_mpath);
bgp_path_info_mpath_enqueue(prev_mpath,
new_mpath);
prev_mpath = new_mpath;
mpath_changed = 1;
mpath_count++;
if (ecommunity_linkbw_present(
bgp_attr_get_ecommunity(
new_mpath->attr),
&bwval))
cum_bw += bwval;
else
all_paths_lb = false;
if (debug) {
bgp_path_info_path_with_addpath_rx_str(
new_mpath, path_buf,
sizeof(path_buf));
zlog_debug(
"%pRN: add mpath %s nexthop %pI4, cur count %d",
bgp_dest_to_rnode(dest),
path_buf,
&new_mpath->attr->nexthop,
mpath_count);
}
}
mp_node = mp_next_node;
mpath_changed = true;
UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
}
cur_iterator = cur_iterator->next;
}
if (new_best) {
bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
if (mpath_count <= 1 ||
!ecommunity_linkbw_present(
bgp_attr_get_ecommunity(new_best->attr), &bwval))
all_paths_lb = false;
else
cum_bw += bwval;
bgp_path_info_mpath_lb_update(new_best, true,
all_paths_lb, cum_bw);
if (mpath_count > 1 || new_best->mpath) {
bgp_path_info_mpath_count_set(new_best, mpath_count);
bgp_path_info_mpath_lb_update(new_best, true, all_paths_lb, cum_bw);
}
if (debug)
zlog_debug(
"%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
bgp_dest_to_rnode(dest), bgp->name_pretty,
mpath_count, mpath_changed ? "YES" : "NO",
all_paths_lb, cum_bw);
zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
dest, bgp->name_pretty, mpath_count,
mpath_changed ? "YES" : "NO", all_paths_lb,
cum_bw);
if (mpath_count == 1)
UNSET_FLAG(new_best->flags, BGP_PATH_MULTIPATH);
if (mpath_changed
|| (bgp_path_info_mpath_count(new_best) != old_mpath_count))
SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
if ((mpath_count - 1) != old_mpath_count ||
old_cum_bw != cum_bw)
if ((mpath_count) != old_mpath_count || old_cum_bw != cum_bw)
SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG);
}
}
/*
* bgp_mp_dmed_deselect
*
* Clean up multipath information for BGP_PATH_DMED_SELECTED path that
* is not selected as best path
*/
void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
{
struct bgp_path_info *mpinfo, *mpnext;
if (!dmed_best)
return;
for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo;
mpinfo = mpnext) {
mpnext = bgp_path_info_mpath_next(mpinfo);
bgp_path_info_mpath_dequeue(mpinfo);
}
bgp_path_info_mpath_count_set(dmed_best, 0);
UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG);
assert(bgp_path_info_mpath_first(dmed_best) == NULL);
}
/*
* bgp_path_info_mpath_aggregate_update
*
@ -810,7 +604,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
if (!new_best)
return;
if (!bgp_path_info_mpath_count(new_best)) {
if (bgp_path_info_mpath_count(new_best) == 1) {
if ((new_attr = bgp_path_info_mpath_attr(new_best))) {
bgp_attr_unintern(&new_attr);
bgp_path_info_mpath_attr_set(new_best, NULL);

View file

@ -2,8 +2,9 @@
/*
* BGP Multipath
* Copyright (C) 2010 Google Inc.
* 2024 Nvidia Corporation
*
* This file is part of Quagga
* This file is part of FRR
*/
#ifndef _FRR_BGP_MPATH_H
@ -13,27 +14,24 @@
* multipath selections, lazily allocated to save memory
*/
struct bgp_path_info_mpath {
/* Points to the first multipath (on bestpath) or the next multipath */
struct bgp_path_info_mpath *mp_next;
/* Points to the previous multipath or NULL on bestpath */
struct bgp_path_info_mpath *mp_prev;
/* Points to bgp_path_info associated with this multipath info */
struct bgp_path_info *mp_info;
/* When attached to best path, the number of selected multipaths */
uint16_t mp_count;
/* Flags - relevant as noted. */
/* Flags - relevant as noted, attached to bestpath. */
uint16_t mp_flags;
#define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */
#define BGP_MP_LB_ALL 0x2 /* Link-bandwidth present for all multipaths */
/* Aggregated attribute for advertising multipath route */
/*
* Aggregated attribute for advertising multipath route,
* attached to bestpath
*/
struct attr *mp_attr;
/* Cumulative bandiwdth of all multipaths - attached to best path. */
/* Cumulative bandiwdth of all multipaths - attached to bestpath. */
uint64_t cum_bw;
};
@ -47,23 +45,16 @@ extern int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
/* Functions used by bgp_best_selection to record current
* multipath selections
*/
extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
struct bgp_path_info *bpi2);
extern void bgp_mp_list_init(struct list *mp_list);
extern void bgp_mp_list_clear(struct list *mp_list);
extern void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo);
extern void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best);
extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, struct bgp_path_info *bpi2);
extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *new_best,
struct bgp_path_info *old_best,
struct list *mp_list,
struct bgp_path_info *old_best, uint32_t num_candidates,
struct bgp_maxpaths_cfg *mpath_cfg);
extern void
bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
struct bgp_path_info *old_best);
/* Unlink and free multipath information associated with a bgp_path_info */
extern void bgp_path_info_mpath_dequeue(struct bgp_path_info *path);
extern void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath);
/* Walk list of multipaths associated with a best path */

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_label.h"
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
#define MPLS_LABEL_IS_NULL(label) \
@ -31,6 +32,7 @@
#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH 20
extern void bgp_mplsvpn_init(void);
extern void bgp_mplsvpn_path_nh_label_unlink(struct bgp_path_info *pi);
extern int bgp_nlri_parse_vpn(struct peer *, struct attr *, struct bgp_nlri *);
extern uint32_t decode_label(mpls_label_t *);
extern void encode_label(mpls_label_t, mpls_label_t *);
@ -55,10 +57,17 @@ extern void vpn_leak_from_vrf_update_all(struct bgp *to_bgp,
extern void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi);
extern void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from,
afi_t afi);
extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
extern bool vpn_leak_to_vrf_no_retain_filter_check(struct bgp *from_bgp,
struct attr *attr,
afi_t afi);
extern void vpn_leak_to_vrf_update(struct bgp *from_bgp,
struct bgp_path_info *path_vpn,
struct prefix_rd *prd);
@ -104,7 +113,8 @@ static inline bool is_bgp_vrf_mplsvpn(struct bgp *bgp)
}
static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
const char **pmsg)
const char **pmsg,
bool ignore_export_rt_list)
{
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
&& bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
@ -124,8 +134,21 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
return 0;
}
/* Is there an RT list set? */
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
/* Before performing withdrawal, VPN activation is checked; however,
* when the route-map modifies the export route-target (RT) list, it
* becomes challenging to determine if VPN prefixes were previously
* present, or not. The 'ignore_export_rt_list' parameter will be
* used to force the withdraw operation by not checking the possible
* route-map changes.
* Of the 'ignore_export_rt_list' is set to false, check the following:
* - Is there an RT list set?
* - Is there a route-map that sets RT communities
*/
if (!ignore_export_rt_list &&
!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] &&
(!bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] ||
!bgp_route_map_has_extcommunity_rt(
bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]))) {
if (pmsg)
*pmsg = "rtlist tovpn not defined";
return 0;
@ -147,14 +170,23 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
return 0;
}
/* Is there an "auto" export label that isn't allocated yet? */
if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
(bgp_vrf->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)) {
if (pmsg)
*pmsg = "auto label not allocated";
return 0;
/* Is there a "manual" export label that isn't allocated yet? */
if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
bgp_vrf->vpn_policy[afi].tovpn_label != BGP_PREVENT_VRF_2_VRF_LEAK &&
bgp_vrf->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE &&
(bgp_vrf->vpn_policy[afi].tovpn_label >= MPLS_LABEL_UNRESERVED_MIN &&
!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG))) {
if (!bgp_zebra_request_label_range(bgp_vrf->vpn_policy[afi]
.tovpn_label,
1, false)) {
if (pmsg)
*pmsg = "manual label could not be allocated";
return 0;
}
SET_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG);
}
return 1;
@ -218,8 +250,7 @@ static inline void vpn_leak_prechange(enum vpn_policy_direction direction,
vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi);
}
if ((direction == BGP_VPN_POLICY_DIR_TOVPN) &&
vpn_leak_to_vpn_active(bgp_vrf, afi, NULL)) {
vpn_leak_to_vpn_active(bgp_vrf, afi, NULL, true)) {
vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi);
}
}
@ -237,8 +268,7 @@ static inline void vpn_leak_postchange(enum vpn_policy_direction direction,
if (!CHECK_FLAG(bgp_vpn->af_flags[afi][SAFI_MPLS_VPN],
BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL))
bgp_clear_soft_in(bgp_vpn, afi, SAFI_MPLS_VPN);
else
vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi);
}
if (direction == BGP_VPN_POLICY_DIR_TOVPN) {
@ -290,12 +320,11 @@ static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
struct bgp_table *table;
struct bgp_dest *dest;
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
!pi->extra ||
!pi->extra->parent)
if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra ||
!pi->extra->vrfleak || !pi->extra->vrfleak->parent)
return true;
parent_pi = (struct bgp_path_info *)pi->extra->parent;
parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent;
dest = parent_pi->net;
if (!dest)
return true;
@ -324,4 +353,74 @@ extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
extern void bgp_vpn_leak_unimport(struct bgp *from_bgp);
extern void bgp_vpn_leak_export(struct bgp *from_bgp);
extern bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi);
extern int
bgp_mplsvpn_nh_label_bind_cmp(const struct bgp_mplsvpn_nh_label_bind_cache *a,
const struct bgp_mplsvpn_nh_label_bind_cache *b);
extern void bgp_mplsvpn_path_nh_label_bind_unlink(struct bgp_path_info *pi);
extern void bgp_mplsvpn_nh_label_bind_register_local_label(
struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi);
mpls_label_t bgp_mplsvpn_nh_label_bind_get_label(struct bgp_path_info *pi);
/* used to bind a local label to the (label, nexthop) values
* from an incoming BGP mplsvpn update
*/
struct bgp_mplsvpn_nh_label_bind_cache {
/* RB-tree entry. */
struct bgp_mplsvpn_nh_label_bind_cache_item entry;
/* The nexthop and the vpn label are the key of the list.
* Only received BGP MPLSVPN updates may use that structure.
* orig_label is the original label received from the BGP Update.
*/
struct prefix nexthop;
mpls_label_t orig_label;
/* resolved interface for the paths */
struct nexthop *nh;
/* number of mplsvpn path */
unsigned int path_count;
/* back pointer to bgp instance */
struct bgp *bgp_vpn;
/* MPLS label allocated value.
* When the next-hop is changed because of 'next-hop-self' or
* because it is an eBGP peer, the redistributed orig_label value
* is unmodified, unless the 'l3vpn-multi-domain-switching'
* is enabled: a new_label value is allocated:
* - The new_label value is sent in the advertised BGP update,
* instead of the label value.
* - An MPLS entry is set to swap <new_label> with <orig_label>.
*/
mpls_label_t new_label;
/* list of path_vrfs using it */
LIST_HEAD(mplsvpn_nh_label_bind_path_lists, bgp_path_info) paths;
time_t last_update;
bool allocation_in_progress;
};
DECLARE_RBTREE_UNIQ(bgp_mplsvpn_nh_label_bind_cache,
struct bgp_mplsvpn_nh_label_bind_cache, entry,
bgp_mplsvpn_nh_label_bind_cmp);
void bgp_mplsvpn_nh_label_bind_free(
struct bgp_mplsvpn_nh_label_bind_cache *bmnc);
struct bgp_mplsvpn_nh_label_bind_cache *
bgp_mplsvpn_nh_label_bind_new(struct bgp_mplsvpn_nh_label_bind_cache_head *tree,
struct prefix *p, mpls_label_t orig_label);
struct bgp_mplsvpn_nh_label_bind_cache *bgp_mplsvpn_nh_label_bind_find(
struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p,
mpls_label_t orig_label);
void bgp_mplsvpn_nexthop_init(void);
extern void sid_register(struct bgp *bgp, const struct in6_addr *sid,
const char *locator_name);
extern void sid_unregister(struct bgp *bgp, const struct in6_addr *sid);
#endif /* _QUAGGA_BGP_MPLSVPN_H */

View file

@ -511,8 +511,8 @@ static int bgp_init_snmp_stats(struct bgp *bgp)
{
if (is_bgp_vrf_mplsvpn(bgp)) {
if (bgp->snmp_stats == NULL) {
bgp->snmp_stats = XCALLOC(
MTYPE_BGP, sizeof(struct bgp_snmp_stats));
bgp->snmp_stats = XCALLOC(MTYPE_BGP_NAME,
sizeof(struct bgp_snmp_stats));
/* fix up added routes */
if (bgp->snmp_stats) {
bgp->snmp_stats->routes_added =
@ -523,7 +523,7 @@ static int bgp_init_snmp_stats(struct bgp *bgp)
}
} else {
if (bgp->snmp_stats) {
XFREE(MTYPE_BGP, bgp->snmp_stats);
XFREE(MTYPE_BGP_NAME, bgp->snmp_stats);
bgp->snmp_stats = NULL;
}
}
@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp)
/* add trap in here */
bgp->snmp_stats->active = new_active;
if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) {
bgp_mpls_l3vpn_update_last_changed(bgp);
return 0;
}
/* send relevent trap */
if (bgp->snmp_stats->active)
trap = MPLSL3VPNVRFUP;

View file

@ -35,7 +35,7 @@
extern struct zebra_privs_t bgpd_privs;
static char *bgp_get_bound_name(struct peer *peer);
static char *bgp_get_bound_name(struct peer_connection *connection);
void bgp_dump_listener_info(struct vty *vty)
{
@ -117,11 +117,13 @@ static int bgp_md5_set_connect(int socket, union sockunion *su,
return ret;
}
static int bgp_md5_set_password(struct peer *peer, const char *password)
static int bgp_md5_set_password(struct peer_connection *connection,
const char *password)
{
struct listnode *node;
int ret = 0;
struct bgp_listener *listener;
struct peer *peer = connection->peer;
/*
* Set or unset the password on the listen socket(s). Outbound
@ -130,9 +132,9 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
if (listener->su.sa.sa_family ==
peer->su.sa.sa_family) {
connection->su.sa.sa_family) {
uint16_t prefixlen =
peer->su.sa.sa_family == AF_INET
connection->su.sa.sa_family == AF_INET
? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN;
@ -149,8 +151,8 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
continue;
ret = bgp_md5_set_socket(listener->fd,
&peer->su, prefixlen,
password);
&connection->su,
prefixlen, password);
break;
}
}
@ -186,10 +188,10 @@ int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p)
return bgp_md5_set_prefix(bgp, p, NULL);
}
int bgp_md5_set(struct peer *peer)
int bgp_md5_set(struct peer_connection *connection)
{
/* Set the password from listen socket. */
return bgp_md5_set_password(peer, peer->password);
return bgp_md5_set_password(connection, connection->peer->password);
}
static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd)
@ -211,18 +213,20 @@ static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd)
}
}
int bgp_md5_unset(struct peer *peer)
int bgp_md5_unset(struct peer_connection *connection)
{
/* Unset the password from listen socket. */
return bgp_md5_set_password(peer, NULL);
return bgp_md5_set_password(connection, NULL);
}
int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
int bgp_set_socket_ttl(struct peer_connection *connection)
{
int ret = 0;
struct peer *peer = connection->peer;
if (!peer->gtsm_hops) {
ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl);
ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd,
peer->ttl);
if (ret) {
flog_err(
EC_LIB_SOCKET,
@ -235,7 +239,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
with the
outgoing ttl. Therefore setting both.
*/
ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL);
ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd,
MAXTTL);
if (ret) {
flog_err(
EC_LIB_SOCKET,
@ -243,7 +248,7 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
__func__, &peer->remote_id, errno);
return ret;
}
ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock,
ret = sockopt_minttl(connection->su.sa.sa_family, connection->fd,
MAXTTL + 1 - peer->gtsm_hops);
if (ret) {
flog_err(
@ -329,6 +334,53 @@ static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst)
#endif
}
int bgp_tcp_mss_set(struct peer *peer)
{
struct listnode *node;
int ret = 0;
struct bgp_listener *listener;
uint32_t min_mss = 0;
struct peer *p;
for (ALL_LIST_ELEMENTS_RO(peer->bgp->peer, node, p)) {
if (!CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS))
continue;
if (!p->tcp_mss)
continue;
if (!min_mss)
min_mss = p->tcp_mss;
min_mss = MIN(min_mss, p->tcp_mss);
}
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) {
if (listener->su.sa.sa_family !=
peer->connection->su.sa.sa_family)
continue;
if (!listener->bgp) {
if (peer->bgp->vrf_id != VRF_DEFAULT)
continue;
} else if (listener->bgp != peer->bgp)
continue;
/* Set TCP MSS per listener only if there is at least
* one peer that is in passive mode. Otherwise, TCP MSS
* is set per socket via bgp_connect().
*/
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE))
sockopt_tcp_mss_set(listener->fd, min_mss);
break;
}
}
return ret;
}
static void bgp_socket_set_buffer_size(const int fd)
{
if (getsockopt_so_sendbuf(fd) < (int)bm->socket_buffer)
@ -344,8 +396,8 @@ static void bgp_accept(struct event *thread)
int accept_sock;
union sockunion su;
struct bgp_listener *listener = EVENT_ARG(thread);
struct peer *peer;
struct peer *peer1;
struct peer *peer, *peer1;
struct peer_connection *connection, *connection1;
char buf[SU_ADDRSTRLEN];
struct bgp *bgp = NULL;
@ -428,25 +480,37 @@ static void bgp_accept(struct event *thread)
if (!peer1) {
peer1 = peer_lookup_dynamic_neighbor(bgp, &su);
if (peer1) {
connection1 = peer1->connection;
/* Dynamic neighbor has been created, let it proceed */
peer1->fd = bgp_sock;
connection1->fd = bgp_sock;
if (bgp_set_socket_ttl(connection1) < 0) {
peer1->last_reset = PEER_DOWN_SOCKET_ERROR;
zlog_err("%s: Unable to set min/max TTL on peer %s (dynamic), error received: %s(%d)",
__func__, peer1->host,
safe_strerror(errno), errno);
return;
}
/* Set the user configured MSS to TCP socket */
if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS))
sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss);
bgp_fsm_change_status(peer1, Active);
EVENT_OFF(
peer1->t_start); /* created in peer_create() */
frr_with_privs (&bgpd_privs) {
vrf_bind(peer1->bgp->vrf_id, bgp_sock,
bgp_get_bound_name(connection1));
}
bgp_peer_reg_with_nht(peer1);
bgp_fsm_change_status(connection1, Active);
EVENT_OFF(connection1->t_start);
if (peer_active(peer1)) {
if (CHECK_FLAG(peer1->flags,
PEER_FLAG_TIMER_DELAYOPEN))
BGP_EVENT_ADD(
peer1,
TCP_connection_open_w_delay);
BGP_EVENT_ADD(connection1,
TCP_connection_open_w_delay);
else
BGP_EVENT_ADD(peer1,
BGP_EVENT_ADD(connection1,
TCP_connection_open);
}
@ -465,6 +529,7 @@ static void bgp_accept(struct event *thread)
return;
}
connection1 = peer1->connection;
if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN)
|| CHECK_FLAG(peer1->bgp->flags, BGP_FLAG_SHUTDOWN)) {
if (bgp_debug_neighbor_events(peer1))
@ -482,11 +547,11 @@ static void bgp_accept(struct event *thread)
* Established and then the Clearing_Completed event is generated. Also,
* block incoming connection in Deleted state.
*/
if (peer1->status == Clearing || peer1->status == Deleted) {
if (connection1->status == Clearing || connection1->status == Deleted) {
if (bgp_debug_neighbor_events(peer1))
zlog_debug(
"[Event] Closing incoming conn for %s (%p) state %d",
peer1->host, peer1, peer1->status);
zlog_debug("[Event] Closing incoming conn for %s (%p) state %d",
peer1->host, peer1,
peer1->connection->status);
close(bgp_sock);
return;
}
@ -521,10 +586,9 @@ static void bgp_accept(struct event *thread)
}
if (bgp_debug_neighbor_events(peer1))
zlog_debug(
"[Event] connection from %s fd %d, active peer status %d fd %d",
inet_sutop(&su, buf), bgp_sock, peer1->status,
peer1->fd);
zlog_debug("[Event] connection from %s fd %d, active peer status %d fd %d",
inet_sutop(&su, buf), bgp_sock, connection1->status,
connection1->fd);
if (peer1->doppelganger) {
/* We have an existing connection. Kill the existing one and run
@ -537,15 +601,11 @@ static void bgp_accept(struct event *thread)
peer_delete(peer1->doppelganger);
}
if (bgp_set_socket_ttl(peer1, bgp_sock) < 0)
if (bgp_debug_neighbor_events(peer1))
zlog_debug(
"[Event] Unable to set min/max TTL on peer %s, Continuing",
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
peer1->as, peer1->as_type, NULL, false, NULL);
connection = peer->connection;
peer_xfer_config(peer, peer1);
bgp_peer_gr_flags_update(peer);
@ -563,18 +623,25 @@ static void bgp_accept(struct event *thread)
peer->doppelganger = peer1;
peer1->doppelganger = peer;
peer->fd = bgp_sock;
connection->fd = bgp_sock;
if (bgp_set_socket_ttl(connection) < 0)
if (bgp_debug_neighbor_events(peer))
zlog_debug("[Event] Unable to set min/max TTL on peer %s, Continuing",
peer->host);
frr_with_privs(&bgpd_privs) {
vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer));
vrf_bind(peer->bgp->vrf_id, bgp_sock,
bgp_get_bound_name(peer->connection));
}
bgp_peer_reg_with_nht(peer);
bgp_fsm_change_status(peer, Active);
EVENT_OFF(peer->t_start); /* created in peer_create() */
bgp_fsm_change_status(connection, Active);
EVENT_OFF(connection->t_start); /* created in peer_create() */
SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
/* Make dummy peer until read Open packet. */
if (peer_established(peer1)
&& CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
if (peer_established(connection1) &&
CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
/* If we have an existing established connection with graceful
* restart
* capability announced with one or more address families, then
@ -588,14 +655,14 @@ static void bgp_accept(struct event *thread)
PEER_FLAG_GRACEFUL_RESTART_HELPER))
SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT);
bgp_event_update(peer1, TCP_connection_closed);
bgp_event_update(connection1, TCP_connection_closed);
}
if (peer_active(peer)) {
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
BGP_EVENT_ADD(peer, TCP_connection_open_w_delay);
BGP_EVENT_ADD(connection, TCP_connection_open_w_delay);
else
BGP_EVENT_ADD(peer, TCP_connection_open);
BGP_EVENT_ADD(connection, TCP_connection_open);
}
/*
@ -606,24 +673,23 @@ static void bgp_accept(struct event *thread)
}
/* BGP socket bind. */
static char *bgp_get_bound_name(struct peer *peer)
static char *bgp_get_bound_name(struct peer_connection *connection)
{
if (!peer)
return NULL;
struct peer *peer = connection->peer;
if ((peer->bgp->vrf_id == VRF_DEFAULT) && !peer->ifname
&& !peer->conf_if)
return NULL;
if (peer->su.sa.sa_family != AF_INET
&& peer->su.sa.sa_family != AF_INET6)
if (connection->su.sa.sa_family != AF_INET &&
connection->su.sa.sa_family != AF_INET6)
return NULL; // unexpected
/* 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->su.sa.sa_family == AF_INET6 && peer->conf_if)
if (connection->su.sa.sa_family == AF_INET6 && peer->conf_if)
return peer->conf_if;
if (peer->ifname)
@ -640,7 +706,6 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst,
{
struct prefix *p, *sel, d;
struct connected *connected;
struct listnode *node;
int common;
if (!sockunion2hostprefix(dst, &d))
@ -649,7 +714,7 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst,
sel = NULL;
common = -1;
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
frr_each (if_connected, ifp->connected, connected) {
p = connected->address;
if (p->family != d.family)
continue;
@ -667,11 +732,12 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst,
}
/* Update source selection. */
static int bgp_update_source(struct peer *peer)
static int bgp_update_source(struct peer_connection *connection)
{
struct interface *ifp;
union sockunion addr;
int ret = 0;
struct peer *peer = connection->peer;
sockunion_init(&addr);
@ -681,38 +747,41 @@ static int bgp_update_source(struct peer *peer)
if (!ifp)
return -1;
if (bgp_update_address(ifp, &peer->su, &addr))
if (bgp_update_address(ifp, &connection->su, &addr))
return -1;
ret = sockunion_bind(peer->fd, &addr, 0, &addr);
ret = sockunion_bind(connection->fd, &addr, 0, &addr);
}
/* Source is specified with IP address. */
if (peer->update_source)
ret = sockunion_bind(peer->fd, peer->update_source, 0,
ret = sockunion_bind(connection->fd, peer->update_source, 0,
peer->update_source);
return ret;
}
/* BGP try to connect to the peer. */
int bgp_connect(struct peer *peer)
int bgp_connect(struct peer_connection *connection)
{
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON));
struct peer *peer = connection->peer;
assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON));
assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON));
ifindex_t ifindex = 0;
if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) {
if (peer->conf_if && BGP_CONNECTION_SU_UNSPEC(connection)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("Peer address not learnt: Returning from connect");
return 0;
}
frr_with_privs(&bgpd_privs) {
/* Make socket for the peer. */
peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id,
bgp_get_bound_name(peer));
/* Make socket for the peer. */
connection->fd =
vrf_sockunion_socket(&connection->su, peer->bgp->vrf_id,
bgp_get_bound_name(connection));
}
if (peer->fd < 0) {
if (connection->fd < 0) {
peer->last_reset = PEER_DOWN_SOCKET_ERROR;
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s: Failure to create socket for connection to %s, error received: %s(%d)",
@ -721,18 +790,18 @@ int bgp_connect(struct peer *peer)
return -1;
}
set_nonblocking(peer->fd);
set_nonblocking(connection->fd);
/* Set the user configured MSS to TCP socket */
if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS))
sockopt_tcp_mss_set(peer->fd, peer->tcp_mss);
sockopt_tcp_mss_set(connection->fd, peer->tcp_mss);
bgp_socket_set_buffer_size(peer->fd);
bgp_socket_set_buffer_size(connection->fd);
/* Set TCP keepalive when TCP keepalive is enabled */
bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd);
bgp_update_setsockopt_tcp_keepalive(peer->bgp, connection->fd);
if (bgp_set_socket_ttl(peer, peer->fd) < 0) {
if (bgp_set_socket_ttl(peer->connection) < 0) {
peer->last_reset = PEER_DOWN_SOCKET_ERROR;
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)",
@ -742,36 +811,42 @@ int bgp_connect(struct peer *peer)
return -1;
}
sockopt_reuseaddr(peer->fd);
sockopt_reuseport(peer->fd);
sockopt_reuseaddr(connection->fd);
sockopt_reuseport(connection->fd);
#ifdef IPTOS_PREC_INTERNETCONTROL
frr_with_privs(&bgpd_privs) {
if (sockunion_family(&peer->su) == AF_INET)
setsockopt_ipv4_tos(peer->fd, bm->tcp_dscp);
else if (sockunion_family(&peer->su) == AF_INET6)
setsockopt_ipv6_tclass(peer->fd, bm->tcp_dscp);
if (sockunion_family(&connection->su) == AF_INET)
setsockopt_ipv4_tos(connection->fd, bm->ip_tos);
else if (sockunion_family(&connection->su) == AF_INET6)
setsockopt_ipv6_tclass(connection->fd, bm->ip_tos);
}
#endif
if (peer->password) {
uint16_t prefixlen = peer->su.sa.sa_family == AF_INET
uint16_t prefixlen = peer->connection->su.sa.sa_family == AF_INET
? IPV4_MAX_BITLEN
: IPV6_MAX_BITLEN;
if (!BGP_PEER_SU_UNSPEC(peer))
bgp_md5_set(peer);
if (!BGP_CONNECTION_SU_UNSPEC(connection))
bgp_md5_set(connection);
bgp_md5_set_connect(peer->fd, &peer->su, prefixlen,
bgp_md5_set_connect(connection->fd, &connection->su, prefixlen,
peer->password);
}
/* Update source bind. */
if (bgp_update_source(peer) < 0) {
if (bgp_update_source(connection) < 0) {
peer->last_reset = PEER_DOWN_SOCKET_ERROR;
return connect_error;
}
/* If the peer is passive mode, force to move to Active mode. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
BGP_EVENT_ADD(connection, TCP_connection_open_failed);
return BGP_FSM_SUCCESS;
}
if (peer->conf_if || peer->ifname)
ifindex = ifname2ifindex(peer->conf_if ? peer->conf_if
: peer->ifname,
@ -779,15 +854,14 @@ int bgp_connect(struct peer *peer)
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [Event] Connect start to %s fd %d", peer->host,
peer->host, peer->fd);
peer->host, connection->fd);
/* Connect to the remote peer. */
return sockunion_connect(peer->fd, &peer->su, htons(peer->port),
ifindex);
return sockunion_connect(connection->fd, &connection->su,
htons(peer->port), ifindex);
}
/* After TCP connection is established. Get local address and port. */
int bgp_getsockname(struct peer *peer)
void bgp_updatesockname(struct peer *peer)
{
if (peer->su_local) {
sockunion_free(peer->su_local);
@ -799,19 +873,22 @@ int bgp_getsockname(struct peer *peer)
peer->su_remote = NULL;
}
peer->su_local = sockunion_getsockname(peer->fd);
if (!peer->su_local)
return -1;
peer->su_remote = sockunion_getpeername(peer->fd);
if (!peer->su_remote)
return -1;
peer->su_local = sockunion_getsockname(peer->connection->fd);
peer->su_remote = sockunion_getpeername(peer->connection->fd);
}
/* After TCP connection is established. Get local address and port. */
int bgp_getsockname(struct peer *peer)
{
bgp_updatesockname(peer);
if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
&peer->nexthop, peer)) {
flog_err(
EC_BGP_NH_UPD,
"%s: nexthop_set failed, resetting connection - intf %s",
peer->host,
"%s: nexthop_set failed, local: %pSUp remote: %pSUp update_if: %s resetting connection - intf %s",
peer->host, peer->su_local, peer->su_remote,
peer->update_if ? peer->update_if : "(None)",
peer->nexthop.ifp ? peer->nexthop.ifp->name
: "(Unknown)");
return -1;
@ -833,9 +910,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
#ifdef IPTOS_PREC_INTERNETCONTROL
if (sa->sa_family == AF_INET)
setsockopt_ipv4_tos(sock, bm->tcp_dscp);
setsockopt_ipv4_tos(sock, bm->ip_tos);
else if (sa->sa_family == AF_INET6)
setsockopt_ipv6_tclass(sock, bm->tcp_dscp);
setsockopt_ipv6_tclass(sock, bm->ip_tos);
#endif
sockopt_v6only(sa->sa_family, sock);

View file

@ -21,15 +21,17 @@ extern int bgp_socket(struct bgp *bgp, unsigned short port,
const char *address);
extern void bgp_close_vrf_socket(struct bgp *bgp);
extern void bgp_close(void);
extern int bgp_connect(struct peer *);
extern int bgp_getsockname(struct peer *);
extern int bgp_connect(struct peer_connection *connection);
extern int bgp_getsockname(struct peer *peer);
extern void bgp_updatesockname(struct peer *peer);
extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p,
const char *password);
extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p);
extern int bgp_md5_set(struct peer *);
extern int bgp_md5_unset(struct peer *);
extern int bgp_set_socket_ttl(struct peer *, int fd);
extern int bgp_md5_set(struct peer_connection *connection);
extern int bgp_md5_unset(struct peer_connection *connection);
extern int bgp_set_socket_ttl(struct peer_connection *connection);
extern int bgp_tcp_mss_set(struct peer *peer);
extern int bgp_update_address(struct interface *ifp, const union sockunion *dst,
union sockunion *addr);

View file

@ -31,6 +31,7 @@
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_mplsvpn.h"
DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Addr Intf String");
@ -42,9 +43,9 @@ int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
if (a->srte_color > b->srte_color)
return 1;
if (a->ifindex < b->ifindex)
if (a->ifindex_ipv6_ll < b->ifindex_ipv6_ll)
return -1;
if (a->ifindex > b->ifindex)
if (a->ifindex_ipv6_ll > b->ifindex_ipv6_ll)
return 1;
return prefix_cmp(&a->prefix, &b->prefix);
@ -64,7 +65,7 @@ struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
sizeof(struct bgp_nexthop_cache));
bnc->prefix = *prefix;
bnc->ifindex = ifindex;
bnc->ifindex_ipv6_ll = ifindex;
bnc->srte_color = srte_color;
bnc->tree = tree;
LIST_INIT(&(bnc->paths));
@ -104,7 +105,7 @@ struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
bnc.prefix = *prefix;
bnc.srte_color = srte_color;
bnc.ifindex = ifindex;
bnc.ifindex_ipv6_ll = ifindex;
return bgp_nexthop_cache_find(tree, &bnc);
}
@ -119,6 +120,9 @@ static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)
while (!LIST_EMPTY(&(bnc->paths))) {
struct bgp_path_info *path = LIST_FIRST(&(bnc->paths));
bgp_mplsvpn_path_nh_label_unlink(path);
bgp_mplsvpn_path_nh_label_bind_unlink(path);
path_nh_map(path, bnc, false);
}
@ -381,6 +385,7 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
struct bgp_connected_ref *bc;
struct listnode *node, *nnode;
struct peer *peer;
struct peer_connection *connection;
addr = ifc->address;
@ -405,14 +410,14 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
}
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->conf_if
&& (strcmp(peer->conf_if, ifc->ifp->name) == 0)
&& !peer_established(peer)
&& !CHECK_FLAG(peer->flags,
PEER_FLAG_IFPEER_V6ONLY)) {
if (peer->conf_if &&
(strcmp(peer->conf_if, ifc->ifp->name) == 0) &&
!peer_established(peer->connection) &&
!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) {
connection = peer->connection;
if (peer_active(peer))
BGP_EVENT_ADD(peer, BGP_Stop);
BGP_EVENT_ADD(peer, BGP_Start);
BGP_EVENT_ADD(connection, BGP_Stop);
BGP_EVENT_ADD(connection, BGP_Start);
}
}
} else if (addr->family == AF_INET6) {
@ -479,7 +484,9 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
XFREE(MTYPE_BGP_CONN, bc);
bgp_dest_set_bgp_connected_ref_info(dest, NULL);
}
bgp_dest_unlock_node(dest);
dest = bgp_dest_unlock_node(dest);
assert(dest);
bgp_dest_unlock_node(dest);
}
@ -590,7 +597,7 @@ bool bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer)
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = peer->su.sin.sin_addr;
p.u.prefix4 = peer->connection->su.sin.sin_addr;
dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p);
if (!dest2) {
@ -623,7 +630,7 @@ bool bgp_multiaccess_check_v6(struct in6_addr nexthop, struct peer *peer)
p.family = AF_INET6;
p.prefixlen = IPV6_MAX_BITLEN;
p.u.prefix6 = peer->su.sin6.sin6_addr;
p.u.prefix6 = peer->connection->su.sin6.sin6_addr;
dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP6], &p);
if (!dest2) {
@ -665,7 +672,7 @@ bool bgp_subgrp_multiaccess_check_v6(struct in6_addr nexthop,
if (paf->peer == exclude)
continue;
p.u.prefix6 = paf->peer->su.sin6.sin6_addr;
p.u.prefix6 = paf->peer->connection->su.sin6.sin6_addr;
dest2 = bgp_node_match(bgp->connected_table[AFI_IP6], &p);
if (dest1 == dest2) {
bgp_dest_unlock_node(dest1);
@ -707,7 +714,7 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
if (paf->peer == exclude)
continue;
p.u.prefix4 = paf->peer->su.sin.sin_addr;
p.u.prefix4 = paf->peer->connection->su.sin.sin_addr;
dest2 = bgp_node_match(bgp->connected_table[AFI_IP], &p);
if (dest1 == dest2) {
@ -854,8 +861,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
json_object_string_add(
json_gate, "interfaceName",
ifindex2ifname(
bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bnc->ifindex_ipv6_ll
? bnc->ifindex_ipv6_ll
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4:
@ -866,8 +874,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
json_object_string_add(
json_gate, "interfaceName",
ifindex2ifname(
bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bnc->ifindex_ipv6_ll
? bnc->ifindex_ipv6_ll
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
@ -876,8 +885,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
json_object_string_add(
json_gate, "interfaceName",
ifindex2ifname(
bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bnc->ifindex_ipv6_ll
? bnc->ifindex_ipv6_ll
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
@ -908,29 +918,40 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
}
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV6:
vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
vty_out(vty, " gate %pI6, if %s\n",
&nexthop->gate.ipv6,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
vty_out(vty, " gate %pI6", &nexthop->gate.ipv6);
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX &&
bnc->ifindex_ipv6_ll)
vty_out(vty, ", if %s\n",
ifindex2ifname(bnc->ifindex_ipv6_ll,
bgp->vrf_id));
else if (nexthop->ifindex)
vty_out(vty, ", if %s\n",
ifindex2ifname(nexthop->ifindex,
bgp->vrf_id));
else
vty_out(vty, "\n");
break;
case NEXTHOP_TYPE_IPV4:
vty_out(vty, " gate %pI4\n", &nexthop->gate.ipv4);
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out(vty, " gate %pI4", &nexthop->gate.ipv4);
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX &&
bnc->ifindex_ipv6_ll)
vty_out(vty, ", if %s\n",
ifindex2ifname(bnc->ifindex_ipv6_ll,
bgp->vrf_id));
else if (nexthop->ifindex)
vty_out(vty, ", if %s\n",
ifindex2ifname(nexthop->ifindex,
bgp->vrf_id));
else
vty_out(vty, "\n");
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " if %s\n",
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out(vty, " gate %pI4, if %s\n",
&nexthop->gate.ipv4,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
ifindex2ifname(bnc->ifindex_ipv6_ll
? bnc->ifindex_ipv6_ll
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
@ -951,6 +972,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
{
char buf[PREFIX2STR_BUFFER];
time_t tbuf;
char timebuf[32];
struct peer *peer;
json_object *json_last_update = NULL;
json_object *json_nexthop = NULL;
@ -981,6 +1003,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
if (bnc->is_evpn_gwip_nexthop)
json_object_boolean_true_add(json_nexthop,
"isEvpnGatewayIp");
json_object_string_addf(json, "resolvedPrefix", "%pFX",
&bnc->resolved_prefix);
} else {
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
buf, bnc->metric, bnc->path_count);
@ -988,6 +1012,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
vty_out(vty, ", peer %s", peer->host);
if (bnc->is_evpn_gwip_nexthop)
vty_out(vty, " EVPN Gateway IP");
vty_out(vty, "\n Resolved prefix %pFX",
&bnc->resolved_prefix);
vty_out(vty, "\n");
}
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
@ -1049,14 +1075,14 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
json_last_update = json_object_new_object();
json_object_int_add(json_last_update, "epoch", tbuf);
json_object_string_add(json_last_update, "string",
ctime(&tbuf));
ctime_r(&tbuf, timebuf));
json_object_object_add(json_nexthop, "lastUpdate",
json_last_update);
} else {
json_object_int_add(json_nexthop, "lastUpdate", tbuf);
}
} else {
vty_out(vty, " Last update: %s", ctime(&tbuf));
vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf));
}
/* show paths dependent on nexthop, if needed. */

View file

@ -26,8 +26,10 @@ PREDECL_RBTREE_UNIQ(bgp_nexthop_cache);
/* BGP nexthop cache value structure. */
struct bgp_nexthop_cache {
afi_t afi;
/* The ifindex of the outgoing interface *if* it's a v6 LL */
ifindex_t ifindex;
ifindex_t ifindex_ipv6_ll;
/* RB-tree entry. */
struct bgp_nexthop_cache_item entry;
@ -37,6 +39,18 @@ struct bgp_nexthop_cache {
/* Nexthop number and nexthop linked list.*/
uint8_t nexthop_num;
/* This flag is set to TRUE for a bnc that is gateway IP overlay index
* nexthop.
*/
bool is_evpn_gwip_nexthop;
uint16_t change_flags;
#define BGP_NEXTHOP_CHANGED (1 << 0)
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
struct nexthop *nexthop;
time_t last_update;
uint16_t flags;
@ -52,6 +66,7 @@ struct bgp_nexthop_cache {
#define BGP_STATIC_ROUTE (1 << 4)
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
#define BGP_NEXTHOP_LABELED_VALID (1 << 6)
#define BGP_NEXTHOP_ULTIMATE (1 << 7)
/*
* This flag is added for EVPN gateway IP nexthops.
@ -70,27 +85,17 @@ struct bgp_nexthop_cache {
*/
#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7)
uint16_t change_flags;
#define BGP_NEXTHOP_CHANGED (1 << 0)
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
uint32_t srte_color;
/* Back pointer to the cache tree this entry belongs to. */
struct bgp_nexthop_cache_head *tree;
uint32_t srte_color;
struct prefix prefix;
struct prefix resolved_prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
/* This flag is set to TRUE for a bnc that is gateway IP overlay index
* nexthop.
*/
bool is_evpn_gwip_nexthop;
};
extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
@ -104,11 +109,6 @@ struct tip_addr {
int refcnt;
};
struct bgp_addrv6 {
struct in6_addr addrv6;
struct list *ifp_name_list;
};
/* Forward declaration(s). */
struct peer;
struct update_subgroup;

99
bgpd/bgp_nhg.c Normal file
View file

@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* BGP Nexthop Group Support
* Copyright (C) 2023 NVIDIA Corporation
* Copyright (C) 2023 6WIND
*/
#include <zebra.h>
#include <bgpd/bgpd.h>
#include <bgpd/bgp_debug.h>
#include <bgpd/bgp_nhg.h>
/****************************************************************************
* L3 NHGs are used for fast failover of nexthops in the dplane. These are
* the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is
* left to the application using it.
* PS: Currently EVPN host routes is the only app using L3 NHG for fast
* failover of remote ES links.
***************************************************************************/
static bitfield_t bgp_nh_id_bitmap;
static uint32_t bgp_nhg_start;
/* XXX - currently we do nothing on the callbacks */
static void bgp_nhg_add_cb(const char *name)
{
}
static void bgp_nhg_modify_cb(const struct nexthop_group_cmd *nhgc)
{
}
static void bgp_nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
}
static void bgp_nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
}
static void bgp_nhg_del_cb(const char *name)
{
}
static void bgp_nhg_zebra_init(void)
{
static bool bgp_nhg_zebra_inited;
if (bgp_nhg_zebra_inited)
return;
bgp_nhg_zebra_inited = true;
bgp_nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP);
nexthop_group_init(bgp_nhg_add_cb, bgp_nhg_modify_cb,
bgp_nhg_add_nexthop_cb, bgp_nhg_del_nexthop_cb,
bgp_nhg_del_cb);
}
void bgp_nhg_init(void)
{
uint32_t id_max;
id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024);
bf_init(bgp_nh_id_bitmap, id_max);
bf_assign_zero_index(bgp_nh_id_bitmap);
if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("bgp nhg range %u - %u", bgp_nhg_start + 1,
bgp_nhg_start + id_max);
}
void bgp_nhg_finish(void)
{
bf_free(bgp_nh_id_bitmap);
}
uint32_t bgp_nhg_id_alloc(void)
{
uint32_t nhg_id = 0;
bgp_nhg_zebra_init();
bf_assign_index(bgp_nh_id_bitmap, nhg_id);
if (nhg_id)
nhg_id += bgp_nhg_start;
return nhg_id;
}
void bgp_nhg_id_free(uint32_t nhg_id)
{
if (!nhg_id || (nhg_id <= bgp_nhg_start))
return;
nhg_id -= bgp_nhg_start;
bf_release_index(bgp_nh_id_bitmap, nhg_id);
}

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