mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
Merge branch 'master' into babel_nonzero_interval
Signed-off-by: Mingwei Zheng <zmw12306@gmail.com>
This commit is contained in:
commit
6cb374a174
309
.clang-format
309
.clang-format
|
@ -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"
|
||||
...
|
||||
|
|
|
@ -20,3 +20,5 @@ c14777c6bfd0a446c85243d3a9835054a259c276
|
|||
8451921b70044a2c1075e7ba391f095fabee2550
|
||||
bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c
|
||||
96941f80927ce31a41f7d1905717f099187be723
|
||||
# apply `black` python formatting for all tests/topotests
|
||||
1a1c2a9f84d0ad1bdadc0cb47d6175d4ccc32544
|
||||
|
|
97
.github/ISSUE_TEMPLATE/bug_report.md
vendored
97
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -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
78
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal 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
28
.github/workflows/behind-base.yml
vendored
Normal 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
163
.github/workflows/build-test-docker.yml
vendored
Normal 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
|
||||
|
3
.github/workflows/conflicts.yml
vendored
3
.github/workflows/conflicts.yml
vendored
|
@ -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:
|
||||
|
|
8
.github/workflows/freeze.yml
vendored
8
.github/workflows/freeze.yml
vendored
|
@ -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
3
.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
257
babeld/message.c
257
babeld/message.c
|
@ -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,
|
||||
×tamp) > 0) {
|
||||
if (parse_hello_subtlv(message + 8, len - 6, ×tamp) > 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
82
bfdd/bfd.c
82
bfdd/bfd.c
|
@ -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)) {
|
||||
|
|
202
bfdd/bfd.h
202
bfdd/bfd.h
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
157
bfdd/bfdctl.h
157
bfdd/bfdctl.h
|
@ -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
|
53
bfdd/bfdd.c
53
bfdd/bfdd.c
|
@ -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();
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
592
bfdd/config.c
592
bfdd/config.c
|
@ -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);
|
||||
}
|
841
bfdd/control.c
841
bfdd/control.c
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
1081
bgpd/bgp_attr.c
1081
bgpd/bgp_attr.c
File diff suppressed because it is too large
Load diff
145
bgpd/bgp_attr.h
145
bgpd/bgp_attr.h
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
662
bgpd/bgp_bmp.c
662
bgpd/bgp_bmp.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
219
bgpd/bgp_clist.c
219
bgpd/bgp_clist.c
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
523
bgpd/bgp_damp.c
523
bgpd/bgp_damp.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
214
bgpd/bgp_debug.c
214
bgpd/bgp_debug.c
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
1492
bgpd/bgp_evpn.c
1492
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
1448
bgpd/bgp_fsm.c
1448
bgpd/bgp_fsm.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
197
bgpd/bgp_io.c
197
bgpd/bgp_io.c
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
156
bgpd/bgp_label.c
156
bgpd/bgp_label.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
104
bgpd/bgp_main.c
104
bgpd/bgp_main.c
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
468
bgpd/bgp_mpath.c
468
bgpd/bgp_mpath.c
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
1784
bgpd/bgp_mplsvpn.c
1784
bgpd/bgp_mplsvpn.c
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
99
bgpd/bgp_nhg.c
Normal 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
Loading…
Reference in a new issue