├── .env ├── test ├── lib │ ├── __init__.py │ ├── fabfile.py │ ├── noseplugin.py │ ├── bagpipe.py │ └── bird.py ├── pip-requires.txt └── scenario_test │ ├── ci-scripts │ └── build_embedded_go.py │ ├── README.md │ ├── bgp_unnumbered_test.py │ ├── bgp_malformed_msg_handling_test.py │ ├── route_server_as2_test.py │ └── route_server_test2.py ├── .pep8 ├── docs └── sources │ ├── policy.png │ ├── rs-policy.png │ ├── policy-component.png │ ├── sentry.md │ ├── bgp-confederation.md │ ├── bmp.md │ ├── route-server.md │ ├── route-reflector.md │ ├── peer-group.md │ ├── mrt.md │ ├── dynamic-neighbor.md │ ├── unnumbered-bgp.md │ ├── cli-operations.md │ └── lib.md ├── pkg ├── packet │ ├── bgp │ │ ├── testdata │ │ │ └── bad-len │ │ │ │ ├── 000852858287eb2ece5cd12aabef453f87b77adb │ │ │ │ ├── 0b229debaa2fc1e8b997c9894ad3184cce8c7bb4 │ │ │ │ ├── 147a924d9a4a4d9960f8bb49e3ec782ee93f82a7 │ │ │ │ ├── 1d1fb484828b4f23af3ff0ab71b67682d5876fd6 │ │ │ │ ├── 27f19d6959e9cbecfcd09b28c3aec493a4b6f18d │ │ │ │ ├── 3765bb2392d48ca8edaf0b5e39209eb2d1b87c53 │ │ │ │ ├── 3dce7e046d709b142092e15b78e9ad20ee5144fa │ │ │ │ ├── 4d4dc736bc89bf41363774d282b8a7641c3e7a98 │ │ │ │ ├── 66e6aab4f34c9c5783c18f90b2d987e5dad241e0 │ │ │ │ ├── a8ecedce17e2e28a466cf9fb3bfaf2d8554fef42 │ │ │ │ └── b7ed0646a97127bf424da480a53a84a0cb9c9565 │ │ ├── esitype_string.go │ │ ├── fsmstate_string.go │ │ ├── internal │ │ │ └── generate.go │ │ ├── srbehavior.go │ │ ├── vpls_test.go │ │ ├── srbehavior_string.go │ │ └── bgpattrtype_string.go │ └── rtr │ │ └── rtr_test.go ├── zebra │ ├── afi_string.go │ ├── ptmenable_string.go │ ├── ptmstatus_string.go │ ├── lsptype_string.go │ ├── safi_string.go │ ├── zapi_windows.go │ ├── nexthoptype_string.go │ ├── zapi_bsd.go │ ├── zapi_darwin.go │ ├── nexthopflag_string.go │ ├── zapi_linux.go │ ├── routetype_string.go │ └── linktype_string.go ├── config │ ├── oc │ │ ├── default_nonlinux.go │ │ ├── util_test.go │ │ ├── default_linux.go │ │ ├── bgp_configs_test.go │ │ └── serve.go │ ├── config_test.go │ └── server_config_test.go └── server │ └── util.go ├── proto ├── buf.yaml ├── buf.gen.yaml └── api │ ├── common.proto │ ├── capability.proto │ └── extcom.proto ├── internal └── pkg │ ├── table │ ├── util.go │ ├── util_windows.go │ ├── util_darwin.go │ └── vrf.go │ ├── netutils │ ├── sockopt_stub.go │ ├── common.go │ ├── utils_windows.go │ ├── sockopt_darwin.go │ ├── utils.go │ ├── sockopt_bsd.go │ ├── sockopt.go │ ├── sockopt_linux_test.go │ └── sockopt_windows.go │ └── version │ └── version.go ├── tools ├── contrib │ ├── centos │ │ ├── add_gobgpd_account.sh │ │ ├── gobgpd.service │ │ └── README.md │ └── ubuntu │ │ └── gobgpd.conf ├── grpc │ ├── python │ │ ├── list_peer.py │ │ └── add_path.py │ └── cpp │ │ ├── add_path.cc │ │ └── Makefile ├── spell-check │ ├── ignore.txt │ ├── dictionary.txt │ ├── README.md │ └── scspell.sh ├── grep_avoided_functions.sh ├── pyang_plugins │ └── README.md ├── completion │ └── zsh │ │ └── _gobgp └── config │ └── example_toml.go ├── .markdownlint.json ├── .gitignore ├── CODEOWNERS ├── .goreleaser.yml ├── .github └── workflows │ └── release.yml ├── cmd ├── gobgpd │ └── util.go └── gobgp │ ├── main.go │ ├── common_test.go │ ├── loglevel.go │ ├── root.go │ ├── global_test.go │ └── bmp.go ├── go.mod ├── .golangci.yml └── README.md /.env: -------------------------------------------------------------------------------- 1 | PYTHONPATH=./test -------------------------------------------------------------------------------- /test/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.pep8: -------------------------------------------------------------------------------- 1 | [pep8] 2 | # E501: Limit all lines to a maximum of 79 characters. 3 | ignore = E501 4 | -------------------------------------------------------------------------------- /docs/sources/policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/docs/sources/policy.png -------------------------------------------------------------------------------- /docs/sources/rs-policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/docs/sources/rs-policy.png -------------------------------------------------------------------------------- /docs/sources/policy-component.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/docs/sources/policy-component.png -------------------------------------------------------------------------------- /test/pip-requires.txt: -------------------------------------------------------------------------------- 1 | nose 2 | toml 3 | pyyaml 4 | fabric == 2.4.0 5 | netaddr 6 | nsenter 7 | docker-py 8 | colored 9 | invoke == 1.2.0 10 | requests <= 2.25.1 11 | -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/000852858287eb2ece5cd12aabef453f87b77adb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/000852858287eb2ece5cd12aabef453f87b77adb -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/0b229debaa2fc1e8b997c9894ad3184cce8c7bb4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/0b229debaa2fc1e8b997c9894ad3184cce8c7bb4 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/147a924d9a4a4d9960f8bb49e3ec782ee93f82a7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/147a924d9a4a4d9960f8bb49e3ec782ee93f82a7 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/1d1fb484828b4f23af3ff0ab71b67682d5876fd6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/1d1fb484828b4f23af3ff0ab71b67682d5876fd6 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/27f19d6959e9cbecfcd09b28c3aec493a4b6f18d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/27f19d6959e9cbecfcd09b28c3aec493a4b6f18d -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/3765bb2392d48ca8edaf0b5e39209eb2d1b87c53: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/3765bb2392d48ca8edaf0b5e39209eb2d1b87c53 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/3dce7e046d709b142092e15b78e9ad20ee5144fa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/3dce7e046d709b142092e15b78e9ad20ee5144fa -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/4d4dc736bc89bf41363774d282b8a7641c3e7a98: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/4d4dc736bc89bf41363774d282b8a7641c3e7a98 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/66e6aab4f34c9c5783c18f90b2d987e5dad241e0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/66e6aab4f34c9c5783c18f90b2d987e5dad241e0 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/a8ecedce17e2e28a466cf9fb3bfaf2d8554fef42: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/a8ecedce17e2e28a466cf9fb3bfaf2d8554fef42 -------------------------------------------------------------------------------- /pkg/packet/bgp/testdata/bad-len/b7ed0646a97127bf424da480a53a84a0cb9c9565: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osrg/gobgp/HEAD/pkg/packet/bgp/testdata/bad-len/b7ed0646a97127bf424da480a53a84a0cb9c9565 -------------------------------------------------------------------------------- /proto/buf.yaml: -------------------------------------------------------------------------------- 1 | # For details on buf.yaml configuration, visit https://buf.build/docs/configuration/v2/buf-yaml 2 | version: v2 3 | lint: 4 | use: 5 | - STANDARD 6 | except: 7 | - PACKAGE_VERSION_SUFFIX 8 | 9 | breaking: 10 | use: 11 | - FILE 12 | -------------------------------------------------------------------------------- /internal/pkg/table/util.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | 3 | package table 4 | 5 | // #include 6 | import "C" 7 | 8 | func SystemMemoryAvailableMiB() uint64 { 9 | return uint64(C.sysconf(C._SC_AVPHYS_PAGES) * C.sysconf(C._SC_PAGE_SIZE) / (1024 * 1024)) 10 | } 11 | -------------------------------------------------------------------------------- /tools/contrib/centos/add_gobgpd_account.sh: -------------------------------------------------------------------------------- 1 | groupadd --system gobgpd 2 | useradd --system -d /var/lib/gobgpd -s /bin/bash -g gobgpd gobgpd 3 | mkdir -p /var/{lib,run,log}/gobgpd 4 | chown -R gobgpd:gobgpd /var/{lib,run,log}/gobgpd 5 | mkdir -p /etc/gobgpd 6 | chown -R gobgpd:gobgpd /etc/gobgpd 7 | -------------------------------------------------------------------------------- /internal/pkg/table/util_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package table 4 | 5 | // #include 6 | import "C" 7 | 8 | func SystemMemoryAvailableMiB() uint64 { 9 | MEMORYSTATUSEX status; 10 | status.dwLength = sizeof(status); 11 | GlobalMemoryStatusEx(&status); 12 | return uint64(status.ullAvailPhys) / (1024 * 1024) 13 | } 14 | -------------------------------------------------------------------------------- /proto/buf.gen.yaml: -------------------------------------------------------------------------------- 1 | # Learn more: https://buf.build/docs/configuration/v2/buf-gen-yaml 2 | version: v2 3 | 4 | plugins: 5 | - remote: buf.build/protocolbuffers/go:v1.36.6 6 | out: ../ 7 | opt: 8 | - paths=source_relative 9 | 10 | - remote: buf.build/grpc/go:v1.5.1 11 | out: ../ 12 | opt: 13 | - paths=source_relative 14 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "no-hard-tabs": { 3 | "code_blocks": false 4 | }, 5 | "line-length": false, 6 | "commands-show-output": false, 7 | "no-duplicate-header": false, 8 | "no-duplicate-heading": false, 9 | "table-column-style": false, 10 | "no-inline-html": { 11 | "allowed_elements": [ 12 | "br" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tools/contrib/centos/gobgpd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=GoBGP Routing Daemon 3 | Wants=network.target 4 | After=network.target 5 | 6 | [Service] 7 | Type=notify 8 | ExecStartPre=/usr/bin/gobgpd -f /etc/gobgpd/gobgpd.conf -d 9 | ExecStart=/usr/bin/gobgpd -f /etc/gobgpd/gobgpd.conf --sdnotify 10 | ExecReload=/usr/bin/kill -HUP $MAINPID 11 | StandardOutput=journal 12 | StandardError=journal 13 | User=gobgpd 14 | Group=gobgpd 15 | AmbientCapabilities=CAP_NET_BIND_SERVICE 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | *.pyc 6 | cmd/gobgp/gobgp 7 | cmd/gobgpd/gobgpd 8 | 9 | # Folders 10 | _obj 11 | _test 12 | vendor 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | test/scenario_test/nosetest*.xml 27 | 28 | *.exe 29 | *.test 30 | *.prof 31 | 32 | # IDE workspace 33 | .idea 34 | .vscode 35 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in the repo. 5 | # * @fujita 6 | 7 | # Order is important. The last matching pattern has the most precedence. 8 | # So if a pull request only touches javascript files, only these owners 9 | # will be requested to review. 10 | pkg/zebra/* @irino 11 | pkg/server/zclient* @irino 12 | 13 | # You can also use email addresses if you prefer. 14 | # docs/* docs@example.com 15 | -------------------------------------------------------------------------------- /tools/grpc/python/list_peer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | from __future__ import print_function 5 | 6 | import grpc 7 | 8 | import gobgp_pb2 9 | import gobgp_pb2_grpc 10 | 11 | _TIMEOUT_SECONDS = 1000 12 | 13 | 14 | def run(): 15 | channel = grpc.insecure_channel('localhost:50051') 16 | stub = gobgp_pb2_grpc.GoBgpServiceStub(channel) 17 | 18 | peers = stub.ListPeer( 19 | gobgp_pb2.ListPeerRequest(), 20 | timeout=_TIMEOUT_SECONDS, 21 | ) 22 | 23 | for peer in peers: 24 | print(peer) 25 | 26 | 27 | if __name__ == '__main__': 28 | run() 29 | -------------------------------------------------------------------------------- /tools/spell-check/ignore.txt: -------------------------------------------------------------------------------- 1 | # Words should be ignored and too specific for adding to dictionary.txt 2 | # Hexadecimal number 3 | ffff 4 | FFFF 5 | 6 | # Function name 7 | Debugf 8 | epoll 9 | Errorf 10 | Fatalf 11 | getpid 12 | getsockopt 13 | Infof 14 | itoa 15 | setsockopt 16 | Sprintf 17 | strconv 18 | Unmarshal 19 | unmarshal 20 | 21 | # Implementation specific 22 | blackhole 23 | dumpv2 24 | elems 25 | etag 26 | Extcomms 27 | fdinfo 28 | ifindex 29 | ifname 30 | linktype 31 | macadv 32 | nhgid 33 | Rcvd 34 | Receivedv4 35 | Receivedv6 36 | softreset 37 | srte 38 | stmt 39 | SRCPFX 40 | IFINDEX 41 | BLACKHOLE 42 | sids 43 | pseudonode 44 | prefixv4 45 | prefixv6 46 | -------------------------------------------------------------------------------- /tools/spell-check/dictionary.txt: -------------------------------------------------------------------------------- 1 | NATURAL: 2 | afisafi 3 | aggregator 4 | aigp 5 | aspath 6 | apiutil 7 | bgpd 8 | bsid 9 | cidr 10 | distinguisher 11 | dscp 12 | ebgp 13 | enlp 14 | ethernet 15 | etree 16 | evpn 17 | flowspec 18 | gobgp 19 | gobgpd 20 | grpc 21 | gzip 22 | ibgp 23 | ipproto 24 | isis 25 | keepalive 26 | keepalives 27 | llgr 28 | localhost 29 | mpls 30 | multicast 31 | multihop 32 | multipath 33 | mututally 34 | nexthop 35 | nexthops 36 | nlri 37 | ospf 38 | pmsi 39 | prepend 40 | reachability 41 | reservable 42 | rpki 43 | sadb 44 | safi 45 | srgb 46 | srlg 47 | subcode 48 | syscall 49 | syslog 50 | teid 51 | unicast 52 | uptime 53 | vpls 54 | zapi 55 | buflen 56 | -------------------------------------------------------------------------------- /pkg/zebra/afi_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=afi"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[afiIP-1] 12 | _ = x[afiIP6-2] 13 | _ = x[afiEther-3] 14 | _ = x[afiMax-4] 15 | } 16 | 17 | const _afi_name = "afiIPafiIP6afiEtherafiMax" 18 | 19 | var _afi_index = [...]uint8{0, 5, 11, 19, 25} 20 | 21 | func (i afi) String() string { 22 | i -= 1 23 | if i >= afi(len(_afi_index)-1) { 24 | return "afi(" + strconv.FormatInt(int64(i+1), 10) + ")" 25 | } 26 | return _afi_name[_afi_index[i]:_afi_index[i+1]] 27 | } 28 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # 2 | # .goreleaser.yml 3 | # Build customization 4 | env: 5 | - GO111MODULE=on 6 | - CGO_ENABLED=0 7 | 8 | builds: 9 | - id: gobgp 10 | main: ./cmd/gobgp/ 11 | binary: gobgp 12 | flags: 13 | - -a 14 | - -tags=netgo 15 | ldflags: -s 16 | goos: 17 | - linux 18 | goarch: 19 | - amd64 20 | - 386 21 | - arm 22 | - arm64 23 | 24 | - id: gobgpd 25 | main: ./cmd/gobgpd/ 26 | binary: gobgpd 27 | flags: 28 | - -a 29 | - -tags=netgo 30 | ldflags: -s 31 | goos: 32 | - linux 33 | goarch: 34 | - amd64 35 | - 386 36 | - arm 37 | - arm64 38 | 39 | archives: 40 | - id: foo 41 | files: 42 | - LICENSE 43 | - README.md 44 | -------------------------------------------------------------------------------- /tools/grep_avoided_functions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # List of functions which should not be used with remarkable reasons 4 | FUNCS=( 5 | # On a 32-bit platform, int type is not big enough to convert into uint32 type. 6 | # strconv.Atoi() should be replaced by strconv.ParseUint() or 7 | # strconv.ParseInt(). 8 | 'strconv\.Atoi' 9 | ) 10 | 11 | SCRIPT_DIR=`dirname $0` 12 | cd "${SCRIPT_DIR}/.." 13 | 14 | RESULT=0 15 | 16 | PKG_BASE=github.com/osrg/gobgp/v4 17 | 18 | for FUNC in ${FUNCS[@]} 19 | do 20 | for GO_PKG in $(go list $PKG_BASE/... | grep -v '/vendor/') 21 | do 22 | grep ${FUNC} -r ${GO_PKG#$PKG_BASE/} 23 | if [ $? -ne 1 ] 24 | then 25 | RESULT=1 26 | fi 27 | done 28 | done 29 | 30 | exit $RESULT 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.* 7 | 8 | jobs: 9 | goreleaser: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Set up Go 18 | uses: actions/setup-go@v4 19 | with: 20 | go-version: 'stable' 21 | 22 | - name: Run GoReleaser 23 | uses: goreleaser/goreleaser-action@v4 24 | with: 25 | # either 'goreleaser' (default) or 'goreleaser-pro' 26 | distribution: goreleaser 27 | version: latest 28 | args: release --clean 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /pkg/zebra/ptmenable_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ptmEnable"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[ptmEnableOff-0] 12 | _ = x[ptmEnableOn-1] 13 | _ = x[ptmEnableUnspec-2] 14 | } 15 | 16 | const _ptmEnable_name = "ptmEnableOffptmEnableOnptmEnableUnspec" 17 | 18 | var _ptmEnable_index = [...]uint8{0, 12, 23, 38} 19 | 20 | func (i ptmEnable) String() string { 21 | if i >= ptmEnable(len(_ptmEnable_index)-1) { 22 | return "ptmEnable(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _ptmEnable_name[_ptmEnable_index[i]:_ptmEnable_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /pkg/zebra/ptmstatus_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ptmStatus"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[ptmStatusDown-0] 12 | _ = x[ptmStatusUp-1] 13 | _ = x[ptmStatusUnknown-2] 14 | } 15 | 16 | const _ptmStatus_name = "ptmStatusDownptmStatusUpptmStatusUnknown" 17 | 18 | var _ptmStatus_index = [...]uint8{0, 13, 24, 40} 19 | 20 | func (i ptmStatus) String() string { 21 | if i >= ptmStatus(len(_ptmStatus_index)-1) { 22 | return "ptmStatus(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _ptmStatus_name[_ptmStatus_index[i]:_ptmStatus_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /tools/contrib/ubuntu/gobgpd.conf: -------------------------------------------------------------------------------- 1 | description "GoBGP BGP daemon" 2 | author "Pavel Odintsov " 3 | 4 | start on (filesystem and net-device-up IFACE=lo) 5 | stop on runlevel [!2345] 6 | 7 | # TODO: use path without version number 8 | env DAEMON=/usr/sbin/gobgpd 9 | env CONFIGURATION_FILE=/etc/gobgpd.conf 10 | env DAEMON_OPTIONS="--disable-stdlog --syslog yes" 11 | 12 | #expect fork 13 | #respawn 14 | #respawn limit 10 5 15 | #oom never 16 | 17 | # Check configuration before start. You could check result in dmesg output: 18 | # gobgp pre-start process (12265) terminated with status 1 19 | pre-start script 20 | $DAEMON --dry-run -f $CONFIGURATION_FILE 21 | if [ $? -ne 0 ]; then 22 | exit $? 23 | fi 24 | end script 25 | 26 | exec $DAEMON -f $CONFIGURATION_FILE $DAEMON_OPTIONS 27 | -------------------------------------------------------------------------------- /tools/spell-check/README.md: -------------------------------------------------------------------------------- 1 | # What's this 2 | 3 | This script is a spell checker for GoBGP's source codes. 4 | 5 | ## Requirements 6 | 7 | - [scspell3k](https://pypi.python.org/pypi/scspell3k): Spell checker for 8 | source code written in Python. 9 | 10 | ```bash 11 | pip install scspell3k 12 | ``` 13 | 14 | ## How to use 15 | 16 | Just run `scspell.sh`. 17 | 18 | ```bash 19 | bash tools/spell-check/scspell.sh 20 | ``` 21 | 22 | Example of output: 23 | 24 | ```bash 25 | # Format: 26 | # path/to/file.go: 27 | xxx/xxx.go: 'mispeld' not found in dictionary (from token 'Mispeld') 28 | ``` 29 | 30 | ## Adding new words to dictionary 31 | 32 | If you want to add new words to the dictionary for this spell checker, please 33 | insert words into `tools/spell-check/dictionary.txt` or 34 | `tools/spell-check/ignore.txt`. 35 | -------------------------------------------------------------------------------- /pkg/zebra/lsptype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=lspTYPE"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[lspNone-0] 12 | _ = x[lspStatic-1] 13 | _ = x[lspLDP-2] 14 | _ = x[lspBGP-3] 15 | _ = x[lspSR-4] 16 | _ = x[lspSHARP-5] 17 | } 18 | 19 | const _lspTYPE_name = "lspNonelspStaticlspLDPlspBGPlspSRlspSHARP" 20 | 21 | var _lspTYPE_index = [...]uint8{0, 7, 16, 22, 28, 33, 41} 22 | 23 | func (i lspTYPE) String() string { 24 | if i >= lspTYPE(len(_lspTYPE_index)-1) { 25 | return "lspTYPE(" + strconv.FormatInt(int64(i), 10) + ")" 26 | } 27 | return _lspTYPE_name[_lspTYPE_index[i]:_lspTYPE_index[i+1]] 28 | } 29 | -------------------------------------------------------------------------------- /test/lib/fabfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | from fabric import task 3 | from invoke import run as local 4 | from base import CmdBuffer 5 | 6 | 7 | @task 8 | def make_gobgp_ctn(ctx, tag='gobgp', 9 | local_gobgp_path='', 10 | from_image='osrg/quagga'): 11 | if local_gobgp_path == '': 12 | local_gobgp_path = os.getcwd() 13 | 14 | local('CGO_ENABLED=0 go build "-ldflags=-s -w -buildid=" ./cmd/gobgp') 15 | local('CGO_ENABLED=0 go build "-ldflags=-s -w -buildid=" ./cmd/gobgpd') 16 | 17 | c = CmdBuffer() 18 | c << 'FROM {0}'.format(from_image) 19 | c << 'COPY gobgpd /go/bin/gobgpd' 20 | c << 'COPY gobgp /go/bin/gobgp' 21 | 22 | os.chdir(local_gobgp_path) 23 | local('echo \'{0}\' > Dockerfile'.format(str(c))) 24 | local('docker build -t {0} .'.format(tag)) 25 | local('rm Dockerfile') 26 | -------------------------------------------------------------------------------- /pkg/packet/bgp/esitype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ESIType"; DO NOT EDIT. 2 | 3 | package bgp 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[ESI_ARBITRARY-0] 12 | _ = x[ESI_LACP-1] 13 | _ = x[ESI_MSTP-2] 14 | _ = x[ESI_MAC-3] 15 | _ = x[ESI_ROUTERID-4] 16 | _ = x[ESI_AS-5] 17 | } 18 | 19 | const _ESIType_name = "ESI_ARBITRARYESI_LACPESI_MSTPESI_MACESI_ROUTERIDESI_AS" 20 | 21 | var _ESIType_index = [...]uint8{0, 13, 21, 29, 36, 48, 54} 22 | 23 | func (i ESIType) String() string { 24 | if i >= ESIType(len(_ESIType_index)-1) { 25 | return "ESIType(" + strconv.FormatInt(int64(i), 10) + ")" 26 | } 27 | return _ESIType_name[_ESIType_index[i]:_ESIType_index[i+1]] 28 | } 29 | -------------------------------------------------------------------------------- /pkg/config/oc/default_nonlinux.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | //go:build !linux 16 | 17 | package oc 18 | 19 | import ( 20 | "fmt" 21 | ) 22 | 23 | func GetIPv6LinkLocalNeighborAddress(ifname string) (string, error) { 24 | return "", fmt.Errorf("unnumbered peering is not supported") 25 | } 26 | -------------------------------------------------------------------------------- /docs/sources/sentry.md: -------------------------------------------------------------------------------- 1 | # Sentry 2 | 3 | GoBGP supports Sentry for error and exception tracking. 4 | 5 | To enable Sentry, set the `--sentry-dsn` flag to your Sentry DSN. 6 | 7 | ```bash 8 | $ gobgpd --sentry-dsn= 9 | ``` 10 | 11 | In addition, you can set the `--sentry-environment` flag to your Sentry environment. 12 | 13 | ```bash 14 | $ gobgpd --sentry-dsn= --sentry-environment= 15 | ``` 16 | 17 | You can also set the `--sentry-sample-rate` flag to the sample rate of Sentry traces. 18 | 19 | ```bash 20 | $ gobgpd --sentry-dsn= --sentry-sample-rate= 21 | ``` 22 | 23 | Finally, you can set the `--sentry-debug` flag to enable Sentry debug mode. 24 | 25 | ```bash 26 | $ gobgpd --sentry-dsn= --sentry-debug=true 27 | ``` 28 | 29 | When Sentry debug mode is enabled, there is a message logged to Sentry when the program starts. 30 | This is particularly useful to verify that Sentry is working as expected. 31 | -------------------------------------------------------------------------------- /pkg/packet/bgp/fsmstate_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=FSMState"; DO NOT EDIT. 2 | 3 | package bgp 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[BGP_FSM_IDLE-0] 12 | _ = x[BGP_FSM_CONNECT-1] 13 | _ = x[BGP_FSM_ACTIVE-2] 14 | _ = x[BGP_FSM_OPENSENT-3] 15 | _ = x[BGP_FSM_OPENCONFIRM-4] 16 | _ = x[BGP_FSM_ESTABLISHED-5] 17 | } 18 | 19 | const _FSMState_name = "BGP_FSM_IDLEBGP_FSM_CONNECTBGP_FSM_ACTIVEBGP_FSM_OPENSENTBGP_FSM_OPENCONFIRMBGP_FSM_ESTABLISHED" 20 | 21 | var _FSMState_index = [...]uint8{0, 12, 27, 41, 57, 76, 95} 22 | 23 | func (i FSMState) String() string { 24 | if i < 0 || i >= FSMState(len(_FSMState_index)-1) { 25 | return "FSMState(" + strconv.FormatInt(int64(i), 10) + ")" 26 | } 27 | return _FSMState_name[_FSMState_index[i]:_FSMState_index[i+1]] 28 | } 29 | -------------------------------------------------------------------------------- /cmd/gobgpd/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build !windows 17 | 18 | package main 19 | 20 | import ( 21 | "os" 22 | "os/signal" 23 | "runtime" 24 | "runtime/debug" 25 | "syscall" 26 | ) 27 | 28 | func init() { 29 | go func() { 30 | sigCh := make(chan os.Signal, 1) 31 | signal.Notify(sigCh, syscall.SIGUSR1) 32 | for range sigCh { 33 | runtime.GC() 34 | debug.FreeOSMemory() 35 | } 36 | }() 37 | } 38 | -------------------------------------------------------------------------------- /pkg/zebra/safi_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Safi"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[safiUnspec-0] 12 | _ = x[SafiUnicast-1] 13 | _ = x[safiMulticast-2] 14 | _ = x[safiMplsVpn-3] 15 | _ = x[safiEncap-4] 16 | _ = x[safiEvpn-5] 17 | _ = x[safiLabeledUnicast-6] 18 | _ = x[safiFlowspec-7] 19 | _ = x[safiMax-8] 20 | _ = x[zapi4SafiMplsVpn-3] 21 | _ = x[zapi3SafiMplsVpn-4] 22 | _ = x[zapi4SafiEncap-5] 23 | _ = x[zapi4SafiEvpn-6] 24 | _ = x[zapi3SafiEncap-7] 25 | } 26 | 27 | const _Safi_name = "safiUnspecSafiUnicastsafiMulticastsafiMplsVpnsafiEncapsafiEvpnsafiLabeledUnicastsafiFlowspecsafiMax" 28 | 29 | var _Safi_index = [...]uint8{0, 10, 21, 34, 45, 54, 62, 80, 92, 99} 30 | 31 | func (i Safi) String() string { 32 | if i >= Safi(len(_Safi_index)-1) { 33 | return "Safi(" + strconv.FormatInt(int64(i), 10) + ")" 34 | } 35 | return _Safi_name[_Safi_index[i]:_Safi_index[i+1]] 36 | } 37 | -------------------------------------------------------------------------------- /cmd/gobgp/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | "os" 21 | 22 | "github.com/osrg/gobgp/v4/internal/pkg/version" 23 | "google.golang.org/grpc" 24 | ) 25 | 26 | func main() { 27 | if len(os.Args) > 1 && os.Args[1] == "--version" { 28 | fmt.Println("gobgp version", version.Version()) 29 | os.Exit(0) 30 | } 31 | grpc.EnableTracing = false 32 | if err := newRootCmd().Execute(); err != nil { 33 | fmt.Fprintln(os.Stderr, err) 34 | os.Exit(1) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tools/pyang_plugins/README.md: -------------------------------------------------------------------------------- 1 | # Generating config code from yang 2 | 3 | ## What's this ? 4 | 5 | This is a pyang plugin to generate config/bgp_configs.go from 6 | [openconfig yang files](https://github.com/openconfig/public). 7 | 8 | ## Prerequisites 9 | 10 | Python 3. 11 | 12 | ## How to use 13 | 14 | Clone the required resources by using Git: 15 | 16 | ```shell 17 | $ export CWD=`pwd` 18 | $ git clone https://github.com/osrg/gobgp 19 | $ git clone https://github.com/osrg/public 20 | $ git clone https://github.com/osrg/yang 21 | $ git clone https://github.com/osrg/pyang 22 | ``` 23 | 24 | Generate config/bgp_configs.go from yang files: 25 | 26 | ```shell 27 | $ cd pyang 28 | $ source ./env.sh 29 | $ PYTHONPATH=. ./bin/pyang \ 30 | --plugindir $CWD/gobgp/tools/pyang_plugins \ 31 | -p $CWD/yang/standard/ietf/RFC \ 32 | -p $CWD/public/release/models \ 33 | -p $CWD/public/release/models/bgp \ 34 | -p $CWD/public/release/models/policy \ 35 | -f golang \ 36 | $CWD/public/release/models/policy/openconfig-routing-policy.yang \ 37 | $CWD/public/release/models/bgp/openconfig-bgp.yang \ 38 | $CWD/gobgp/tools/pyang_plugins/gobgp.yang \ 39 | | gofmt > $CWD/gobgp/pkg/config/oc/bgp_configs.go 40 | ``` 41 | -------------------------------------------------------------------------------- /internal/pkg/table/util_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | 3 | package table 4 | 5 | /* 6 | #cgo CFLAGS: -x objective-c 7 | #cgo LDFLAGS: -framework CoreServices -framework IOKit 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int get_page_size() { 15 | int mib[2] = {CTL_HW, HW_PAGESIZE}; 16 | int pagesize = 0; 17 | size_t length = sizeof(pagesize); 18 | 19 | if (sysctl(mib, 2, &pagesize, &length, NULL, 0) < 0) { 20 | return -1; 21 | } 22 | return pagesize; 23 | } 24 | 25 | int get_vm_stats(vm_statistics_data_t *vmstat_out) { 26 | mach_msg_type_number_t count = HOST_VM_INFO_COUNT; 27 | return host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)vmstat_out, &count); 28 | } 29 | */ 30 | import "C" 31 | 32 | func SystemMemoryAvailableMiB() uint64 { 33 | // Get page size 34 | pageSize := C.get_page_size() 35 | if pageSize < 0 { 36 | return 0 37 | } 38 | 39 | // Get VM statistics 40 | var vmstat C.vm_statistics_data_t 41 | if C.get_vm_stats(&vmstat) != C.KERN_SUCCESS { 42 | return 0 43 | } 44 | 45 | // Compute total and usage breakdown 46 | return uint64(vmstat.free_count) * uint64(pageSize) >> 20 // Convert to MiB 47 | } 48 | -------------------------------------------------------------------------------- /pkg/zebra/zapi_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package zebra 17 | 18 | import ( 19 | "strings" 20 | "syscall" 21 | ) 22 | 23 | func intfflag2string(flag uint64) string { 24 | ss := make([]string, 0, 10) 25 | if flag&syscall.IFF_UP > 0 { 26 | ss = append(ss, "UP") 27 | } 28 | if flag&syscall.IFF_BROADCAST > 0 { 29 | ss = append(ss, "BROADCAST") 30 | } 31 | if flag&syscall.IFF_LOOPBACK > 0 { 32 | ss = append(ss, "LOOPBACK") 33 | } 34 | if flag&syscall.IFF_MULTICAST > 0 { 35 | ss = append(ss, "MULTICAST") 36 | } 37 | return strings.Join(ss, " | ") 38 | } 39 | -------------------------------------------------------------------------------- /test/lib/noseplugin.py: -------------------------------------------------------------------------------- 1 | import os 2 | from nose.plugins import Plugin 3 | 4 | parser_option = None 5 | 6 | 7 | class OptionParser(Plugin): 8 | 9 | def options(self, parser, env=os.environ): 10 | super(OptionParser, self).options(parser, env=env) 11 | parser.add_option('--test-prefix', action="store", dest="test_prefix", default="") 12 | parser.add_option('--gobgp-image', action="store", dest="gobgp_image", default="osrg/gobgp") 13 | parser.add_option('--exabgp-path', action="store", dest="exabgp_path", default="") 14 | parser.add_option('--go-path', action="store", dest="go_path", default="") 15 | parser.add_option('--gobgp-log-level', action="store", 16 | dest="gobgp_log_level", default="info") 17 | parser.add_option('--test-index', action="store", type="int", dest="test_index", default=0) 18 | parser.add_option('--config-format', action="store", dest="config_format", default="yaml") 19 | 20 | def configure(self, options, conf): 21 | super(OptionParser, self).configure(options, conf) 22 | global parser_option 23 | parser_option = options 24 | 25 | if not self.enabled: 26 | return 27 | 28 | def finalize(self, result): 29 | pass 30 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt_stub.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build !linux && !dragonfly && !freebsd && !netbsd && !openbsd && !darwin && !windows 17 | 18 | package netutils 19 | 20 | import ( 21 | "fmt" 22 | "net" 23 | ) 24 | 25 | func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error { 26 | return fmt.Errorf("setting md5 is not supported") 27 | } 28 | 29 | func SetTcpTTLSockopt(conn net.Conn, ttl int) error { 30 | return fmt.Errorf("setting ttl is not supported") 31 | } 32 | 33 | func SetTcpMinTTLSockopt(conn net.Conn, ttl int) error { 34 | return fmt.Errorf("setting min ttl is not supported") 35 | } 36 | 37 | func SetTcpMSSSockopt(conn net.Conn, mss uint16) error { 38 | return fmt.Errorf("setting min ttl is not supported") 39 | } 40 | -------------------------------------------------------------------------------- /docs/sources/bgp-confederation.md: -------------------------------------------------------------------------------- 1 | # BGP Confederation 2 | 3 | This page explains how to configure BGP confederation feature when BGP peers 4 | are part of a larger mesh representing a single autonomous system (AS). 5 | 6 | ## Prerequisites 7 | 8 | Assume you finished [Getting Started](getting-started.md). 9 | 10 | ## Contents 11 | 12 | - [Configuration](#configuration) 13 | 14 | ## Configuration 15 | 16 | If AS30 is a confederation composed of AS65001 and AS65002, the confederation members must configure 17 | the following attributes to ensure GoBGP communicates in the correct manner with other member ASNs. 18 | Each confederated autonomous systems must configure the `[global.confederation.config]` with 19 | `enabled = true` and `identifier = 30`. The identifier parameter is used to designate what the 20 | confederation should present as it's ASN non-confederation members. Each member of the confederation 21 | must also configure `member-as-list` with a list of other ASNs which compose the confederation. For 22 | example, AS65001 would configure this attribute as `member-as-list = [ 65002 ]`. 23 | 24 | ```toml 25 | [global] 26 | [global.config] 27 | as = 65001 28 | router-id = "10.0.0.1" 29 | [global.confederation.config] 30 | enabled = true 31 | identifier = 30 32 | member-as-list = [ 65002 ] 33 | 34 | [[neighbors]] 35 | [neighbors.config] 36 | peer-as = 65002 37 | neighbor-address = "10.0.0.2" 38 | ``` 39 | -------------------------------------------------------------------------------- /internal/pkg/netutils/common.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package netutils 17 | 18 | import ( 19 | "net" 20 | "strings" 21 | "syscall" 22 | ) 23 | 24 | func extractFamilyFromAddress(address string) int { 25 | if ip := net.ParseIP(address); ip != nil && ip.To4() == nil { 26 | return syscall.AF_INET6 27 | } 28 | // default 29 | return syscall.AF_INET 30 | } 31 | 32 | func extractFamilyFromConn(conn net.Conn) int { 33 | family := syscall.AF_INET 34 | if strings.Contains(conn.RemoteAddr().String(), "[") { 35 | family = syscall.AF_INET6 36 | } 37 | return family 38 | } 39 | 40 | func extractProtoFromAddress(address string) string { 41 | if ip := net.ParseIP(address); ip != nil && ip.To4() == nil { 42 | return "tcp6" 43 | } 44 | // default to tcp4 45 | return "tcp4" 46 | } 47 | -------------------------------------------------------------------------------- /internal/pkg/netutils/utils_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build windows 17 | 18 | package netutils 19 | 20 | import ( 21 | "syscall" 22 | ) 23 | 24 | func setSockOptInt(sc syscall.RawConn, level, name, value int) error { 25 | var opterr error 26 | fn := func(s uintptr) { 27 | opterr = syscall.SetsockoptInt(syscall.Handle(s), level, name, value) 28 | } 29 | err := sc.Control(fn) 30 | if opterr == nil { 31 | return err 32 | } 33 | return opterr 34 | } 35 | 36 | func setSockOptIpTtl(sc syscall.RawConn, family int, value int) error { 37 | level := syscall.IPPROTO_IP 38 | name := syscall.IP_TTL 39 | if family == syscall.AF_INET6 { 40 | level = syscall.IPPROTO_IPV6 41 | name = syscall.IPV6_UNICAST_HOPS 42 | } 43 | return setSockOptInt(sc, level, name, value) 44 | } 45 | -------------------------------------------------------------------------------- /cmd/gobgp/common_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "strings" 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func Test_ExtractReserved(t *testing.T) { 26 | assert := assert.New(t) 27 | args := strings.Split("10 rt 100:100 med 10 nexthop 10.0.0.1 aigp metric 10 local-pref 100", " ") 28 | keys := map[string]int{ 29 | "rt": paramList, 30 | "med": paramSingle, 31 | "nexthop": paramSingle, 32 | "aigp": paramList, 33 | "local-pref": paramSingle, 34 | } 35 | m, _ := extractReserved(args, keys) 36 | assert.True(len(m["rt"]) == 1) 37 | assert.True(len(m["med"]) == 1) 38 | assert.True(len(m["nexthop"]) == 1) 39 | assert.True(len(m["aigp"]) == 2) 40 | assert.True(len(m["local-pref"]) == 1) 41 | } 42 | -------------------------------------------------------------------------------- /pkg/zebra/nexthoptype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=nexthopType"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[nexthopTypeIFIndex-1] 12 | _ = x[nexthopTypeIPv4-2] 13 | _ = x[nexthopTypeIPv4IFIndex-3] 14 | _ = x[nexthopTypeIPv6-4] 15 | _ = x[nexthopTypeIPv6IFIndex-5] 16 | _ = x[nexthopTypeBlackhole-6] 17 | _ = x[nexthopTypeIFName-2] 18 | _ = x[backwardNexthopTypeIPv4-3] 19 | _ = x[backwardNexthopTypeIPv4IFIndex-4] 20 | _ = x[nexthopTypeIPv4IFName-5] 21 | _ = x[backwardNexthopTypeIPv6-6] 22 | _ = x[backwardNexthopTypeIPv6IFIndex-7] 23 | _ = x[nexthopTypeIPv6IFName-8] 24 | _ = x[backwardNexthopTypeBlackhole-9] 25 | } 26 | 27 | const _nexthopType_name = "nexthopTypeIFIndexnexthopTypeIPv4nexthopTypeIPv4IFIndexnexthopTypeIPv6nexthopTypeIPv6IFIndexnexthopTypeBlackholebackwardNexthopTypeIPv6IFIndexnexthopTypeIPv6IFNamebackwardNexthopTypeBlackhole" 28 | 29 | var _nexthopType_index = [...]uint8{0, 18, 33, 55, 70, 92, 112, 142, 163, 191} 30 | 31 | func (i nexthopType) String() string { 32 | i -= 1 33 | if i >= nexthopType(len(_nexthopType_index)-1) { 34 | return "nexthopType(" + strconv.FormatInt(int64(i+1), 10) + ")" 35 | } 36 | return _nexthopType_name[_nexthopType_index[i]:_nexthopType_index[i+1]] 37 | } 38 | -------------------------------------------------------------------------------- /internal/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package version 17 | 18 | import "fmt" 19 | 20 | const ( 21 | MAJOR uint = 4 22 | MINOR uint = 1 23 | PATCH uint = 0 24 | ) 25 | 26 | var ( 27 | COMMIT string = "" 28 | IDENTIFIER string = "" 29 | METADATA string = "" 30 | ) 31 | 32 | func Version() string { 33 | suffix := "" 34 | if len(IDENTIFIER) > 0 { 35 | suffix = fmt.Sprintf("-%s", IDENTIFIER) 36 | } 37 | 38 | if len(COMMIT) > 0 || len(METADATA) > 0 { 39 | suffix = suffix + "+" 40 | } 41 | 42 | if len(COMMIT) > 0 { 43 | suffix = fmt.Sprintf("%s"+"commit.%s", suffix, COMMIT) 44 | } 45 | 46 | if len(METADATA) > 0 { 47 | if len(COMMIT) > 0 { 48 | suffix = suffix + "." 49 | } 50 | suffix = suffix + METADATA 51 | } 52 | 53 | return fmt.Sprintf("%d.%d.%d%s", MAJOR, MINOR, PATCH, suffix) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/packet/bgp/internal/generate.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "os" 9 | "regexp" 10 | ) 11 | 12 | const ( 13 | srBehaviourSourceFile = "../../../api/attribute.pb.go" 14 | srBehaviourTargetFile = "srbehavior.go" 15 | ) 16 | 17 | func main() { 18 | if len(os.Args) != 2 { 19 | panic("expected single argument: type to generate") 20 | } 21 | 22 | switch os.Args[1] { 23 | case "SRBehavior": 24 | generateSRBehaviour() 25 | default: 26 | panic("unexpected type: " + os.Args[1]) 27 | } 28 | } 29 | 30 | func generateSRBehaviour() { 31 | content, err := os.ReadFile(srBehaviourSourceFile) 32 | if err != nil { 33 | doPanic("failed to read file %s: %w", srBehaviourSourceFile, err) 34 | } 35 | 36 | re := regexp.MustCompile(`(?ms)type SRv6Behavior int32\s+(const \(.*?\)\n)`) 37 | 38 | match := re.FindSubmatch(content) 39 | if match == nil { 40 | doPanic("couldn't find SRv6Behavior constants") 41 | } 42 | 43 | constants := bytes.ReplaceAll( 44 | bytes.ReplaceAll(match[1], []byte("SRv6Behavior_"), nil), 45 | []byte("SRv6"), 46 | []byte("SR"), 47 | ) 48 | 49 | buf := bytes.NewBuffer([]byte("// Generated code; DO NOT EDIT.\n\npackage bgp\n\n")) 50 | buf.Write(constants) 51 | 52 | if err := os.WriteFile(srBehaviourTargetFile, buf.Bytes(), 0o664); err != nil { 53 | doPanic("failed to write file %s: %w") 54 | } 55 | } 56 | 57 | func doPanic(message string, args ...any) { 58 | panic(fmt.Errorf(message+"\n", args...)) 59 | } 60 | -------------------------------------------------------------------------------- /proto/api/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package api; 4 | 5 | option go_package = "github.com/osrg/gobgp/v4/api;api"; 6 | 7 | // Common types for pretty much everywhere 8 | 9 | message Family { 10 | enum Afi { 11 | AFI_UNSPECIFIED = 0; 12 | AFI_IP = 1; 13 | AFI_IP6 = 2; 14 | AFI_L2VPN = 25; 15 | AFI_LS = 16388; 16 | AFI_OPAQUE = 16397; 17 | } 18 | 19 | enum Safi { 20 | SAFI_UNSPECIFIED = 0; 21 | SAFI_UNICAST = 1; 22 | SAFI_MULTICAST = 2; 23 | SAFI_MPLS_LABEL = 4; 24 | SAFI_ENCAPSULATION = 7; 25 | SAFI_VPLS = 65; 26 | SAFI_EVPN = 70; 27 | SAFI_LS = 71; 28 | SAFI_SR_POLICY = 73; 29 | SAFI_MUP = 85; 30 | SAFI_MPLS_VPN = 128; 31 | SAFI_MPLS_VPN_MULTICAST = 129; 32 | SAFI_ROUTE_TARGET_CONSTRAINTS = 132; 33 | SAFI_FLOW_SPEC_UNICAST = 133; 34 | SAFI_FLOW_SPEC_VPN = 134; 35 | SAFI_KEY_VALUE = 241; 36 | } 37 | 38 | Afi afi = 1; 39 | Safi safi = 2; 40 | } 41 | 42 | message RouteDistinguisherTwoOctetASN { 43 | uint32 admin = 1; 44 | uint32 assigned = 2; 45 | } 46 | 47 | message RouteDistinguisherIPAddress { 48 | string admin = 1; 49 | uint32 assigned = 2; 50 | } 51 | 52 | message RouteDistinguisherFourOctetASN { 53 | uint32 admin = 1; 54 | uint32 assigned = 2; 55 | } 56 | 57 | message RouteDistinguisher { 58 | oneof rd { 59 | RouteDistinguisherTwoOctetASN two_octet_asn = 1; 60 | RouteDistinguisherIPAddress ip_address = 2; 61 | RouteDistinguisherFourOctetASN four_octet_asn = 3; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /internal/pkg/table/vrf.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package table 17 | 18 | import ( 19 | "github.com/osrg/gobgp/v4/pkg/packet/bgp" 20 | ) 21 | 22 | type Vrf struct { 23 | Name string 24 | Id uint32 25 | Rd bgp.RouteDistinguisherInterface 26 | ImportRt routeTargetMap 27 | ExportRt []bgp.ExtendedCommunityInterface 28 | MplsLabel uint32 29 | } 30 | 31 | func (v *Vrf) Clone() *Vrf { 32 | f := func(rt []bgp.ExtendedCommunityInterface) []bgp.ExtendedCommunityInterface { 33 | l := make([]bgp.ExtendedCommunityInterface, 0, len(rt)) 34 | return append(l, rt...) 35 | } 36 | return &Vrf{ 37 | Name: v.Name, 38 | Id: v.Id, 39 | Rd: v.Rd, 40 | ImportRt: v.ImportRt.Clone(), 41 | ExportRt: f(v.ExportRt), 42 | MplsLabel: v.MplsLabel, 43 | } 44 | } 45 | 46 | func isLastTargetUser(vrfs map[string]*Vrf, target uint64) bool { 47 | for _, vrf := range vrfs { 48 | if _, exist := vrf.ImportRt[target]; exist { 49 | return false 50 | } 51 | } 52 | return true 53 | } 54 | -------------------------------------------------------------------------------- /pkg/config/config_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | 9 | "github.com/osrg/gobgp/v4/pkg/server" 10 | ) 11 | 12 | // ExampleUpdateConfig shows how InitialConfig can be used without UpdateConfig 13 | func ExampleInitialConfig() { 14 | bgpServer := server.NewBgpServer() 15 | go bgpServer.Serve() 16 | 17 | initialConfig, err := ReadConfigFile("gobgp.conf", "toml") 18 | if err != nil { 19 | // Handle error 20 | return 21 | } 22 | 23 | isGracefulRestart := true 24 | _, err = InitialConfig(context.Background(), bgpServer, initialConfig, isGracefulRestart) 25 | if err != nil { 26 | // Handle error 27 | return 28 | } 29 | } 30 | 31 | // ExampleUpdateConfig shows how UpdateConfig is used in conjunction with 32 | // InitialConfig. 33 | func ExampleUpdateConfig() { 34 | bgpServer := server.NewBgpServer() 35 | go bgpServer.Serve() 36 | 37 | initialConfig, err := ReadConfigFile("gobgp.conf", "toml") 38 | if err != nil { 39 | // Handle error 40 | return 41 | } 42 | 43 | isGracefulRestart := true 44 | currentConfig, err := InitialConfig(context.Background(), bgpServer, initialConfig, isGracefulRestart) 45 | if err != nil { 46 | // Handle error 47 | return 48 | } 49 | 50 | sigCh := make(chan os.Signal, 1) 51 | signal.Notify(sigCh, syscall.SIGHUP) 52 | 53 | for range sigCh { 54 | newConfig, err := ReadConfigFile("gobgp.conf", "toml") 55 | if err != nil { 56 | // Handle error 57 | continue 58 | } 59 | 60 | currentConfig, err = UpdateConfig(context.Background(), bgpServer, currentConfig, newConfig) 61 | if err != nil { 62 | // Handle error 63 | continue 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2017 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build darwin 17 | 18 | package netutils 19 | 20 | import ( 21 | "fmt" 22 | "net" 23 | "strings" 24 | "syscall" 25 | ) 26 | 27 | func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error { 28 | return fmt.Errorf("setting md5 is not supported") 29 | } 30 | 31 | func SetTcpTTLSockopt(conn net.Conn, ttl int) error { 32 | family := syscall.AF_INET 33 | if strings.Contains(conn.RemoteAddr().String(), "[") { 34 | family = syscall.AF_INET6 35 | } 36 | sc, err := conn.(syscall.Conn).SyscallConn() 37 | if err != nil { 38 | return err 39 | } 40 | return setSockOptIpTtl(sc, family, ttl) 41 | } 42 | 43 | func SetTcpMinTTLSockopt(conn net.Conn, ttl int) error { 44 | return fmt.Errorf("setting min ttl is not supported") 45 | } 46 | 47 | func SetTcpMSSSockopt(conn net.Conn, mss uint16) error { 48 | family := extractFamilyFromConn(conn) 49 | sc, err := conn.(syscall.Conn).SyscallConn() 50 | if err != nil { 51 | return err 52 | } 53 | return setSockOptTcpMss(sc, family, mss) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/zebra/zapi_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build freebsd || netbsd || openbsd 17 | 18 | package zebra 19 | 20 | import ( 21 | "strings" 22 | "syscall" 23 | ) 24 | 25 | func intfflag2string(flag uint64) string { 26 | ss := make([]string, 0, 10) 27 | if flag&syscall.IFF_UP > 0 { 28 | ss = append(ss, "UP") 29 | } 30 | if flag&syscall.IFF_BROADCAST > 0 { 31 | ss = append(ss, "BROADCAST") 32 | } 33 | if flag&syscall.IFF_DEBUG > 0 { 34 | ss = append(ss, "DEBUG") 35 | } 36 | if flag&syscall.IFF_LOOPBACK > 0 { 37 | ss = append(ss, "LOOPBACK") 38 | } 39 | if flag&syscall.IFF_POINTOPOINT > 0 { 40 | ss = append(ss, "POINTOPOINT") 41 | } 42 | if flag&syscall.IFF_RUNNING > 0 { 43 | ss = append(ss, "RUNNING") 44 | } 45 | if flag&syscall.IFF_NOARP > 0 { 46 | ss = append(ss, "NOARP") 47 | } 48 | if flag&syscall.IFF_PROMISC > 0 { 49 | ss = append(ss, "PROMISC") 50 | } 51 | if flag&syscall.IFF_ALLMULTI > 0 { 52 | ss = append(ss, "ALLMULTI") 53 | } 54 | if flag&syscall.IFF_MULTICAST > 0 { 55 | ss = append(ss, "MULTICAST") 56 | } 57 | return strings.Join(ss, " | ") 58 | } 59 | -------------------------------------------------------------------------------- /tools/grpc/python/add_path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | from __future__ import print_function 5 | 6 | import grpc 7 | 8 | import gobgp_pb2 9 | import gobgp_pb2_grpc 10 | import attribute_pb2 11 | import common_pb2 12 | import nlri_pb2 13 | 14 | _TIMEOUT_SECONDS = 1000 15 | 16 | 17 | def run(): 18 | channel = grpc.insecure_channel('localhost:50051') 19 | stub = gobgp_pb2_grpc.GoBgpServiceStub(channel) 20 | 21 | nlri = nlri_pb2.NLRI( 22 | prefix=nlri_pb2.IPAddressPrefix( 23 | prefix_len=24, 24 | prefix="10.0.0.0", 25 | ) 26 | ) 27 | 28 | as_segment = attribute_pb2.AsSegment( 29 | type=attribute_pb2.AsSegment.TYPE_AS_SEQUENCE, 30 | numbers=[100, 200], 31 | ) 32 | 33 | attributes = [ 34 | attribute_pb2.Attribute( 35 | origin=attribute_pb2.OriginAttribute(origin=2) # ORIGIN_INCOMPLETE 36 | ), 37 | attribute_pb2.Attribute( 38 | as_path=attribute_pb2.AsPathAttribute(segments=[as_segment]) 39 | ), 40 | attribute_pb2.Attribute( 41 | next_hop=attribute_pb2.NextHopAttribute(next_hop="1.1.1.1") 42 | ), 43 | ] 44 | 45 | stub.AddPath( 46 | gobgp_pb2.AddPathRequest( 47 | table_type=gobgp_pb2.TABLE_TYPE_GLOBAL, 48 | path=gobgp_pb2.Path( 49 | nlri=nlri, 50 | pattrs=attributes, 51 | family=common_pb2.Family( 52 | afi=common_pb2.Family.AFI_IP, 53 | safi=common_pb2.Family.SAFI_UNICAST, 54 | ), 55 | ) 56 | ), 57 | timeout=_TIMEOUT_SECONDS, 58 | ) 59 | 60 | if __name__ == '__main__': 61 | run() 62 | -------------------------------------------------------------------------------- /pkg/zebra/zapi_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package zebra 17 | 18 | import ( 19 | "strings" 20 | "syscall" 21 | ) 22 | 23 | func intfflag2string(flag uint64) string { 24 | ss := make([]string, 0, 10) 25 | if flag&syscall.IFF_UP > 0 { 26 | ss = append(ss, "UP") 27 | } 28 | if flag&syscall.IFF_BROADCAST > 0 { 29 | ss = append(ss, "BROADCAST") 30 | } 31 | if flag&syscall.IFF_DEBUG > 0 { 32 | ss = append(ss, "DEBUG") 33 | } 34 | if flag&syscall.IFF_LOOPBACK > 0 { 35 | ss = append(ss, "LOOPBACK") 36 | } 37 | if flag&syscall.IFF_POINTOPOINT > 0 { 38 | ss = append(ss, "POINTOPOINT") 39 | } 40 | if flag&syscall.IFF_NOTRAILERS > 0 { 41 | ss = append(ss, "NOTRAILERS") 42 | } 43 | if flag&syscall.IFF_RUNNING > 0 { 44 | ss = append(ss, "RUNNING") 45 | } 46 | if flag&syscall.IFF_NOARP > 0 { 47 | ss = append(ss, "NOARP") 48 | } 49 | if flag&syscall.IFF_PROMISC > 0 { 50 | ss = append(ss, "PROMISC") 51 | } 52 | if flag&syscall.IFF_ALLMULTI > 0 { 53 | ss = append(ss, "ALLMULTI") 54 | } 55 | if flag&syscall.IFF_MULTICAST > 0 { 56 | ss = append(ss, "MULTICAST") 57 | } 58 | return strings.Join(ss, " | ") 59 | } 60 | -------------------------------------------------------------------------------- /pkg/packet/bgp/srbehavior.go: -------------------------------------------------------------------------------- 1 | // Generated code; DO NOT EDIT. 2 | 3 | package bgp 4 | 5 | const ( 6 | RESERVED SRBehavior = 0 7 | END SRBehavior = 1 8 | END_WITH_PSP SRBehavior = 2 9 | END_WITH_USP SRBehavior = 3 10 | END_WITH_PSP_USP SRBehavior = 4 11 | ENDX SRBehavior = 5 12 | ENDX_WITH_PSP SRBehavior = 6 13 | ENDX_WITH_USP SRBehavior = 7 14 | ENDX_WITH_PSP_USP SRBehavior = 8 15 | ENDT SRBehavior = 9 16 | ENDT_WITH_PSP SRBehavior = 10 17 | ENDT_WITH_USP SRBehavior = 11 18 | ENDT_WITH_PSP_USP SRBehavior = 12 19 | END_B6_ENCAPS SRBehavior = 14 20 | END_BM SRBehavior = 15 21 | END_DX6 SRBehavior = 16 22 | END_DX4 SRBehavior = 17 23 | END_DT6 SRBehavior = 18 24 | END_DT4 SRBehavior = 19 25 | END_DT46 SRBehavior = 20 26 | END_DX2 SRBehavior = 21 27 | END_DX2V SRBehavior = 22 28 | END_DT2U SRBehavior = 23 29 | END_DT2M SRBehavior = 24 30 | END_B6_ENCAPS_Red SRBehavior = 27 31 | END_WITH_USD SRBehavior = 28 32 | END_WITH_PSP_USD SRBehavior = 29 33 | END_WITH_USP_USD SRBehavior = 30 34 | END_WITH_PSP_USP_USD SRBehavior = 31 35 | ENDX_WITH_USD SRBehavior = 32 36 | ENDX_WITH_PSP_USD SRBehavior = 33 37 | ENDX_WITH_USP_USD SRBehavior = 34 38 | ENDX_WITH_PSP_USP_USD SRBehavior = 35 39 | ENDT_WITH_USD SRBehavior = 36 40 | ENDT_WITH_PSP_USD SRBehavior = 37 41 | ENDT_WITH_USP_USD SRBehavior = 38 42 | ENDT_WITH_PSP_USP_USD SRBehavior = 39 43 | ENDM_GTP6D SRBehavior = 69 // 0x0045 44 | ENDM_GTP6DI SRBehavior = 70 // 0x0046 45 | ENDM_GTP6E SRBehavior = 71 // 0x0047 46 | ENDM_GTP4E SRBehavior = 72 // 0x0048 47 | ) 48 | -------------------------------------------------------------------------------- /pkg/config/oc/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package oc 17 | 18 | import ( 19 | "testing" 20 | 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | func TestDetectConfigFileType(t *testing.T) { 25 | assert := assert.New(t) 26 | 27 | assert.Equal("toml", detectConfigFileType("bgpd.conf", "toml")) 28 | assert.Equal("toml", detectConfigFileType("bgpd.toml", "xxx")) 29 | assert.Equal("yaml", detectConfigFileType("bgpd.yaml", "xxx")) 30 | assert.Equal("yaml", detectConfigFileType("bgpd.yml", "xxx")) 31 | assert.Equal("json", detectConfigFileType("bgpd.json", "xxx")) 32 | } 33 | 34 | func TestIsAfiSafiChanged(t *testing.T) { 35 | v4 := AfiSafi{ 36 | Config: AfiSafiConfig{ 37 | AfiSafiName: AFI_SAFI_TYPE_IPV4_UNICAST, 38 | }, 39 | } 40 | v6 := AfiSafi{ 41 | Config: AfiSafiConfig{ 42 | AfiSafiName: AFI_SAFI_TYPE_IPV6_UNICAST, 43 | }, 44 | } 45 | old := []AfiSafi{v4} 46 | new := []AfiSafi{v4} 47 | assert.False(t, isAfiSafiChanged(old, new)) 48 | 49 | new = append(new, v6) 50 | assert.True(t, isAfiSafiChanged(old, new)) 51 | 52 | new = []AfiSafi{v6} 53 | assert.True(t, isAfiSafiChanged(old, new)) 54 | v4ap := v4 55 | v4ap.AddPaths.Config.Receive = true 56 | new = []AfiSafi{v4ap} 57 | assert.True(t, isAfiSafiChanged(old, new)) 58 | } 59 | -------------------------------------------------------------------------------- /pkg/zebra/nexthopflag_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=nexthopFlag"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[nexthopFlagActive-1] 12 | _ = x[nexthopFlagFIB-2] 13 | _ = x[nexthopFlagRecursive-4] 14 | _ = x[nexthopFlagOnlink-8] 15 | _ = x[nexthopFlagDuplicate-16] 16 | _ = x[nexthopFlagRnhFiltered-32] 17 | _ = x[nexthopFlagHasBackup-64] 18 | _ = x[nexthopFlagSRTE-128] 19 | _ = x[zapi6Frr7dot3nexthopFlagMatched-16] 20 | _ = x[zapi6Frr7dot3nexthopFlagDuplicate-32] 21 | _ = x[zapi6Frr7dot3nexthopFlagRnhFiltered-64] 22 | _ = x[zapi6Frr7nexthopFlagFiltered-32] 23 | _ = x[zapi6Frr7nexthopFlagDuplicate-64] 24 | _ = x[zapi6Frr7nexthopFlagEvpnRvtep-128] 25 | } 26 | 27 | const ( 28 | _nexthopFlag_name_0 = "nexthopFlagActivenexthopFlagFIB" 29 | _nexthopFlag_name_1 = "nexthopFlagRecursive" 30 | _nexthopFlag_name_2 = "nexthopFlagOnlink" 31 | _nexthopFlag_name_3 = "nexthopFlagDuplicate" 32 | _nexthopFlag_name_4 = "nexthopFlagRnhFiltered" 33 | _nexthopFlag_name_5 = "nexthopFlagHasBackup" 34 | _nexthopFlag_name_6 = "nexthopFlagSRTE" 35 | ) 36 | 37 | var ( 38 | _nexthopFlag_index_0 = [...]uint8{0, 17, 31} 39 | ) 40 | 41 | func (i nexthopFlag) String() string { 42 | switch { 43 | case 1 <= i && i <= 2: 44 | i -= 1 45 | return _nexthopFlag_name_0[_nexthopFlag_index_0[i]:_nexthopFlag_index_0[i+1]] 46 | case i == 4: 47 | return _nexthopFlag_name_1 48 | case i == 8: 49 | return _nexthopFlag_name_2 50 | case i == 16: 51 | return _nexthopFlag_name_3 52 | case i == 32: 53 | return _nexthopFlag_name_4 54 | case i == 64: 55 | return _nexthopFlag_name_5 56 | case i == 128: 57 | return _nexthopFlag_name_6 58 | default: 59 | return "nexthopFlag(" + strconv.FormatInt(int64(i), 10) + ")" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /internal/pkg/netutils/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build !windows 17 | 18 | package netutils 19 | 20 | import ( 21 | "syscall" 22 | ) 23 | 24 | func setSockOptString(sc syscall.RawConn, level int, opt int, str string) error { 25 | var opterr error 26 | fn := func(s uintptr) { 27 | opterr = syscall.SetsockoptString(int(s), level, opt, str) 28 | } 29 | err := sc.Control(fn) 30 | if opterr == nil { 31 | return err 32 | } 33 | return opterr 34 | } 35 | 36 | func setSockOptInt(sc syscall.RawConn, level, name, value int) error { 37 | var opterr error 38 | fn := func(s uintptr) { 39 | opterr = syscall.SetsockoptInt(int(s), level, name, value) 40 | } 41 | err := sc.Control(fn) 42 | if opterr == nil { 43 | return err 44 | } 45 | return opterr 46 | } 47 | 48 | func setSockOptIpTtl(sc syscall.RawConn, family int, value int) error { 49 | level := syscall.IPPROTO_IP 50 | name := syscall.IP_TTL 51 | if family == syscall.AF_INET6 { 52 | level = syscall.IPPROTO_IPV6 53 | name = syscall.IPV6_UNICAST_HOPS 54 | } 55 | return setSockOptInt(sc, level, name, value) 56 | } 57 | 58 | func setSockOptTcpMss(sc syscall.RawConn, family int, value uint16) error { 59 | level := syscall.IPPROTO_TCP 60 | name := syscall.TCP_MAXSEG 61 | return setSockOptInt(sc, level, name, int(value)) 62 | } 63 | -------------------------------------------------------------------------------- /test/scenario_test/ci-scripts/build_embedded_go.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | from subprocess import call 4 | 5 | def build_embedded_go_codes(filename): 6 | """ 7 | Extract embedded Go code snippets from a Markdown file and compile each of them. 8 | 9 | Args: 10 | filename (str): The path to the Markdown file containing embedded Go code snippets. 11 | 12 | Returns: 13 | list: A list of output Go file names that were created and compiled. 14 | 15 | Raises: 16 | ValueError: If no Go code block is found in the file. 17 | """ 18 | 19 | with open(filename, 'r') as f: 20 | flag = False # Tracks if inside Go block 21 | codes = [] # Go codes from embedded 22 | snippet_counter = 1 23 | out_files = [] 24 | 25 | for line in f.readlines(): 26 | if line.strip() == '```go': 27 | flag = True 28 | codes = [] 29 | elif line.strip() == '```' and flag: 30 | out = f'temporary_{snippet_counter}.go' 31 | out_files.append(out) 32 | 33 | if os.path.exists(out): 34 | os.remove(out) 35 | 36 | with open(out, 'w') as g: 37 | g.write("".join(codes)) 38 | 39 | snippet_counter += 1 40 | flag = False 41 | elif flag: 42 | codes.append(line) 43 | 44 | if not out_files: 45 | raise ValueError("No Go code block found in the markdown file (argument).") 46 | 47 | return out_files 48 | 49 | 50 | if __name__ == '__main__': 51 | filename = sys.argv[1] 52 | out_files = build_embedded_go_codes(filename) 53 | 54 | ret_code = 0 55 | for out in out_files: 56 | ret = call(['go', 'build', '-o', out.replace('.go', ''), out]) 57 | if ret != 0: 58 | ret_code = ret 59 | os.remove(out) 60 | if os.path.exists(out.replace('.go', '')): 61 | os.remove(out.replace('.go', '')) 62 | 63 | sys.exit(ret_code) 64 | -------------------------------------------------------------------------------- /pkg/config/oc/default_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | //go:build linux 16 | 17 | package oc 18 | 19 | import ( 20 | "fmt" 21 | "net" 22 | 23 | "github.com/vishvananda/netlink" 24 | ) 25 | 26 | func GetIPv6LinkLocalNeighborAddress(ifname string) (string, error) { 27 | ifi, err := net.InterfaceByName(ifname) 28 | if err != nil { 29 | return "", err 30 | } 31 | neighs, err := netlink.NeighList(ifi.Index, netlink.FAMILY_V6) 32 | if err != nil { 33 | return "", err 34 | } 35 | cnt := 0 36 | var addr net.IP 37 | for _, neigh := range neighs { 38 | local, err := isLocalLinkLocalAddress(ifi.Index, neigh.IP) 39 | if err != nil { 40 | return "", err 41 | } 42 | if neigh.State&netlink.NUD_FAILED == 0 && neigh.IP.IsLinkLocalUnicast() && !local { 43 | addr = neigh.IP 44 | cnt++ 45 | } 46 | } 47 | 48 | if cnt == 0 { 49 | return "", fmt.Errorf("no ipv6 link-local neighbor found") 50 | } else if cnt > 1 { 51 | return "", fmt.Errorf("found %d link-local neighbors. only support p2p link", cnt) 52 | } 53 | 54 | return fmt.Sprintf("%s%%%s", addr, ifname), nil 55 | } 56 | 57 | func isLocalLinkLocalAddress(ifindex int, addr net.IP) (bool, error) { 58 | ifi, err := net.InterfaceByIndex(ifindex) 59 | if err != nil { 60 | return false, err 61 | } 62 | addrs, err := ifi.Addrs() 63 | if err != nil { 64 | return false, err 65 | } 66 | for _, a := range addrs { 67 | if ip, _, _ := net.ParseCIDR(a.String()); addr.Equal(ip) { 68 | return true, nil 69 | } 70 | } 71 | return false, nil 72 | } 73 | -------------------------------------------------------------------------------- /docs/sources/bmp.md: -------------------------------------------------------------------------------- 1 | # BGP Monitoring Protocol 2 | 3 | GoBGP supports [BGP Monitoring Protocol (RFC 7854)](https://tools.ietf.org/html/rfc7854), which provides a convenient interface for obtaining route views. 4 | 5 | ## Prerequisites 6 | 7 | Assume you finished [Getting Started](getting-started.md). 8 | 9 | ## Contents 10 | 11 | - [Configuration](#configuration) 12 | - [Verification](#verification) 13 | 14 | ## Configuration 15 | 16 | Add `[bmp-servers]` session to enable BMP. 17 | 18 | ```toml 19 | [global.config] 20 | as = 64512 21 | router-id = "192.168.255.1" 22 | 23 | [[bmp-servers]] 24 | [bmp-servers.config] 25 | address = "127.0.0.1" 26 | port=11019 27 | ``` 28 | 29 | The supported route monitoring policy types are: 30 | 31 | - pre-policy (Default) 32 | - post-policy 33 | - both (Obsoleted) 34 | - local-rib 35 | - all 36 | 37 | Enable post-policy support as follows: 38 | 39 | ```toml 40 | [[bmp-servers]] 41 | [bmp-servers.config] 42 | address = "127.0.0.1" 43 | port=11019 44 | route-monitoring-policy = "post-policy" 45 | ``` 46 | 47 | Enable all policies support as follows: 48 | 49 | ```toml 50 | [[bmp-servers]] 51 | [bmp-servers.config] 52 | address = "127.0.0.1" 53 | port=11019 54 | route-monitoring-policy = "all" 55 | ``` 56 | 57 | To enable BMP stats reports, specify the interval seconds to send statistics messages. 58 | The default value is 0 and no statistics messages are sent. 59 | Please note the range of this interval is 15 though 65535 seconds. 60 | 61 | ```toml 62 | [[bmp-servers]] 63 | [bmp-servers.config] 64 | address = "127.0.0.1" 65 | port=11019 66 | statistics-timeout = 3600 67 | ``` 68 | 69 | To enable route mirroring feature, specify `true` for `route-mirroring-enabled` option. 70 | Please note this option is mainly for debugging purpose. 71 | 72 | ```toml 73 | [[bmp-servers]] 74 | [bmp-servers.config] 75 | address = "127.0.0.1" 76 | port=11019 77 | route-mirroring-enabled = true 78 | ``` 79 | 80 | ## Verification 81 | 82 | Let's check if BMP works with a bmp server. You can find some OSS BMP server implementations such as [yambp](https://github.com/smartbgp/yabmp), [OpenBMP](https://github.com/SNAS/openbmp), etc. 83 | -------------------------------------------------------------------------------- /cmd/gobgp/loglevel.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | 21 | "github.com/osrg/gobgp/v4/api" 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | func modLogLevelServer(cmdType string, args []string) error { 26 | var level api.SetLogLevelRequest_Level 27 | 28 | switch cmdType { 29 | case cmdPanic: 30 | level = api.SetLogLevelRequest_LEVEL_PANIC 31 | case cmdFatal: 32 | level = api.SetLogLevelRequest_LEVEL_FATAL 33 | case cmdError: 34 | level = api.SetLogLevelRequest_LEVEL_ERROR 35 | case cmdWarn: 36 | level = api.SetLogLevelRequest_LEVEL_WARN 37 | case cmdInfo: 38 | level = api.SetLogLevelRequest_LEVEL_INFO 39 | case cmdDebug: 40 | level = api.SetLogLevelRequest_LEVEL_DEBUG 41 | case cmdTrace: 42 | level = api.SetLogLevelRequest_LEVEL_TRACE 43 | default: 44 | return fmt.Errorf("invalid log level: %s", cmdType) 45 | } 46 | _, err := client.SetLogLevel(ctx, &api.SetLogLevelRequest{Level: level}) 47 | return err 48 | } 49 | 50 | func newLogLevelCmd() *cobra.Command { 51 | logLevelCmd := &cobra.Command{ 52 | Use: cmdLogLevel, 53 | } 54 | cmds := []string{ 55 | cmdPanic, 56 | cmdFatal, 57 | cmdError, 58 | cmdWarn, 59 | cmdInfo, 60 | cmdDebug, 61 | cmdTrace, 62 | } 63 | 64 | for _, cmd := range cmds { 65 | subCmd := &cobra.Command{ 66 | Use: cmd, 67 | Run: func(cmd *cobra.Command, args []string) { 68 | if err := modLogLevelServer(cmd.Use, args); err != nil { 69 | exitWithError(err) 70 | } 71 | }, 72 | } 73 | logLevelCmd.AddCommand(subCmd) 74 | } 75 | return logLevelCmd 76 | } 77 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build dragonfly || freebsd || netbsd 17 | 18 | package netutils 19 | 20 | import ( 21 | "net" 22 | "syscall" 23 | ) 24 | 25 | const ( 26 | tcpMD5SIG = 0x10 // TCP MD5 Signature (RFC2385) 27 | ipv6MinHopCount = 73 // Generalized TTL Security Mechanism (RFC5082) 28 | ) 29 | 30 | func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error { 31 | sc, err := l.SyscallConn() 32 | if err != nil { 33 | return err 34 | } 35 | // always enable and assumes that the configuration is done by setkey() 36 | return setSockOptInt(sc, syscall.IPPROTO_TCP, tcpMD5SIG, 1) 37 | } 38 | 39 | func SetTcpTTLSockopt(conn net.Conn, ttl int) error { 40 | family := extractFamilyFromConn(conn) 41 | sc, err := conn.(syscall.Conn).SyscallConn() 42 | if err != nil { 43 | return err 44 | } 45 | return setSockOptIpTtl(sc, family, ttl) 46 | } 47 | 48 | func SetTcpMinTTLSockopt(conn net.Conn, ttl int) error { 49 | family := extractFamilyFromConn(conn) 50 | sc, err := conn.(syscall.Conn).SyscallConn() 51 | if err != nil { 52 | return err 53 | } 54 | level := syscall.IPPROTO_IP 55 | name := syscall.IP_MINTTL 56 | if family == syscall.AF_INET6 { 57 | level = syscall.IPPROTO_IPV6 58 | name = ipv6MinHopCount 59 | } 60 | return setSockOptInt(sc, level, name, ttl) 61 | } 62 | 63 | func SetTcpMSSSockopt(conn net.Conn, mss uint16) error { 64 | family := extractFamilyFromConn(conn) 65 | sc, err := conn.(syscall.Conn).SyscallConn() 66 | if err != nil { 67 | return err 68 | } 69 | return setSockOptTcpMss(sc, family, mss) 70 | } 71 | -------------------------------------------------------------------------------- /tools/spell-check/scspell.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=`dirname $0` 4 | GOBGP=${SCRIPT_DIR}/../../ 5 | 6 | FUNCS=( 7 | Debug 8 | Debugf 9 | Debugln 10 | Error 11 | Errorf 12 | Errorln 13 | Fatal 14 | Fatalf 15 | Fatalln 16 | Fprint 17 | Fprintf 18 | Fprintln 19 | Info 20 | Infof 21 | Infoln 22 | Panic 23 | Panicf 24 | Panicln 25 | Print 26 | Printf 27 | Println 28 | Sprint 29 | Sprintf 30 | Sprintln 31 | Warn 32 | Warnf 33 | Warning 34 | Warningf 35 | Warningln 36 | Warnln 37 | ) 38 | 39 | CHECK_LOG=/tmp/gobgp/scspell.log 40 | mkdir -p `dirname ${CHECK_LOG}` 41 | rm -f ${CHECK_LOG} # Clean up previous output 42 | 43 | # Do find *.go files except under vendor directory 44 | for FILE in `find ${GOBGP} -type d -name vendor -prune -o -type f -name *.go | sort` 45 | do 46 | TMP_FILE=${FILE/${GOBGP}//tmp/gobgp/} 47 | mkdir -p `dirname ${TMP_FILE}` 48 | rm -f ${TMP_FILE} # Clean up previous output 49 | 50 | for FUNC in ${FUNCS[@]} 51 | do 52 | # Do grep cases like: 53 | # fmt.Print("...") 54 | # or 55 | # fmt.Print( 56 | # "...") 57 | grep ${FUNC}'("' ${FILE} | grep -o '".*"' >> ${TMP_FILE} 58 | grep ${FUNC}'($' -A 1 ${FILE} | grep -o '".*"' >> ${TMP_FILE} 59 | done 60 | 61 | # If any case found 62 | if [ -s ${TMP_FILE} ] 63 | then 64 | # Apply exclude rules defined in ignore.txt 65 | for WORD in `grep -v -e '^\s*#' -e '^$' ${SCRIPT_DIR}/ignore.txt` 66 | do 67 | sed -i "s/${WORD}//g" ${TMP_FILE} 68 | done 69 | 70 | # Do scspell with dictionary.txt and reformat messages 71 | scspell \ 72 | --use-builtin-base-dict \ 73 | --override-dictionary ${SCRIPT_DIR}/dictionary.txt \ 74 | --report-only \ 75 | ${TMP_FILE} 2>&1 \ 76 | | tee -a ${CHECK_LOG} \ 77 | | sed "s/\/tmp\/gobgp\///" | cut -d ':' -f -1,3- 78 | fi 79 | 80 | #rm ${TMP_FILE} 81 | done 82 | 83 | RESULT=0 84 | 85 | # If any output of scspell exists 86 | if [ -s ${CHECK_LOG} ] 87 | then 88 | echo "---" 89 | echo "See ${CHECK_LOG} for more details." 90 | # Set return code as error 91 | RESULT=1 92 | fi 93 | 94 | #rm -f ${CHECK_LOG} 95 | exit ${RESULT} 96 | 97 | -------------------------------------------------------------------------------- /tools/completion/zsh/_gobgp: -------------------------------------------------------------------------------- 1 | #compdef gobgp 2 | __af(){ 3 | _arguments \ 4 | '-a[address family]::(ipv4 ipv6 evpn encap rtc)' 5 | } 6 | 7 | __global(){ 8 | local -a _global_arguments 9 | _global_arguments=( 10 | "rib" 11 | ) 12 | 13 | _arguments : \ 14 | '*:: :->command' 15 | 16 | if (( CURRENT == 1 )); then 17 | _describe -t commands "global command" _global_arguments 18 | return 19 | fi 20 | 21 | case "$words[1]" in 22 | rib) 23 | __af ;; 24 | esac 25 | } 26 | 27 | __neighbor(){ 28 | : ${(A)_neighbors::=${=${$(gobgp -u ${${opt_args[-u]}:-127.0.0.1} -q neighbor)//\:/\\:}}} 29 | 30 | _arguments : \ 31 | '*:: :->command' 32 | 33 | if (( CURRENT == 1 )); then 34 | _describe -t commands "neighbor selection" _neighbors 35 | return 36 | fi 37 | 38 | local -a _neighbor_arguments 39 | _neighbor_arguments=( 40 | "local" 41 | "adj-in" 42 | "adj-out" 43 | "reset" 44 | "softreset" 45 | "softresetin" 46 | "softresetout" 47 | "shutdown" 48 | "enable" 49 | "disable" 50 | "policy" 51 | ) 52 | 53 | _arguments : \ 54 | '*:: :->command' 55 | 56 | if (( CURRENT == 1 )); then 57 | _describe -t commands "neighbor command" _neighbor_arguments 58 | return 59 | fi 60 | 61 | case "$words[1]" in 62 | local) ;& 63 | adj-in) ;& 64 | adj-out) ;& 65 | reset) ;& 66 | softreset) ;& 67 | softresetin) ;& 68 | softresetout) 69 | __af ;; 70 | esac 71 | } 72 | 73 | local -a _gobgp_arguments 74 | _gobgp_arguments=( 75 | "global" 76 | "neighbor" 77 | ) 78 | 79 | _arguments : \ 80 | '-u[specifying an url (127.0.0.1)]::' \ 81 | '-p[specifying a port]::' \ 82 | '-d[use debug]' \ 83 | '-q[use quiet]' \ 84 | '-j[use json format to output format]' \ 85 | '-h[Show this help message]' \ 86 | '*:: :->command' 87 | 88 | if (( CURRENT == 1 )); then 89 | _describe -t commands "gobgp command" _gobgp_arguments 90 | return 91 | fi 92 | 93 | case "$words[1]" in 94 | global) 95 | __global ;; 96 | neighbor) 97 | __neighbor ;; 98 | esac 99 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build !linux && !openbsd && !windows 17 | 18 | package netutils 19 | 20 | import ( 21 | "fmt" 22 | "log/slog" 23 | "net" 24 | "syscall" 25 | ) 26 | 27 | func SetTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error { 28 | return SetTcpMD5SigSockopt(l, address, key) 29 | } 30 | 31 | func SetTCPTTLSockopt(conn net.Conn, ttl int) error { 32 | return SetTcpTTLSockopt(conn, ttl) 33 | } 34 | 35 | func SetTCPMinTTLSockopt(conn net.Conn, ttl int) error { 36 | return SetTcpMinTTLSockopt(conn, ttl) 37 | } 38 | 39 | func SetBindToDevSockopt(sc syscall.RawConn, device string) error { 40 | return fmt.Errorf("binding connection to a device is not supported") 41 | } 42 | 43 | func SetTCPMSSSockopt(conn net.Conn, mss uint16) error { 44 | return SetTcpMSSSockopt(conn, mss) 45 | } 46 | 47 | func DialerControl(logger *slog.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, mss uint16, password string, bindInterface string) error { 48 | if password != "" { 49 | logger.Warn("setting md5 for active connection is not supported", 50 | slog.String("Topic", "Peer"), 51 | slog.String("Key", address), 52 | ) 53 | } 54 | if ttl != 0 { 55 | logger.Warn("setting ttl for active connection is not supported", 56 | slog.String("Topic", "Peer"), 57 | slog.String("Key", address), 58 | ) 59 | } 60 | if minTtl != 0 { 61 | logger.Warn("setting min ttl for active connection is not supported", 62 | slog.String("Topic", "Peer"), 63 | slog.String("Key", address), 64 | ) 65 | } 66 | if mss != 0 { 67 | logger.Warn("setting MSS for active connection is not supported", 68 | slog.String("Topic", "Peer"), 69 | slog.String("Key", address), 70 | ) 71 | } 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /docs/sources/route-server.md: -------------------------------------------------------------------------------- 1 | # Route Server 2 | 3 | This page explains how to set up GoBGP as a [route server](https://tools.ietf.org/html/rfc7947) 4 | 5 | ## Prerequisites 6 | 7 | Assumed that you finished [Getting Started](getting-started.md). 8 | 9 | ## Configuration 10 | 11 | This example uses the following simple configuration file, `gobgpd.conf`. There are three changes from 12 | the configuration file used in [Getting Started](getting-started.md) 13 | 14 | - Peers are configured as route server clients (of course!). 15 | - GoBGP doesn't try to connect to peers. It only listens and accepts. 16 | - MD5 passwords are enabled. 17 | 18 | ```toml 19 | [global.config] 20 | as = 64512 21 | router-id = "192.168.255.1" 22 | 23 | [[neighbors]] 24 | [neighbors.config] 25 | neighbor-address = "10.0.255.1" 26 | peer-as = 65001 27 | auth-password = "hoge1" 28 | [neighbors.transport.config] 29 | passive-mode = true 30 | [neighbors.route-server.config] 31 | route-server-client = true 32 | 33 | [[neighbors]] 34 | [neighbors.config] 35 | neighbor-address = "10.0.255.2" 36 | peer-as = 65002 37 | auth-password = "hoge2" 38 | [neighbors.transport.config] 39 | passive-mode = true 40 | [neighbors.route-server.config] 41 | route-server-client = true 42 | ``` 43 | 44 | ## Starting GoBGP 45 | 46 | Let's start gobgpd: 47 | 48 | ```bash 49 | $ sudo -E gobgpd -f gobgpd.conf 50 | {"level":"info","msg":"Peer 10.0.255.1 is added","time":"2015-04-06T22:55:57+09:00"} 51 | {"level":"info","msg":"Peer 10.0.255.2 is added","time":"2015-04-06T22:55:57+09:00"} 52 | ``` 53 | 54 | GoBGP implements multiple RIBs, that is, each peer has own local 55 | RIB. Let's check respectively. 56 | 57 | ```bash 58 | $ gobgp neighbor 10.0.255.1 local 59 | Network Next Hop AS_PATH Age Attrs 60 | *> 10.3.0.0/24 10.0.255.2 [65002] 00:05:50 [{Origin: 0} {Med: 0}] 61 | *> 192.168.2.0/24 10.0.255.2 [65002] 00:05:50 [{Origin: 0} {Med: 0}] 62 | ``` 63 | 64 | ```bash 65 | $ gobgp neighbor 10.0.255.2 local 66 | Network Next Hop AS_PATH Age Attrs 67 | *> 10.3.0.0/16 10.0.255.1 [65001] 00:06:12 [{Origin: 0} {Med: 0}] 68 | *> 10.3.0.1/32 10.0.255.1 [65001] 00:06:12 [{Origin: 0} {Med: 0}] 69 | ``` 70 | 71 | Of course, you can also look at the adjacent rib-in and rib-out of each peer as done in [Getting Started](getting-started.md). 72 | -------------------------------------------------------------------------------- /pkg/packet/bgp/vpls_test.go: -------------------------------------------------------------------------------- 1 | package bgp 2 | 3 | import ( 4 | "net/netip" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_VPLSExtended(t *testing.T) { 12 | assert := assert.New(t) 13 | exts := make([]ExtendedCommunityInterface, 0) 14 | exts = append(exts, NewVPLSExtended(100, 1500)) 15 | m1 := NewPathAttributeExtendedCommunities(exts) 16 | buf1, err := m1.Serialize() 17 | require.NoError(t, err) 18 | 19 | m2 := NewPathAttributeExtendedCommunities(nil) 20 | err = m2.DecodeFromBytes(buf1) 21 | require.NoError(t, err) 22 | 23 | _, err = m2.Serialize() 24 | require.NoError(t, err) 25 | 26 | assert.Equal(m1, m2) 27 | } 28 | 29 | func Test_VPLSExtended_decoding(t *testing.T) { 30 | assert := assert.New(t) 31 | buf := []byte{ 32 | 0xc0, 0x10, 0x10, 0x00, 0x02, 0xfd, 0xf9, 0x00, 0x00, 0x00, 33 | 0x68, 0x80, 0x0a, 0x13, 0x00, 0x05, 0xdc, 0x00, 0x64, 34 | } 35 | m1 := NewPathAttributeExtendedCommunities(nil) 36 | err := m1.DecodeFromBytes(buf) 37 | require.NoError(t, err) 38 | 39 | exts := make([]ExtendedCommunityInterface, 0) 40 | exts = append(exts, NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 65017, 104, true), NewVPLSExtended(0, 1500)) 41 | m2 := NewPathAttributeExtendedCommunities(exts) 42 | 43 | assert.Equal(m1, m2) 44 | } 45 | 46 | func Test_VPLSNLRI(t *testing.T) { 47 | assert := assert.New(t) 48 | n1 := NewVPLSNLRI(NewRouteDistinguisherTwoOctetAS(65500, 10), 1, 3, 8, 100) 49 | buf1, err := n1.Serialize() 50 | assert.NoError(err) 51 | n2 := &VPLSNLRI{} 52 | err = n2.decodeFromBytes(buf1) 53 | assert.NoError(err) 54 | 55 | t.Logf("%s", n1) 56 | t.Logf("%s", n2) 57 | 58 | assert.Equal(n1, n1) 59 | } 60 | 61 | func Test_VPLSNLRI_decoding(t *testing.T) { 62 | assert := assert.New(t) 63 | buf := []byte{ 64 | 0x90, 0x0e, 0x00, 0x1c, 0x00, 0x19, 0x41, 0x04, 0xc0, 0x00, 0x02, 65 | 0x07, 0x00, 0x00, 0x11, 0x00, 0x00, 0xfd, 0xf9, 0x00, 0x00, 0x00, 66 | 0x68, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0xc3, 0x50, 0x01, 67 | } 68 | m1 := &PathAttributeMpReachNLRI{} 69 | err := m1.DecodeFromBytes(buf) 70 | require.NoError(t, err) 71 | 72 | rd := NewRouteDistinguisherTwoOctetAS(65017, 104) 73 | nlri := NewVPLSNLRI(rd, 1, 1, 8, 800000) 74 | m2, _ := NewPathAttributeMpReachNLRI(RF_VPLS, []PathNLRI{{NLRI: nlri}}, netip.MustParseAddr("192.0.2.7")) 75 | m2.Flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH 76 | 77 | assert.Equal(m1, m2) 78 | } 79 | -------------------------------------------------------------------------------- /pkg/zebra/zapi_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package zebra 17 | 18 | import ( 19 | "strings" 20 | "syscall" 21 | ) 22 | 23 | func intfflag2string(flag uint64) string { 24 | ss := make([]string, 0, 10) 25 | if flag&syscall.IFF_UP > 0 { 26 | ss = append(ss, "UP") 27 | } 28 | if flag&syscall.IFF_BROADCAST > 0 { 29 | ss = append(ss, "BROADCAST") 30 | } 31 | if flag&syscall.IFF_DEBUG > 0 { 32 | ss = append(ss, "DEBUG") 33 | } 34 | if flag&syscall.IFF_LOOPBACK > 0 { 35 | ss = append(ss, "LOOPBACK") 36 | } 37 | if flag&syscall.IFF_POINTOPOINT > 0 { 38 | ss = append(ss, "POINTOPOINT") 39 | } 40 | if flag&syscall.IFF_NOTRAILERS > 0 { 41 | ss = append(ss, "NOTRAILERS") 42 | } 43 | if flag&syscall.IFF_RUNNING > 0 { 44 | ss = append(ss, "RUNNING") 45 | } 46 | if flag&syscall.IFF_NOARP > 0 { 47 | ss = append(ss, "NOARP") 48 | } 49 | if flag&syscall.IFF_PROMISC > 0 { 50 | ss = append(ss, "PROMISC") 51 | } 52 | if flag&syscall.IFF_ALLMULTI > 0 { 53 | ss = append(ss, "ALLMULTI") 54 | } 55 | if flag&syscall.IFF_MASTER > 0 { 56 | ss = append(ss, "MASTER") 57 | } 58 | if flag&syscall.IFF_SLAVE > 0 { 59 | ss = append(ss, "SLAVE") 60 | } 61 | if flag&syscall.IFF_MULTICAST > 0 { 62 | ss = append(ss, "MULTICAST") 63 | } 64 | if flag&syscall.IFF_PORTSEL > 0 { 65 | ss = append(ss, "PORTSEL") 66 | } 67 | if flag&syscall.IFF_AUTOMEDIA > 0 { 68 | ss = append(ss, "AUTOMEDIA") 69 | } 70 | if flag&syscall.IFF_DYNAMIC > 0 { 71 | ss = append(ss, "DYNAMIC") 72 | } 73 | // if flag&syscall.IFF_LOWER_UP > 0 { 74 | // ss = append(ss, "LOWER_UP") 75 | // } 76 | // if flag&syscall.IFF_DORMANT > 0 { 77 | // ss = append(ss, "DORMANT") 78 | // } 79 | // if flag&syscall.IFF_ECHO > 0 { 80 | // ss = append(ss, "ECHO") 81 | // } 82 | return strings.Join(ss, " | ") 83 | } 84 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/osrg/gobgp/v4 2 | 3 | go 1.24.5 4 | 5 | require ( 6 | github.com/BurntSushi/toml v1.5.0 7 | github.com/coreos/go-systemd/v22 v22.5.0 8 | github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da 9 | github.com/eapache/channels v1.1.0 10 | github.com/fsnotify/fsnotify v1.9.0 11 | github.com/getsentry/sentry-go v0.34.1 12 | github.com/go-test/deep v1.1.1 13 | github.com/google/go-cmp v0.7.0 14 | github.com/google/uuid v1.6.0 15 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 16 | github.com/jessevdk/go-flags v1.6.1 17 | github.com/k-sone/critbitgo v1.4.0 18 | github.com/kr/pretty v0.3.1 19 | github.com/orcaman/concurrent-map/v2 v2.0.1 20 | github.com/prometheus/client_golang v1.16.0 21 | github.com/prometheus/client_model v0.3.0 22 | github.com/segmentio/fasthash v1.0.3 23 | github.com/sirupsen/logrus v1.9.3 24 | github.com/spf13/cobra v1.9.1 25 | github.com/spf13/viper v1.20.1 26 | github.com/stretchr/testify v1.10.0 27 | github.com/vishvananda/netlink v1.3.1 28 | golang.org/x/sys v0.34.0 29 | golang.org/x/text v0.27.0 30 | golang.org/x/time v0.12.0 31 | google.golang.org/grpc v1.73.0 32 | google.golang.org/protobuf v1.36.6 33 | ) 34 | 35 | require ( 36 | github.com/beorn7/perks v1.0.1 // indirect 37 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 38 | github.com/davecgh/go-spew v1.1.1 // indirect 39 | github.com/eapache/queue v1.1.0 // indirect 40 | github.com/go-viper/mapstructure/v2 v2.4.0 // indirect 41 | github.com/golang/protobuf v1.5.4 // indirect 42 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 43 | github.com/kr/text v0.2.0 // indirect 44 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 45 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 46 | github.com/pmezard/go-difflib v1.0.0 // indirect 47 | github.com/prometheus/common v0.42.0 // indirect 48 | github.com/prometheus/procfs v0.10.1 // indirect 49 | github.com/rogpeppe/go-internal v1.9.0 // indirect 50 | github.com/sagikazarmark/locafero v0.7.0 // indirect 51 | github.com/sourcegraph/conc v0.3.0 // indirect 52 | github.com/spf13/afero v1.12.0 // indirect 53 | github.com/spf13/cast v1.7.1 // indirect 54 | github.com/spf13/pflag v1.0.6 // indirect 55 | github.com/subosito/gotenv v1.6.0 // indirect 56 | github.com/vishvananda/netns v0.0.5 // indirect 57 | go.uber.org/atomic v1.9.0 // indirect 58 | go.uber.org/multierr v1.9.0 // indirect 59 | golang.org/x/net v0.38.0 // indirect 60 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect 61 | gopkg.in/yaml.v3 v3.0.1 // indirect 62 | ) 63 | -------------------------------------------------------------------------------- /pkg/server/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package server 17 | 18 | import ( 19 | "github.com/eapache/channels" 20 | 21 | "github.com/osrg/gobgp/v4/pkg/packet/bgp" 22 | ) 23 | 24 | func nonblockSendChannel[T any](ch chan<- T, item T) bool { 25 | select { 26 | case ch <- item: 27 | // sent 28 | return true 29 | default: 30 | // drop the item 31 | return false 32 | } 33 | } 34 | 35 | func drainChannel[T any](ch <-chan T) { 36 | for { 37 | select { 38 | case _, ok := <-ch: 39 | if !ok { 40 | return 41 | } 42 | // drain the channel 43 | default: 44 | return 45 | } 46 | } 47 | } 48 | 49 | func cleanInfiniteChannel(ch *channels.InfiniteChannel) { 50 | ch.Close() 51 | // drain all remaining items 52 | drainChannel(ch.Out()) 53 | } 54 | 55 | // Returns the binary formatted Administrative Shutdown Communication from the 56 | // given string value. 57 | func newAdministrativeCommunication(communication string) (data []byte) { 58 | if communication == "" { 59 | return nil 60 | } 61 | com := []byte(communication) 62 | if len(com) > bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX { 63 | data = []byte{bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX} 64 | data = append(data, com[:bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX]...) 65 | } else { 66 | data = []byte{byte(len(com))} 67 | data = append(data, com...) 68 | } 69 | return data 70 | } 71 | 72 | // Parses the given NOTIFICATION message data as a binary value and returns 73 | // the Administrative Shutdown Communication in string and the rest binary. 74 | func decodeAdministrativeCommunication(data []byte) (string, []byte) { 75 | if len(data) == 0 { 76 | return "", data 77 | } 78 | communicationLen := min(int(data[0]), bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX) 79 | if communicationLen > len(data)-1 { 80 | communicationLen = len(data) - 1 81 | } 82 | return string(data[1 : communicationLen+1]), data[communicationLen+1:] 83 | } 84 | -------------------------------------------------------------------------------- /docs/sources/route-reflector.md: -------------------------------------------------------------------------------- 1 | # Route Reflector 2 | 3 | This page explains how to set up GoBGP as a route reflector. 4 | 5 | ## Prerequisites 6 | 7 | Assumed you finished [Getting Started](getting-started.md). 8 | 9 | ## Configuration 10 | 11 | Configure `RouteReflector.RouteReflectorConfig` section to enable route reflector functionality. 12 | The configuration below configures two route reflector clients and two normal iBGP peers. 13 | 14 | ```toml 15 | [global.config] 16 | router-id = "192.168.0.1" 17 | as = 65000 18 | 19 | [[neighbors]] 20 | [neighbors.config] 21 | neighbor-address = "192.168.10.2" 22 | peer-as = 65000 23 | [neighbors.route-reflector.config] 24 | route-reflector-client = true 25 | route-reflector-cluster-id = "192.168.0.1" 26 | 27 | [[neighbors]] 28 | [neighbors.config] 29 | neighbor-address = "192.168.10.3" 30 | peer-as = 65000 31 | [neighbors.route-reflector.config] 32 | route-reflector-client = true 33 | route-reflector-cluster-id = "192.168.0.1" 34 | 35 | [[neighbors]] 36 | [neighbors.config] 37 | neighbor-address = "192.168.10.4" 38 | peer-as = 65000 39 | 40 | [[neighbors]] 41 | [neighbors.config] 42 | neighbor-address = "192.168.10.5" 43 | peer-as = 65000 44 | ``` 45 | 46 | ## Check route reflector behavior 47 | 48 | Let's check adj-rib-out of a route reflector client. 49 | 50 | ```bash 51 | $ gobgp neighbor 192.168.10.2 adj-out 52 | Network Next Hop AS_PATH Attrs 53 | 10.0.2.0/24 192.168.10.3 [{Origin: i} {Med: 0} {LocalPref: 100} {Originator: 192.168.0.3} {ClusterList: [192.168.0.1]}] 54 | 10.0.3.0/24 192.168.10.4 [{Origin: i} {Med: 0} {LocalPref: 100} {Originator: 192.168.0.4} {ClusterList: [192.168.0.1]}] 55 | 10.0.4.0/24 192.168.10.5 [{Origin: i} {Med: 0} {LocalPref: 100} {Originator: 192.168.0.5} {ClusterList: [192.168.0.1]}] 56 | ``` 57 | 58 | You can see the routes from other iBGP peers are reflected. 59 | Also Originator and ClusterList path attributes are added. 60 | 61 | For the normal iBGP peer's adj-rib-out 62 | 63 | ```bash 64 | $ gobgp neighbor 192.168.10.4 adj-out 65 | Network Next Hop AS_PATH Attrs 66 | 10.0.1.0/24 192.168.10.2 [{Origin: i} {Med: 0} {LocalPref: 100}] 67 | 10.0.2.0/24 192.168.10.3 [{Origin: i} {Med: 0} {LocalPref: 100}] 68 | ``` 69 | 70 | Only the routes from route reflector clients are advertised via GoBGP. 71 | Originator and ClusterList path attributes are not added. 72 | -------------------------------------------------------------------------------- /pkg/zebra/routetype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=RouteType"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[routeSystem-0] 12 | _ = x[routeKernel-1] 13 | _ = x[routeConnect-2] 14 | _ = x[RouteStatic-3] 15 | _ = x[routeRIP-4] 16 | _ = x[routeRIPNG-5] 17 | _ = x[routeOSPF-6] 18 | _ = x[routeOSPF6-7] 19 | _ = x[routeISIS-8] 20 | _ = x[RouteBGP-9] 21 | _ = x[routePIM-10] 22 | _ = x[routeEIGRP-11] 23 | _ = x[routeNHRP-12] 24 | _ = x[routeHSLS-13] 25 | _ = x[routeOLSR-14] 26 | _ = x[routeTABLE-15] 27 | _ = x[routeLDP-16] 28 | _ = x[routeVNC-17] 29 | _ = x[routeVNCDirect-18] 30 | _ = x[routeVNCDirectRH-19] 31 | _ = x[routeBGPDirect-20] 32 | _ = x[routeBGPDirectEXT-21] 33 | _ = x[routeBABEL-22] 34 | _ = x[routeSHARP-23] 35 | _ = x[routePBR-24] 36 | _ = x[routeBFD-25] 37 | _ = x[routeOpenfabric-26] 38 | _ = x[routeVRRP-27] 39 | _ = x[routeNHG-28] 40 | _ = x[routeSRTE-29] 41 | _ = x[routeAll-30] 42 | _ = x[routeMax-31] 43 | _ = x[zapi5Frr4RouteAll-24] 44 | _ = x[zapi5Frr5RouteAll-25] 45 | _ = x[zapi6Frr6RouteAll-26] 46 | _ = x[zapi6Frr7RouteAll-27] 47 | _ = x[zapi6Frr7dot2RouteAll-28] 48 | _ = x[zapi6Frr7dot3RouteAll-29] 49 | _ = x[zapi4RouteNHRP-11] 50 | _ = x[zapi4RouteHSLS-12] 51 | _ = x[zapi4RouteOLSR-13] 52 | _ = x[zapi4RouteTABLE-14] 53 | _ = x[zapi4RouteLDP-15] 54 | _ = x[zapi4RouteVNC-16] 55 | _ = x[zapi4RouteVNCDirect-17] 56 | _ = x[zapi4RouteVNCDirectRH-18] 57 | _ = x[zapi4RouteBGPDixrect-19] 58 | _ = x[zapi4RouteBGPDirectEXT-20] 59 | _ = x[zapi4RouteAll-21] 60 | _ = x[zapi3RouteHSLS-11] 61 | _ = x[zapi3RouteOLSR-12] 62 | _ = x[zapi3RouteBABEL-13] 63 | _ = x[zapi3RouteNHRP-14] 64 | } 65 | 66 | const _RouteType_name = "routeSystemrouteKernelrouteConnectRouteStaticrouteRIProuteRIPNGrouteOSPFrouteOSPF6routeISISRouteBGProutePIMrouteEIGRProuteNHRProuteHSLSrouteOLSRrouteTABLErouteLDProuteVNCrouteVNCDirectrouteVNCDirectRHrouteBGPDirectrouteBGPDirectEXTrouteBABELrouteSHARProutePBRrouteBFDrouteOpenfabricrouteVRRProuteNHGrouteSRTErouteAllrouteMax" 67 | 68 | var _RouteType_index = [...]uint16{0, 11, 22, 34, 45, 53, 63, 72, 82, 91, 99, 107, 117, 126, 135, 144, 154, 162, 170, 184, 200, 214, 231, 241, 251, 259, 267, 282, 291, 299, 308, 316, 324} 69 | 70 | func (i RouteType) String() string { 71 | if i >= RouteType(len(_RouteType_index)-1) { 72 | return "RouteType(" + strconv.FormatInt(int64(i), 10) + ")" 73 | } 74 | return _RouteType_name[_RouteType_index[i]:_RouteType_index[i+1]] 75 | } 76 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "2" 3 | 4 | issues: 5 | max-issues-per-linter: 0 6 | 7 | linters: 8 | # defaults: errcheck, govet, ineffassign, staticcheck, unused 9 | enable: 10 | - misspell 11 | - whitespace 12 | # - unparam 13 | - unconvert 14 | - intrange 15 | - copyloopvar 16 | settings: 17 | errcheck: 18 | exclude-functions: 19 | # local 20 | - (*github.com/osrg/gobgp/v4/pkg/server.tcpListener).Close 21 | 22 | # other packages 23 | - github.com/coreos/go-systemd/v22/daemon.SdNotify 24 | - github.com/kr/pretty.Printf 25 | - github.com/kr/pretty.Println 26 | - (*os.File).Sync 27 | - (*os.File).Close 28 | - (net.Conn).Close 29 | - (*net.conn).Close 30 | - (net.Conn).SetReadDeadline 31 | - (net.Conn).SetWriteDeadline 32 | - (net.Listener).Close 33 | - (*google.golang.org/grpc.ClientConn).Close 34 | - (net.Conn).Write 35 | - (*bufio.Writer).Flush 36 | copyloopvar: 37 | check-alias: true 38 | exclusions: 39 | rules: 40 | # https://github.com/kisielk/errcheck/issues/101 41 | # exclude deferred error 42 | - path: . 43 | linters: 44 | - errcheck 45 | source: "^\\s*defer\\s+" 46 | # exclude goroutine error 47 | - path: . 48 | linters: 49 | - errcheck 50 | source: "^\\s*go\\s+" 51 | 52 | formatters: 53 | enable: 54 | - gofmt 55 | - gofumpt 56 | - goimports 57 | settings: 58 | gofmt: 59 | rewrite-rules: 60 | # remove unnecessary parenthesis 61 | - pattern: "(a)" 62 | replacement: "a" 63 | # use any 64 | - pattern: "interface{}" 65 | replacement: "any" 66 | # slice simply 67 | - pattern: "a[b:len(a)]" 68 | replacement: "a[b:]" 69 | - pattern: "a[0:b]" 70 | replacement: "a[:b]" 71 | 72 | # assert no error 73 | - pattern: "assert.Nil(err)" 74 | replacement: "assert.NoError(err)" 75 | - pattern: "assert.Nil(t, err)" 76 | replacement: "assert.NoError(t, err)" 77 | - pattern: "assert.Equal(t, nil, err)" 78 | replacement: "assert.NoError(t, err)" 79 | 80 | # assert nil/no-nil 81 | - pattern: "assert.Equal(nil, a)" 82 | replacement: "assert.Nil(a)" 83 | - pattern: "assert.Equal(t, nil, a)" 84 | replacement: "assert.Nil(t, a)" 85 | - pattern: "assert.NotEqual(nil, a)" 86 | replacement: "assert.NotNil(a)" 87 | - pattern: "assert.NotEqual(t, nil, a)" 88 | replacement: "assert.NotNil(t, a)" 89 | -------------------------------------------------------------------------------- /docs/sources/peer-group.md: -------------------------------------------------------------------------------- 1 | # Peer Group 2 | 3 | This page explains how to configure the Peer Group features. 4 | With Peer Group, you can set the same configuration to multiple peers. 5 | 6 | ## Contents 7 | 8 | - [Prerequisite](#prerequisite) 9 | - [Configuration](#configuration) 10 | - [Verification](#verification) 11 | 12 | ## Prerequisite 13 | 14 | Assumed that you finished [Getting Started](getting-started.md). 15 | 16 | ## Configuration 17 | 18 | Below is the configuration to create a peer group. 19 | 20 | ```toml 21 | [[peer-groups]] 22 | [peer-groups.config] 23 | peer-group-name = "sample-group" 24 | peer-as = 65001 25 | [[peer-groups.afi-safis]] 26 | [peer-groups.afi-safis.config] 27 | afi-safi-name = "ipv4-unicast" 28 | [[peer-groups.afi-safis]] 29 | [peer-groups.afi-safis.config] 30 | afi-safi-name = "ipv4-flowspec" 31 | ``` 32 | 33 | The configurations in this peer group will be inherited to the neighbors which is the member of this peer group. 34 | In addition, you can add additional configurations to each member. 35 | 36 | Below is the configuration to create a neighbor which belongs this peer group. 37 | 38 | ```toml 39 | [[neighbors]] 40 | [neighbors.config] 41 | neighbor-address = "172.40.1.3" 42 | peer-group = "sample-group" 43 | [neighbors.timers.config] 44 | hold-time = 99 45 | ``` 46 | 47 | This neighbor belongs to the peer group, so the peer-as is 65001, and ipv4-unicast and ipv4-flowspec are enabled. 48 | Furthermore, an additional configuration is set, the hold timer is 99 secs. 49 | 50 | ## Verification 51 | 52 | You can see the neighbor configuration inherits the peer group config by running `gobgp neighbor` command. 53 | 54 | ```shell 55 | $ gobgp neighbor 172.40.1.3 56 | BGP neighbor is 172.40.1.3, remote AS 65001 57 | BGP version 4, remote router ID 172.40.1.3 58 | BGP state = established, up for 00:00:05 59 | BGP OutQ = 0, Flops = 0 60 | Hold time is 99, keepalive interval is 33 seconds 61 | Configured hold time is 99, keepalive interval is 33 seconds 62 | 63 | Neighbor capabilities: 64 | multiprotocol: 65 | ipv4-unicast: advertised and received 66 | ipv4-flowspec: advertised and received 67 | route-refresh: advertised and received 68 | 4-octet-as: advertised and received 69 | Message statistics: 70 | Sent Rcvd 71 | Opens: 1 1 72 | Notifications: 0 0 73 | Updates: 0 0 74 | Keepalives: 1 1 75 | Route Refresh: 0 0 76 | Discarded: 0 0 77 | Total: 2 2 78 | Route statistics: 79 | Advertised: 0 80 | Received: 0 81 | Accepted: 0 82 | ``` 83 | -------------------------------------------------------------------------------- /test/lib/bagpipe.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | from lib.base import ( 18 | BGPContainer, 19 | CmdBuffer, 20 | yellow, 21 | local, 22 | ) 23 | 24 | 25 | class BagpipeContainer(BGPContainer): 26 | 27 | SHARED_VOLUME = '/root/shared_volume' 28 | 29 | def __init__(self, name, asn, router_id, 30 | ctn_image_name='yoshima/bagpipe-bgp'): 31 | super(BagpipeContainer, self).__init__(name, asn, router_id, 32 | ctn_image_name) 33 | self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME)) 34 | 35 | def run(self): 36 | super(BagpipeContainer, self).run() 37 | cmd = CmdBuffer(' ') 38 | cmd << 'docker exec' 39 | cmd << '{0} cp {1}/bgp.conf'.format(self.name, self.SHARED_VOLUME) 40 | cmd << '/etc/bagpipe-bgp/' 41 | local(str(cmd), capture=True) 42 | cmd = 'docker exec {0} service bagpipe-bgp start'.format(self.name) 43 | local(cmd, capture=True) 44 | 45 | def create_config(self): 46 | c = CmdBuffer() 47 | c << '[BGP]' 48 | if len(self.ip_addrs) > 0: 49 | c << 'local_address={0}'.format(self.ip_addrs[0][1].split('/')[0]) 50 | for info in list(self.peers.values()): 51 | c << 'peers={0}'.format(info['neigh_addr'].split('/')[0]) 52 | c << 'my_as={0}'.format(self.asn) 53 | c << 'enable_rtc=True' 54 | c << '[API]' 55 | c << 'api_host=localhost' 56 | c << 'api_port=8082' 57 | c << '[DATAPLANE_DRIVER_IPVPN]' 58 | c << 'dataplane_driver = DummyDataplaneDriver' 59 | c << '[DATAPLANE_DRIVER_EVPN]' 60 | c << 'dataplane_driver = DummyDataplaneDriver' 61 | 62 | with open('{0}/bgp.conf'.format(self.config_dir), 'w') as f: 63 | print(yellow(str(c))) 64 | f.writelines(str(c)) 65 | 66 | def reload_config(self): 67 | cmd = CmdBuffer(' ') 68 | cmd << 'docker exec' 69 | cmd << '{0} cp {1}/bgp.conf'.format(self.name, self.SHARED_VOLUME) 70 | cmd << '/etc/bagpipe-bgp/' 71 | local(str(cmd), capture=True) 72 | cmd = 'docker exec {0} service bagpipe-bgp restart'.format(self.name) 73 | local(cmd, capture=True) 74 | -------------------------------------------------------------------------------- /docs/sources/mrt.md: -------------------------------------------------------------------------------- 1 | # MRT 2 | 3 | This page explains how to play with GoBGP's MRT feature. 4 | 5 | ## Prerequisites 6 | 7 | Assume you finished [Getting Started](getting-started.md). 8 | 9 | ## Contents 10 | 11 | - [Inject routes from MRT table v2 records](#inject-routes-from-mrt-table-v2-records) 12 | - [Dump updates in MRT BGP4MP format](#dump-updates-in-mrt-bgp4mp-format) 13 | - [Dump the RIB in MRT TABLE_DUMPv2 format](#dump-the-rib-in-mrt-table_dumpv2-format) 14 | 15 | ## Inject routes from MRT table v2 records 16 | 17 | Route injection can be done by 18 | 19 | ```bash 20 | $ gobgp mrt inject global [] 21 | ``` 22 | 23 | ## Dump updates in MRT BGP4MP format 24 | 25 | ### Configuration 26 | 27 | With the following configuration, gobgpd continuously dumps BGP update 28 | messages to `/tmp/updates.dump` file in the BGP4MP format. 29 | 30 | ```toml 31 | [[mrt-dump]] 32 | [mrt-dump.config] 33 | dump-type = "updates" 34 | file-name = "/tmp/updates.dump" 35 | ``` 36 | 37 | Also gobgpd supports log rotation; a new dump file is created 38 | periodically, and the old file is renamed to a different name. With 39 | the following configuration, gobgpd creates a new dump file every 180 40 | seconds such as `/tmp/20160510.1546.dump`. The format of a name can be 41 | specified in golang's 42 | [time](https://golang.org/pkg/time/#pkg-constants) package's format. 43 | 44 | ```toml 45 | [[mrt-dump]] 46 | [mrt-dump.config] 47 | dump-type = "updates" 48 | file-name = "/tmp/log/20060102.1504.dump" 49 | rotation-interval = 180 50 | ``` 51 | 52 | ## Dump the RIB in MRT TABLE_DUMPv2 format 53 | 54 | ### Configuration 55 | 56 | With the following configuration, gobgpd continuously dumps routes in 57 | the global rib to `/tmp/table.dump` file in the TABLE_DUMPv2 format 58 | every 60 seconds. 59 | 60 | ```toml 61 | [[mrt-dump]] 62 | [mrt-dump.config] 63 | dump-type = "table" 64 | file-name = "/tmp/table.dump" 65 | dump-interval = 60 66 | ``` 67 | 68 | With a route server configuration, gobgpd can dump routes in each 69 | peer's RIB. 70 | 71 | ```toml 72 | [[neighbors]] 73 | [neighbors.config] 74 | neighbor-address = "10.0.255.1" 75 | # ...(snip)... 76 | [neighbors.route-server.config] 77 | route-server-client = true 78 | 79 | [[neighbors]] 80 | [neighbors.config] 81 | neighbor-address = "10.0.255.2" 82 | # ...(snip)... 83 | [neighbors.route-server.config] 84 | route-server-client = true 85 | 86 | [[mrt-dump]] 87 | [mrt-dump.config] 88 | dump-type = "table" 89 | file-name = "/tmp/table-1.dump" 90 | table-name = "10.0.255.1" 91 | dump-interval = 60 92 | 93 | [[mrt-dump]] 94 | [mrt-dump.config] 95 | dump-type = "table" 96 | file-name = "/tmp/table-2.dump" 97 | table-name = "10.0.255.2" 98 | dump-interval = 60 99 | ``` 100 | -------------------------------------------------------------------------------- /tools/contrib/centos/README.md: -------------------------------------------------------------------------------- 1 | # GoBGP systemd Integration for CentOS 2 | 3 | The following document describes how to manage `gobgp` with `systemd`. 4 | 5 | Download `gobgp` binaries, unpack them, and put them `/usr/bin/`: 6 | 7 | ```bash 8 | mkdir -p /tmp/gobgp 9 | cd /tmp/gobgp && curl -s -L -O https://github.com/osrg/gobgp/releases/download/v1.31/gobgp_1.31_linux_amd64.tar.gz 10 | tar xvzf gobgp_1.31_linux_amd64.tar.gz 11 | mv gobgp /usr/bin/ 12 | mv gobgpd /usr/bin/ 13 | ``` 14 | 15 | First, create a system account for `gobgp` service: 16 | 17 | ```bash 18 | groupadd --system gobgpd 19 | useradd --system -d /var/lib/gobgpd -s /bin/bash -g gobgpd gobgpd 20 | mkdir -p /var/{lib,run,log}/gobgpd 21 | chown -R gobgpd:gobgpd /var/{lib,run,log}/gobgpd 22 | mkdir -p /etc/gobgpd 23 | chown -R gobgpd:gobgpd /etc/gobgpd 24 | ``` 25 | 26 | Paste the below to create `gobgpd` configuration file. The `router-id` in this 27 | example is the IP address of the interface the default route of the host is 28 | pointing to. 29 | 30 | ```bash 31 | DEFAULT_ROUTE_INTERFACE=$(cat /proc/net/route | cut -f1,2 | grep 00000000 | cut -f1) 32 | DEFAULT_ROUTE_INTERFACE_IPV4=$(ip addr show dev $DEFAULT_ROUTE_INTERFACE | grep "inet " | sed "s/.*inet //" | cut -d"/" -f1) 33 | BGP_AS=65001 34 | BGP_PEER=10.0.255.1 35 | cat << EOF > /etc/gobgpd/gobgpd.conf 36 | [global.config] 37 | as = $BGP_AS 38 | router-id = "$DEFAULT_ROUTE_INTERFACE_IPV4" 39 | 40 | [[neighbors]] 41 | [neighbors.config] 42 | neighbor-address = "$BGP_PEER" 43 | peer-as = $BGP_AS 44 | EOF 45 | ``` 46 | 47 | Next, copy the `systemd` unit file, i.e. `gobgpd.service`, in this directory 48 | to `/usr/lib/systemd/system/`: 49 | 50 | ```bash 51 | cp gobgpd.service /usr/lib/systemd/system/ 52 | ``` 53 | 54 | Next, enable and start the `gobgpd` services: 55 | 56 | ```bash 57 | systemctl enable gobgpd 58 | systemctl start gobgpd 59 | ``` 60 | 61 | If necessary, create an `iptables` rule to allow traffic to `gobgpd` service: 62 | 63 | ```bash 64 | iptables -I INPUT 4 -p tcp -m state --state NEW --dport 179 -j ACCEPT 65 | ``` 66 | 67 | Also, add the following rule into `INPUT` chain in `/etc/sysconfig/iptables`: 68 | 69 | ```plaintext 70 | # BGP 71 | -A INPUT -p tcp -m state --state NEW -m tcp --dport 179 -j ACCEPT 72 | ``` 73 | 74 | Check the status of the services: 75 | 76 | ```bash 77 | systemctl status gobgpd 78 | ``` 79 | 80 | The logs are available via `journald`: 81 | 82 | ```bash 83 | journalctl -u gobgpd.service --since today 84 | journalctl -u gobgpd.service -r 85 | ``` 86 | 87 | A user may interract with GoBGP daemon via `gobgp` tool: 88 | 89 | ```bash 90 | # gobgp global 91 | AS: 65001 92 | Router-ID: 10.0.255.1 93 | Listening Port: 179, Addresses: 0.0.0.0, :: 94 | 95 | # gobgp global rib summary 96 | Table ipv4-unicast 97 | Destination: 0, Path: 0 98 | 99 | # gobgp neighbor 100 | Peer AS Up/Down State |#Received Accepted 101 | 10.0.255.1 65001 never Active | 0 102 | ``` 103 | -------------------------------------------------------------------------------- /pkg/zebra/linktype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=linkType"; DO NOT EDIT. 2 | 3 | package zebra 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[linkTypeUnknown-0] 12 | _ = x[linkTypeEther-1] 13 | _ = x[linkTypeEEther-2] 14 | _ = x[linkTypeAX25-3] 15 | _ = x[linkTypePRONET-4] 16 | _ = x[linkTypeIeee802-5] 17 | _ = x[linkTypeARCNET-6] 18 | _ = x[linkTypeAPPLETLK-7] 19 | _ = x[linkTypeDLCI-8] 20 | _ = x[linkTypeATM-9] 21 | _ = x[linkTypeMetricOM-10] 22 | _ = x[linkTypeIeee1394-11] 23 | _ = x[linkTypeEUI64-12] 24 | _ = x[linkTypeINFINIBAND-13] 25 | _ = x[linkTypeSLIP-14] 26 | _ = x[linkTypeCSLIP-15] 27 | _ = x[linkTypeSLIP6-16] 28 | _ = x[linkTypeCSLIP6-17] 29 | _ = x[linkTypeRSRVD-18] 30 | _ = x[linkTypeADAPT-19] 31 | _ = x[linkTypeROSE-20] 32 | _ = x[linkTypeX25-21] 33 | _ = x[linkTypePPP-22] 34 | _ = x[linkTypeCHDLC-23] 35 | _ = x[linkTypeLAPB-24] 36 | _ = x[linkTypeRAWHDLC-25] 37 | _ = x[linkTypeIPIP-26] 38 | _ = x[linkTypeIPIP6-27] 39 | _ = x[linkTypeFRAD-28] 40 | _ = x[linkTypeSKIP-29] 41 | _ = x[linkTypeLOOPBACK-30] 42 | _ = x[linkTypeLOCALTLK-31] 43 | _ = x[linkTypeFDDI-32] 44 | _ = x[linkTypeSIT-33] 45 | _ = x[linkTypeIPDDP-34] 46 | _ = x[linkTypeIPGRE-35] 47 | _ = x[linkTypeIP6GRE-36] 48 | _ = x[linkTypePIMREG-37] 49 | _ = x[linkTypeHIPPI-38] 50 | _ = x[linkTypeECONET-39] 51 | _ = x[linkTypeIRDA-40] 52 | _ = x[linkTypeFCPP-41] 53 | _ = x[linkTypeFCAL-42] 54 | _ = x[linkTypeFCPL-43] 55 | _ = x[linkTypeFCFABRIC-44] 56 | _ = x[linkTypeIeee802Tr-45] 57 | _ = x[linkTypeIeee80211-46] 58 | _ = x[linkTypeIeee80211RadioTap-47] 59 | _ = x[linkTypeIeee802154-48] 60 | _ = x[linkTypeIeee802154Phy-49] 61 | } 62 | 63 | const _linkType_name = "linkTypeUnknownlinkTypeEtherlinkTypeEEtherlinkTypeAX25linkTypePRONETlinkTypeIeee802linkTypeARCNETlinkTypeAPPLETLKlinkTypeDLCIlinkTypeATMlinkTypeMetricOMlinkTypeIeee1394linkTypeEUI64linkTypeINFINIBANDlinkTypeSLIPlinkTypeCSLIPlinkTypeSLIP6linkTypeCSLIP6linkTypeRSRVDlinkTypeADAPTlinkTypeROSElinkTypeX25linkTypePPPlinkTypeCHDLClinkTypeLAPBlinkTypeRAWHDLClinkTypeIPIPlinkTypeIPIP6linkTypeFRADlinkTypeSKIPlinkTypeLOOPBACKlinkTypeLOCALTLKlinkTypeFDDIlinkTypeSITlinkTypeIPDDPlinkTypeIPGRElinkTypeIP6GRElinkTypePIMREGlinkTypeHIPPIlinkTypeECONETlinkTypeIRDAlinkTypeFCPPlinkTypeFCALlinkTypeFCPLlinkTypeFCFABRIClinkTypeIeee802TrlinkTypeIeee80211linkTypeIeee80211RadioTaplinkTypeIeee802154linkTypeIeee802154Phy" 64 | 65 | var _linkType_index = [...]uint16{0, 15, 28, 42, 54, 68, 83, 97, 113, 125, 136, 152, 168, 181, 199, 211, 224, 237, 251, 264, 277, 289, 300, 311, 324, 336, 351, 363, 376, 388, 400, 416, 432, 444, 455, 468, 481, 495, 509, 522, 536, 548, 560, 572, 584, 600, 617, 634, 659, 677, 698} 66 | 67 | func (i linkType) String() string { 68 | if i >= linkType(len(_linkType_index)-1) { 69 | return "linkType(" + strconv.FormatInt(int64(i), 10) + ")" 70 | } 71 | return _linkType_name[_linkType_index[i]:_linkType_index[i+1]] 72 | } 73 | -------------------------------------------------------------------------------- /pkg/packet/bgp/srbehavior_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=SRBehavior"; DO NOT EDIT. 2 | 3 | package bgp 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[RESERVED-0] 12 | _ = x[END-1] 13 | _ = x[END_WITH_PSP-2] 14 | _ = x[END_WITH_USP-3] 15 | _ = x[END_WITH_PSP_USP-4] 16 | _ = x[ENDX-5] 17 | _ = x[ENDX_WITH_PSP-6] 18 | _ = x[ENDX_WITH_USP-7] 19 | _ = x[ENDX_WITH_PSP_USP-8] 20 | _ = x[ENDT-9] 21 | _ = x[ENDT_WITH_PSP-10] 22 | _ = x[ENDT_WITH_USP-11] 23 | _ = x[ENDT_WITH_PSP_USP-12] 24 | _ = x[END_B6_ENCAPS-14] 25 | _ = x[END_BM-15] 26 | _ = x[END_DX6-16] 27 | _ = x[END_DX4-17] 28 | _ = x[END_DT6-18] 29 | _ = x[END_DT4-19] 30 | _ = x[END_DT46-20] 31 | _ = x[END_DX2-21] 32 | _ = x[END_DX2V-22] 33 | _ = x[END_DT2U-23] 34 | _ = x[END_DT2M-24] 35 | _ = x[END_B6_ENCAPS_Red-27] 36 | _ = x[END_WITH_USD-28] 37 | _ = x[END_WITH_PSP_USD-29] 38 | _ = x[END_WITH_USP_USD-30] 39 | _ = x[END_WITH_PSP_USP_USD-31] 40 | _ = x[ENDX_WITH_USD-32] 41 | _ = x[ENDX_WITH_PSP_USD-33] 42 | _ = x[ENDX_WITH_USP_USD-34] 43 | _ = x[ENDX_WITH_PSP_USP_USD-35] 44 | _ = x[ENDT_WITH_USD-36] 45 | _ = x[ENDT_WITH_PSP_USD-37] 46 | _ = x[ENDT_WITH_USP_USD-38] 47 | _ = x[ENDT_WITH_PSP_USP_USD-39] 48 | _ = x[ENDM_GTP6D-69] 49 | _ = x[ENDM_GTP6DI-70] 50 | _ = x[ENDM_GTP6E-71] 51 | _ = x[ENDM_GTP4E-72] 52 | } 53 | 54 | const ( 55 | _SRBehavior_name_0 = "RESERVEDENDEND_WITH_PSPEND_WITH_USPEND_WITH_PSP_USPENDXENDX_WITH_PSPENDX_WITH_USPENDX_WITH_PSP_USPENDTENDT_WITH_PSPENDT_WITH_USPENDT_WITH_PSP_USP" 56 | _SRBehavior_name_1 = "END_B6_ENCAPSEND_BMEND_DX6END_DX4END_DT6END_DT4END_DT46END_DX2END_DX2VEND_DT2UEND_DT2M" 57 | _SRBehavior_name_2 = "END_B6_ENCAPS_RedEND_WITH_USDEND_WITH_PSP_USDEND_WITH_USP_USDEND_WITH_PSP_USP_USDENDX_WITH_USDENDX_WITH_PSP_USDENDX_WITH_USP_USDENDX_WITH_PSP_USP_USDENDT_WITH_USDENDT_WITH_PSP_USDENDT_WITH_USP_USDENDT_WITH_PSP_USP_USD" 58 | _SRBehavior_name_3 = "ENDM_GTP6DENDM_GTP6DIENDM_GTP6EENDM_GTP4E" 59 | ) 60 | 61 | var ( 62 | _SRBehavior_index_0 = [...]uint8{0, 8, 11, 23, 35, 51, 55, 68, 81, 98, 102, 115, 128, 145} 63 | _SRBehavior_index_1 = [...]uint8{0, 13, 19, 26, 33, 40, 47, 55, 62, 70, 78, 86} 64 | _SRBehavior_index_2 = [...]uint8{0, 17, 29, 45, 61, 81, 94, 111, 128, 149, 162, 179, 196, 217} 65 | _SRBehavior_index_3 = [...]uint8{0, 10, 21, 31, 41} 66 | ) 67 | 68 | func (i SRBehavior) String() string { 69 | switch { 70 | case 0 <= i && i <= 12: 71 | return _SRBehavior_name_0[_SRBehavior_index_0[i]:_SRBehavior_index_0[i+1]] 72 | case 14 <= i && i <= 24: 73 | i -= 14 74 | return _SRBehavior_name_1[_SRBehavior_index_1[i]:_SRBehavior_index_1[i+1]] 75 | case 27 <= i && i <= 39: 76 | i -= 27 77 | return _SRBehavior_name_2[_SRBehavior_index_2[i]:_SRBehavior_index_2[i+1]] 78 | case 69 <= i && i <= 72: 79 | i -= 69 80 | return _SRBehavior_name_3[_SRBehavior_index_3[i]:_SRBehavior_index_3[i+1]] 81 | default: 82 | return "SRBehavior(" + strconv.FormatInt(int64(i), 10) + ")" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt_linux_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build linux 17 | 18 | package netutils 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "syscall" 24 | "testing" 25 | "unsafe" 26 | ) 27 | 28 | func Test_buildTcpMD5Sig(t *testing.T) { 29 | s := buildTcpMD5Sig("1.2.3.4", "hello") 30 | 31 | if unsafe.Sizeof(*s) != 216 { 32 | t.Error("TCPM5Sig struct size is wrong", unsafe.Sizeof(s)) 33 | } 34 | 35 | buf1 := new(bytes.Buffer) 36 | if err := binary.Write(buf1, binary.LittleEndian, s); err != nil { 37 | t.Error(err) 38 | } 39 | 40 | buf2 := []uint8{2, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 41 | 42 | if bytes.Equal(buf1.Bytes(), buf2) { 43 | t.Log("OK") 44 | } else { 45 | t.Error("Something wrong v4") 46 | } 47 | } 48 | 49 | func Test_buildTcpMD5Sigv6(t *testing.T) { 50 | s := buildTcpMD5Sig("fe80::4850:31ff:fe01:fc55", "helloworld") 51 | 52 | buf1 := new(bytes.Buffer) 53 | if err := binary.Write(buf1, binary.LittleEndian, s); err != nil { 54 | t.Error(err) 55 | } 56 | 57 | buf2 := []uint8{10, 0, 0, 0, 0, 0, 0, 0, 254, 128, 0, 0, 0, 0, 0, 0, 72, 80, 49, 255, 254, 1, 252, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 104, 101, 108, 108, 111, 119, 111, 114, 108, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 58 | 59 | buf2[0] = syscall.AF_INET6 60 | 61 | if bytes.Equal(buf1.Bytes(), buf2) { 62 | t.Log("OK") 63 | } else { 64 | t.Error("Something wrong v6") 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/packet/bgp/bgpattrtype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=BGPAttrType"; DO NOT EDIT. 2 | 3 | package bgp 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[BGP_ATTR_TYPE_ORIGIN-1] 12 | _ = x[BGP_ATTR_TYPE_AS_PATH-2] 13 | _ = x[BGP_ATTR_TYPE_NEXT_HOP-3] 14 | _ = x[BGP_ATTR_TYPE_MULTI_EXIT_DISC-4] 15 | _ = x[BGP_ATTR_TYPE_LOCAL_PREF-5] 16 | _ = x[BGP_ATTR_TYPE_ATOMIC_AGGREGATE-6] 17 | _ = x[BGP_ATTR_TYPE_AGGREGATOR-7] 18 | _ = x[BGP_ATTR_TYPE_COMMUNITIES-8] 19 | _ = x[BGP_ATTR_TYPE_ORIGINATOR_ID-9] 20 | _ = x[BGP_ATTR_TYPE_CLUSTER_LIST-10] 21 | _ = x[BGP_ATTR_TYPE_MP_REACH_NLRI-14] 22 | _ = x[BGP_ATTR_TYPE_MP_UNREACH_NLRI-15] 23 | _ = x[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES-16] 24 | _ = x[BGP_ATTR_TYPE_AS4_PATH-17] 25 | _ = x[BGP_ATTR_TYPE_AS4_AGGREGATOR-18] 26 | _ = x[BGP_ATTR_TYPE_PMSI_TUNNEL-22] 27 | _ = x[BGP_ATTR_TYPE_TUNNEL_ENCAP-23] 28 | _ = x[BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES-25] 29 | _ = x[BGP_ATTR_TYPE_AIGP-26] 30 | _ = x[BGP_ATTR_TYPE_LS-29] 31 | _ = x[BGP_ATTR_TYPE_LARGE_COMMUNITY-32] 32 | _ = x[BGP_ATTR_TYPE_PREFIX_SID-40] 33 | } 34 | 35 | const ( 36 | _BGPAttrType_name_0 = "BGP_ATTR_TYPE_ORIGINBGP_ATTR_TYPE_AS_PATHBGP_ATTR_TYPE_NEXT_HOPBGP_ATTR_TYPE_MULTI_EXIT_DISCBGP_ATTR_TYPE_LOCAL_PREFBGP_ATTR_TYPE_ATOMIC_AGGREGATEBGP_ATTR_TYPE_AGGREGATORBGP_ATTR_TYPE_COMMUNITIESBGP_ATTR_TYPE_ORIGINATOR_IDBGP_ATTR_TYPE_CLUSTER_LIST" 37 | _BGPAttrType_name_1 = "BGP_ATTR_TYPE_MP_REACH_NLRIBGP_ATTR_TYPE_MP_UNREACH_NLRIBGP_ATTR_TYPE_EXTENDED_COMMUNITIESBGP_ATTR_TYPE_AS4_PATHBGP_ATTR_TYPE_AS4_AGGREGATOR" 38 | _BGPAttrType_name_2 = "BGP_ATTR_TYPE_PMSI_TUNNELBGP_ATTR_TYPE_TUNNEL_ENCAP" 39 | _BGPAttrType_name_3 = "BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIESBGP_ATTR_TYPE_AIGP" 40 | _BGPAttrType_name_4 = "BGP_ATTR_TYPE_LS" 41 | _BGPAttrType_name_5 = "BGP_ATTR_TYPE_LARGE_COMMUNITY" 42 | _BGPAttrType_name_6 = "BGP_ATTR_TYPE_PREFIX_SID" 43 | ) 44 | 45 | var ( 46 | _BGPAttrType_index_0 = [...]uint8{0, 20, 41, 63, 92, 116, 146, 170, 195, 222, 248} 47 | _BGPAttrType_index_1 = [...]uint8{0, 27, 56, 90, 112, 140} 48 | _BGPAttrType_index_2 = [...]uint8{0, 25, 51} 49 | _BGPAttrType_index_3 = [...]uint8{0, 38, 56} 50 | ) 51 | 52 | func (i BGPAttrType) String() string { 53 | switch { 54 | case 1 <= i && i <= 10: 55 | i -= 1 56 | return _BGPAttrType_name_0[_BGPAttrType_index_0[i]:_BGPAttrType_index_0[i+1]] 57 | case 14 <= i && i <= 18: 58 | i -= 14 59 | return _BGPAttrType_name_1[_BGPAttrType_index_1[i]:_BGPAttrType_index_1[i+1]] 60 | case 22 <= i && i <= 23: 61 | i -= 22 62 | return _BGPAttrType_name_2[_BGPAttrType_index_2[i]:_BGPAttrType_index_2[i+1]] 63 | case 25 <= i && i <= 26: 64 | i -= 25 65 | return _BGPAttrType_name_3[_BGPAttrType_index_3[i]:_BGPAttrType_index_3[i+1]] 66 | case i == 29: 67 | return _BGPAttrType_name_4 68 | case i == 32: 69 | return _BGPAttrType_name_5 70 | case i == 40: 71 | return _BGPAttrType_name_6 72 | default: 73 | return "BGPAttrType(" + strconv.FormatInt(int64(i), 10) + ")" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tools/grpc/cpp/add_path.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "gobgp.grpc.pb.h" 13 | #include "attribute.grpc.pb.h" 14 | 15 | using grpc::Channel; 16 | using grpc::ClientContext; 17 | using grpc::Status; 18 | 19 | using gobgpapi::GobgpApi; 20 | 21 | class GobgpClient 22 | { 23 | public: 24 | GobgpClient(std::shared_ptr channel) 25 | : stub_(GobgpApi::NewStub(channel)) {} 26 | void AddPath() 27 | { 28 | std::cout << "In addRoute \n"; 29 | // Parameters to AddPath API 30 | gobgpapi::AddPathRequest request; 31 | ClientContext context; 32 | gobgpapi::AddPathResponse response; 33 | 34 | // Path info variable 35 | gobgpapi::Path *current_path = new gobgpapi::Path; 36 | 37 | // Updating family info of current_path 38 | gobgpapi::Family *current_family = new gobgpapi::Family; 39 | current_family->set_afi(gobgpapi::Family::AFI_IP); 40 | current_family->set_safi(gobgpapi::Family::SAFI_UNICAST); 41 | current_path->set_allocated_family(current_family); 42 | 43 | // Updating nlri info for current_path 44 | google::protobuf::Any *current_nlri = new google::protobuf::Any; 45 | gobgpapi::IPAddressPrefix current_ipaddrprefix; 46 | current_ipaddrprefix.set_prefix("10.0.0.0"); 47 | current_ipaddrprefix.set_prefix_len(24); 48 | current_nlri->PackFrom(current_ipaddrprefix); 49 | current_path->set_allocated_nlri(current_nlri); 50 | 51 | // Updating OriginAttribute info for current_path 52 | google::protobuf::Any *current_origin = current_path->add_pattrs(); 53 | gobgpapi::OriginAttribute current_origin_t; 54 | current_origin_t.set_origin(0); 55 | current_origin->PackFrom(current_origin_t); 56 | 57 | // Updating NextHopAttribute info for current_path 58 | google::protobuf::Any *current_next_hop = current_path->add_pattrs(); 59 | gobgpapi::NextHopAttribute current_next_hop_t; 60 | current_next_hop_t.set_next_hop("1.1.1.1"); 61 | current_next_hop->PackFrom(current_next_hop_t); 62 | // Updating CommunitiesAttribute for current_path 63 | google::protobuf::Any *current_communities = current_path->add_pattrs(); 64 | gobgpapi::CommunitiesAttribute current_communities_t; 65 | current_communities_t.add_communities(100); 66 | current_communities->PackFrom(current_communities_t); 67 | 68 | // Populating the request attributes 69 | request.set_table_type(gobgpapi::TableType::GLOBAL); 70 | request.set_allocated_path(current_path); 71 | 72 | Status status = stub_->AddPath(&context, request, &response); 73 | if (status.ok()) 74 | { 75 | } 76 | else 77 | { 78 | std::cout << status.error_code() << ": " << status.error_message() 79 | << std::endl; 80 | } 81 | } 82 | 83 | private: 84 | std::unique_ptr stub_; 85 | }; 86 | 87 | int main(int argc, char **argv) 88 | { 89 | GobgpClient client(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); 90 | 91 | client.AddPath(); 92 | } 93 | -------------------------------------------------------------------------------- /docs/sources/dynamic-neighbor.md: -------------------------------------------------------------------------------- 1 | # Dynamic Neighbor 2 | 3 | This page explains how to configure the Dynamic Neighbor features. 4 | Dynamic Neighbor enables GoBGP to accept connections from the peers in specific prefix. 5 | 6 | ## Contents 7 | 8 | - [Prerequisite](#prerequisite) 9 | - [Configuration](#configuration) 10 | - [Verification](#verification) 11 | 12 | ## Prerequisite 13 | 14 | Assumed that you finished [Getting Started](getting-started.md) and learned [Peer Group](peer-group.md). 15 | 16 | ## Configuration 17 | 18 | The Dynamic Neighbor feature requires a peer group setting for its configuration. 19 | 20 | ```toml 21 | [global.config] 22 | as = 65001 23 | router-id = "172.40.1.2" 24 | 25 | [[peer-groups]] 26 | [peer-groups.config] 27 | peer-group-name = "sample-group" 28 | peer-as = 65002 29 | [[peer-groups.afi-safis]] 30 | [peer-groups.afi-safis.config] 31 | afi-safi-name = "ipv4-unicast" 32 | [[peer-groups.afi-safis]] 33 | [peer-groups.afi-safis.config] 34 | afi-safi-name = "ipv4-flowspec" 35 | 36 | [[dynamic-neighbors]] 37 | [dynamic-neighbors.config] 38 | prefix = "172.40.0.0/16" 39 | peer-group = "sample-group" 40 | ``` 41 | 42 | By this configuration, peers in `172.40.0.0/16` will be accepted by this GoBGP, 43 | and the `sample-group` configuration is used as the configuration of members of this dynamic neighbor. 44 | 45 | Note that GoBGP will be passive mode to members of dynamic neighbors. 46 | So if both peers listen to each other as dynamic neighbors, the connection will never be established. 47 | 48 | ## Verification 49 | 50 | Dynamic neighbors are not shown by `gobgp neighbor` command until the connection is established. 51 | 52 | ```shell 53 | $ gobgp neighbor 54 | Peer AS Up/Down State |#Received Accepted 55 | ``` 56 | 57 | After the connection is established, the neighbor will appear by `gobgp neighbor` command. 58 | You can see the neighbor config is inherited from the peer group config. 59 | 60 | ```shell 61 | $ gobgp neighbor 62 | Peer AS Up/Down State |#Received Accepted 63 | 172.40.1.3 65001 00:00:23 Establ | 0 0 64 | $ gobgp neighbor 172.40.1.3 65 | BGP neighbor is 172.40.1.3, remote AS 65002 66 | BGP version 4, remote router ID 172.40.1.3 67 | BGP state = established, up for 00:00:07 68 | BGP OutQ = 0, Flops = 0 69 | Hold time is 90, keepalive interval is 30 seconds 70 | Configured hold time is 90, keepalive interval is 30 seconds 71 | 72 | Neighbor capabilities: 73 | multiprotocol: 74 | ipv4-unicast: advertised and received 75 | ipv4-flowspec: advertised and received 76 | route-refresh: advertised and received 77 | 4-octet-as: advertised and received 78 | Message statistics: 79 | Sent Rcvd 80 | Opens: 1 1 81 | Notifications: 0 0 82 | Updates: 0 0 83 | Keepalives: 1 1 84 | Route Refresh: 0 0 85 | Discarded: 0 0 86 | Total: 2 2 87 | Route statistics: 88 | Advertised: 0 89 | Received: 0 90 | Accepted: 0 91 | ``` 92 | -------------------------------------------------------------------------------- /test/scenario_test/README.md: -------------------------------------------------------------------------------- 1 | # Scenario Test 2 | 3 | This page explains how to set up a scenario test environment and run the test. 4 | 5 | ## Contents 6 | 7 | - [Scenario Test](#scenario-test) 8 | - [Contents](#contents) 9 | - [Prerequisites](#prerequisites) 10 | - [Set up dependencies](#set-up-dependencies) 11 | - [Build GoBGP docker image form your source code](#build-gobgp-docker-image-form-your-source-code) 12 | - [Run tests](#run-tests) 13 | - [Clean up](#clean-up) 14 | 15 | ## Prerequisites 16 | 17 | Go, Docker, and Python3 need to be set up. 18 | 19 | ```shell 20 | $ python --version 21 | Python 3.9.7 22 | 23 | $ go version 24 | go version go1.17 linux/arm64 25 | 26 | $ docker version 27 | Client: 28 | Version: 20.10.7 29 | API version: 1.41 30 | Go version: go1.13.8 31 | Git commit: 20.10.7-0ubuntu5.1 32 | Built: Mon Nov 1 00:34:28 2021 33 | OS/Arch: linux/arm64 34 | Context: default 35 | Experimental: true 36 | 37 | Server: 38 | Engine: 39 | Version: 20.10.7 40 | API version: 1.41 (minimum version 1.12) 41 | Go version: go1.13.8 42 | Git commit: 20.10.7-0ubuntu5.1 43 | Built: Thu Oct 21 23:58:58 2021 44 | OS/Arch: linux/arm64 45 | Experimental: false 46 | containerd: 47 | Version: 1.5.5-0ubuntu3 48 | GitCommit: 49 | runc: 50 | Version: 1.0.1-0ubuntu2 51 | GitCommit: 52 | docker-init: 53 | Version: 0.19.0 54 | GitCommit: 55 | ``` 56 | 57 | ## Set up dependencies 58 | 59 | Execute the following commands to install the dependencies: 60 | 61 | ```shell 62 | $ git clone https://github.com/osrg/gobgp 63 | $ cd ./gobgp 64 | $ python3 -m venv .test 65 | $ source .test/bin/activate 66 | $ pip install -r test/pip-requires.txt 67 | ``` 68 | 69 | ## Build GoBGP docker image form your source code 70 | 71 | You need to build GoBGP docker image to test from the source code that you modified. You need run the following command every time you modify the source code. 72 | 73 | ```shell 74 | $ fab -r ./test/lib make-gobgp-ctn 75 | ``` 76 | 77 | ## Run tests 78 | 79 | There are two ways to run tests 80 | 81 | 1. Run all tests 82 | 83 | You can run all scenario tests with run_all_tests.sh. 84 | If all tests passed, you can see "all tests passed successfully" at the end of the test. 85 | 86 | ```shell 87 | $ ./test/scenario_test/run_all_tests.sh 88 | ... 89 | OK 90 | all tests passed successfully 91 | ``` 92 | 93 | 1. Run each test 94 | 95 | You can run scenario tests individually with each test file. 96 | See `test/scenario_test/*.py`, for the individual test files. 97 | 98 | ```shell 99 | $ PYTHONPATH=./test python3 test/scenario_test/.py --gobgp-image=gobgp 100 | ... 101 | OK 102 | ``` 103 | 104 | ## Clean up 105 | 106 | A lot of containers, networks temporary files are created during the test. 107 | Let's clean up. 108 | 109 | ```shell 110 | $ docker rm -f $(sudo docker ps -a -q -f "label=gobgp-test") 111 | $ docker network prune -f --filter "label=gobgp-test" 112 | $ rm -rf /tmp/gobgp 113 | ``` 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoBGP: BGP implementation in Go 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/osrg/gobgp)](https://goreportcard.com/report/github.com/osrg/gobgp) 4 | [![Tests](https://github.com/osrg/gobgp/actions/workflows/ci.yml/badge.svg)](https://github.com/osrg/gobgp/actions/workflows/ci.yml) 5 | [![Go Reference](https://pkg.go.dev/badge/github.com/osrg/gobgp/v4.svg)](https://pkg.go.dev/github.com/osrg/gobgp/v4) 6 | [![Releases](https://img.shields.io/github/release/osrg/gobgp/all.svg?style=flat-square)](https://github.com/osrg/gobgp/releases) 7 | [![LICENSE](https://img.shields.io/github/license/osrg/gobgp.svg?style=flat-square)](https://github.com/osrg/gobgp/blob/master/LICENSE) 8 | 9 | GoBGP is an open source Border Gateway Protocol (BGP) implementation designed from scratch for 10 | modern environment and implemented in a modern programming language, 11 | [the Go Programming Language](http://golang.org/). 12 | 13 | ---- 14 | 15 | ## Install 16 | 17 | Try [a binary release](https://github.com/osrg/gobgp/releases/latest). 18 | 19 | ## Documentation 20 | 21 | ### Using GoBGP 22 | 23 | - [Getting Started](docs/sources/getting-started.md) 24 | - CLI 25 | - [Typical operation examples](docs/sources/cli-operations.md) 26 | - [Complete syntax](docs/sources/cli-command-syntax.md) 27 | - [Route Server](docs/sources/route-server.md) 28 | - [Route Reflector](docs/sources/route-reflector.md) 29 | - [Policy](docs/sources/policy.md) 30 | - Zebra Integration 31 | - [FIB manipulation](docs/sources/zebra.md) 32 | - [Equal Cost Multipath Routing](docs/sources/zebra-multipath.md) 33 | - [MRT](docs/sources/mrt.md) 34 | - [BMP](docs/sources/bmp.md) 35 | - [EVPN](docs/sources/evpn.md) 36 | - [Flowspec](docs/sources/flowspec.md) 37 | - [RPKI](docs/sources/rpki.md) 38 | - [Metrics](docs/sources/metrics.md) 39 | - [Managing GoBGP with your favorite language with gRPC](docs/sources/grpc-client.md) 40 | - Go Native BGP Library 41 | - [Basics](docs/sources/lib.md) 42 | - [BGP-LS](docs/sources/bgp-ls.md) 43 | - [SR Policy](docs/sources/lib-srpolicy.md) 44 | - [Graceful Restart](docs/sources/graceful-restart.md) 45 | - [Additional Paths](docs/sources/add-paths.md) 46 | - [Peer Group](docs/sources/peer-group.md) 47 | - [Dynamic Neighbor](docs/sources/dynamic-neighbor.md) 48 | - [eBGP Multihop](docs/sources/ebgp-multihop.md) 49 | - [TTL Security](docs/sources/ttl-security.md) 50 | - [Confederation](docs/sources/bgp-confederation.md) 51 | - Data Center Networking 52 | - [Unnumbered BGP](docs/sources/unnumbered-bgp.md) 53 | - [Sentry](docs/sources/sentry.md) 54 | 55 | ### Externals 56 | 57 | - [Tutorial: Using GoBGP as an IXP connecting router](http://www.slideshare.net/shusugimoto1986/tutorial-using-gobgp-as-an-ixp-connecting-router) 58 | 59 | ## Community, discussion and support 60 | 61 | We have the [Slack](https://join.slack.com/t/gobgp/shared_invite/zt-g9il5j8i-3gZwnXArK0O9Mnn4Yu~IrQ) for questions, discussion, suggestions, etc. 62 | 63 | You have code or documentation for GoBGP? Awesome! Send a pull 64 | request. No CLA, board members, governance, or other mess. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for info on 65 | code contributing. 66 | 67 | ## Licensing 68 | 69 | GoBGP is licensed under the Apache License, Version 2.0. See 70 | [LICENSE](https://github.com/osrg/gobgp/blob/master/LICENSE) for the full 71 | license text. 72 | -------------------------------------------------------------------------------- /internal/pkg/netutils/sockopt_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | //go:build windows 17 | 18 | package netutils 19 | 20 | import ( 21 | "fmt" 22 | "log/slog" 23 | "net" 24 | "syscall" 25 | ) 26 | 27 | const ( 28 | tcpMD5SIG = 14 // TCP MD5 Signature (RFC2385) 29 | ipv6MinHopCount = 73 // Generalized TTL Security Mechanism (RFC5082) 30 | IP_MINTTL = 0x15 // pulled from https://golang.org/pkg/syscall/?GOOS=linux#IP_MINTTL 31 | TCP_MAXSEG = 0x2 // pulled from https://pkg.go.dev/syscall?GOOS=linux#TCP_MAXSEG 32 | ) 33 | 34 | func SetTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error { 35 | return fmt.Errorf("setting md5 is not supported") 36 | } 37 | 38 | func SetBindToDevSockopt(sc syscall.RawConn, device string) error { 39 | return fmt.Errorf("binding connection to a device is not supported") 40 | } 41 | 42 | func SetTCPTTLSockopt(conn net.Conn, ttl int) error { 43 | family := extractFamilyFromConn(conn) 44 | sc, err := conn.(syscall.Conn).SyscallConn() 45 | if err != nil { 46 | return err 47 | } 48 | return setSockOptIpTtl(sc, family, ttl) 49 | } 50 | 51 | func SetTCPMinTTLSockopt(conn net.Conn, ttl int) error { 52 | family := extractFamilyFromConn(conn) 53 | sc, err := conn.(syscall.Conn).SyscallConn() 54 | if err != nil { 55 | return err 56 | } 57 | level := syscall.IPPROTO_IP 58 | name := IP_MINTTL 59 | if family == syscall.AF_INET6 { 60 | level = syscall.IPPROTO_IPV6 61 | name = ipv6MinHopCount 62 | } 63 | return setSockOptInt(sc, level, name, ttl) 64 | } 65 | 66 | func SetTCPMSSSockopt(conn net.Conn, mss uint16) error { 67 | // TCP_MAXSEG syscall option exists only from Windows 10 68 | // https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockopt 69 | sc, err := conn.(syscall.Conn).SyscallConn() 70 | if err != nil { 71 | return err 72 | } 73 | level := syscall.IPPROTO_TCP 74 | name := TCP_MAXSEG 75 | return setSockOptInt(sc, level, name, int(mss)) 76 | } 77 | 78 | func DialerControl(logger *slog.Logger, network, address string, c syscall.RawConn, ttl, ttlMin uint8, mss uint16, password string, bindInterface string) error { 79 | if password != "" { 80 | logger.Warn("setting md5 for active connection is not supported", 81 | slog.String("Topic", "Peer"), 82 | slog.String("Key", address)) 83 | } 84 | if ttl != 0 { 85 | logger.Warn("setting ttl for active connection is not supported", 86 | slog.String("Topic", "Peer"), 87 | slog.String("Key", address)) 88 | } 89 | if ttlMin != 0 { 90 | logger.Warn("setting min ttl for active connection is not supported", 91 | slog.String("Topic", "Peer"), 92 | slog.String("Key", address)) 93 | } 94 | if mss != 0 { 95 | logger.Warn("setting MSS for active connection is not supported", 96 | slog.String("Topic", "Peer"), 97 | slog.String("Key", address)) 98 | } 99 | return nil 100 | } 101 | -------------------------------------------------------------------------------- /docs/sources/unnumbered-bgp.md: -------------------------------------------------------------------------------- 1 | # Unnumbered BGP 2 | 3 | BGP is not only for the Internet. Due to proven scalability and configuration 4 | flexibility, large data center operators are using BGP for their data center 5 | networking [[ietf-rtgwg-bgp-routing-large-dc](https://tools.ietf.org/html/rfc7938)]. 6 | 7 | In typical case, the topology of the network is CLOS network which can offer 8 | multiple ECMP for ToR switches. 9 | Each ToR switches run BGP daemon and peer to uplink switches connected with 10 | P2P link. 11 | 12 | In this case, since all switches are operated by single administrator and trusted, 13 | we can skip tedious neighbor configurations like specifying neighbor address or 14 | neighbor AS number by using unnumbered BGP feature. 15 | 16 | Unnumbered BGP utilizes IPv6 link local address to automatically decide who 17 | to connect. Also, when using unnumbered BGP, you don't need to specify neighbor AS number. 18 | GoBGP will accept any AS number in the neighbor's open message. 19 | 20 | ## Prerequisites 21 | 22 | To use unnumbered BGP feature, be sure the link between two BGP daemons is P2P 23 | and IPv6 is enabled on interfaces connected to the link. 24 | 25 | Also, check neighbor's IPv6 link local address is on the linux's neighbor table. 26 | 27 | ```bash 28 | $ ip -6 neigh show 29 | fe80::42:acff:fe11:5 dev eth0 lladdr 02:42:ac:11:00:05 REACHABLE 30 | ``` 31 | 32 | If neighbor's address doesn't exist, easiest way to fill the table is `ping6`. 33 | Try the command below 34 | 35 | ```bash 36 | $ ping6 -c 1 ff02::1%eth0 37 | PING ff02::1%eth0 (ff02::1%eth0): 56 data bytes 38 | 64 bytes from fe80::42:acff:fe11:5%eth0: icmp_seq=0 ttl=64 time=0.312 ms 39 | --- ff02::1%eth0 ping statistics --- 40 | 1 packets transmitted, 1 packets received, 0% packet loss 41 | round-trip min/avg/max/stddev = 0.312/0.312/0.312/0.000 ms 42 | ``` 43 | 44 | More reliable method is to run [radvd](http://www.litech.org/radvd/) or 45 | [zebra](http://www.nongnu.org/quagga/) to periodically send router 46 | advertisement. 47 | 48 | ## Configuration via configuration file 49 | 50 | ```toml 51 | [global.config] 52 | as = 64512 53 | router-id = "192.168.255.1" 54 | 55 | [[neighbors]] 56 | [neighbors.config] 57 | neighbor-interface = "eth0" 58 | ``` 59 | 60 | ## Configuration via CLI 61 | 62 | ```bash 63 | $ gobgp global as 64512 router-id 192.168.255.1 64 | $ gobgp neighbor add interface eth0 65 | $ gobgp neighbor eth0 66 | BGP neighbor is fe80::42:acff:fe11:3%eth0, remote AS 65001 67 | BGP version 4, remote router ID 192.168.0.2 68 | BGP state = BGP_FSM_ESTABLISHED, up for 00:00:07 69 | BGP OutQ = 0, Flops = 0 70 | Hold time is 90, keepalive interval is 30 seconds 71 | Configured hold time is 90, keepalive interval is 30 seconds 72 | Neighbor capabilities: 73 | multi-protocol: 74 | ipv4-unicast: advertised and received 75 | ipv6-unicast: advertised and received 76 | route-refresh: advertised and received 77 | extended-nexthop: advertised and received 78 | Local: nlri: ipv4-unicast, nexthop: ipv6 79 | Remote: nlri: ipv4-unicast, nexthop: ipv6 80 | four-octet-as: advertised and received 81 | Message statistics: 82 | Sent Rcvd 83 | Opens: 1 1 84 | Notifications: 0 0 85 | Updates: 1 0 86 | Keepalives: 1 1 87 | Route Refresh: 0 0 88 | Discarded: 0 0 89 | Total: 3 2 90 | Route statistics: 91 | Advertised: 1 92 | Received: 0 93 | Accepted: 0 94 | ``` 95 | -------------------------------------------------------------------------------- /test/scenario_test/bgp_unnumbered_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import unittest 18 | from lib import base 19 | from lib.base import BGP_FSM_ESTABLISHED, local 20 | from lib.gobgp import GoBGPContainer 21 | import sys 22 | import os 23 | import time 24 | 25 | import collections 26 | collections.Callable = collections.abc.Callable 27 | 28 | import nose 29 | from lib.noseplugin import OptionParser, parser_option 30 | from itertools import combinations 31 | 32 | 33 | class GoBGPTestBase(unittest.TestCase): 34 | 35 | @classmethod 36 | def setUpClass(cls): 37 | gobgp_ctn_image_name = parser_option.gobgp_image 38 | base.TEST_PREFIX = parser_option.test_prefix 39 | 40 | g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 41 | ctn_image_name=gobgp_ctn_image_name, 42 | log_level=parser_option.gobgp_log_level) 43 | g2 = GoBGPContainer(name='g2', asn=65001, router_id='192.168.0.2', 44 | ctn_image_name=gobgp_ctn_image_name, 45 | log_level=parser_option.gobgp_log_level) 46 | ctns = [g1, g2] 47 | 48 | initial_wait_time = max(ctn.run() for ctn in ctns) 49 | 50 | time.sleep(initial_wait_time + 2) 51 | 52 | done = False 53 | 54 | def f(ifname, ctn): 55 | out = ctn.local('ip -6 n', capture=True) 56 | l = [line for line in out.split('\n') if ifname in line] 57 | if len(l) == 0: 58 | return False 59 | elif len(l) > 1: 60 | raise Exception('not p2p link') 61 | return 'REACHABLE' in l[0] 62 | 63 | for i in range(20): 64 | g1.local('ping6 -c 1 ff02::1%eth0') 65 | g2.local('ping6 -c 1 ff02::1%eth0') 66 | if f('eth0', g1) and f('eth0', g2): 67 | done = True 68 | break 69 | time.sleep(1) 70 | 71 | if not done: 72 | raise Exception('timeout') 73 | 74 | for a, b in combinations(ctns, 2): 75 | a.add_peer(b, interface='eth0') 76 | b.add_peer(a, interface='eth0') 77 | 78 | cls.g1 = g1 79 | cls.g2 = g2 80 | 81 | # test each neighbor state is turned establish 82 | def test_01_neighbor_established(self): 83 | self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.g2) 84 | 85 | def test_02_add_ipv4_route(self): 86 | 87 | self.g1.add_route('10.0.0.0/24') 88 | 89 | time.sleep(1) 90 | 91 | rib = self.g2.get_global_rib(rf='ipv4') 92 | self.assertEqual(len(rib), 1) 93 | 94 | 95 | if __name__ == '__main__': 96 | output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 97 | if int(output) != 0: 98 | print("docker not found") 99 | sys.exit(1) 100 | 101 | nose.main(argv=sys.argv, addplugins=[OptionParser()], 102 | defaultTest=sys.argv[0]) 103 | -------------------------------------------------------------------------------- /docs/sources/cli-operations.md: -------------------------------------------------------------------------------- 1 | # CLI Operations 2 | 3 | This page explains comprehensive examples of operations via GoBGP CLI. 4 | 5 | ## Prerequisites 6 | 7 | Assumed that you finished [Getting Started](getting-started.md). 8 | 9 | ## Configuration 10 | 11 | This example starts with the same configuration with 12 | [Getting Started](getting-started.md) 13 | 14 | Make sure that all the peers are connected. 15 | 16 | ```bash 17 | $ gobgp neighbor 18 | Peer AS Up/Down State |#Received Accepted 19 | 10.0.255.1 65001 00:00:04 Establ | 2 2 20 | 10.0.255.2 65002 00:00:04 Establ | 2 2 21 | ``` 22 | 23 | ## Adding or deleting a peer dynamically 24 | 25 | You can add a new peer or delete the existing peer without stopping 26 | GoBGP daemon. You can do such by adding a new peer configuration or 27 | deleting the existing configuration of a peer in your configuration 28 | file and sending `HUP` signal to GoBGP daemon. 29 | 30 | In this example, 10.0.255.3 peer is added. The configuration file 31 | should be like the following. 32 | 33 | ```toml 34 | [global.config] 35 | as = 64512 36 | router-id = "192.168.255.1" 37 | 38 | [[neighbors]] 39 | [neighbors.config] 40 | neighbor-address = "10.0.255.1" 41 | peer-as = 65001 42 | [neighbors.route-server.config] 43 | route-server-client = true 44 | 45 | [[neighbors]] 46 | [neighbors.config] 47 | neighbor-address = "10.0.255.2" 48 | peer-as = 65002 49 | [neighbors.route-server.config] 50 | route-server-client = true 51 | 52 | [[neighbors]] 53 | [neighbors.config] 54 | neighbor-address = "10.0.255.3" 55 | peer-as = 65003 56 | [neighbors.route-server.config] 57 | route-server-client = true 58 | ``` 59 | 60 | After you send `HUP` signal (`kill` command), you should see 10.0.255.3 peer. 61 | 62 | ```bash 63 | $ gobgp neighbor 64 | Peer AS Up/Down State |#Received Accepted 65 | 10.0.255.1 65001 00:03:42 Establ | 2 2 66 | 10.0.255.2 65002 00:03:42 Establ | 2 2 67 | 10.0.255.3 65003 00:01:39 Establ | 1 1 68 | ``` 69 | 70 | ## Temporarily disable a configured peer 71 | 72 | Sometime you might want to disable the configured peer without 73 | removing the configuration for the peer. Likely, again you enable the 74 | peer later. 75 | 76 | ```bash 77 | $ gobgp neighbor 10.0.255.1 disable 78 | $ gobgp neighbor 79 | Peer AS Up/Down State |#Received Accepted 80 | 10.0.255.1 65001 never Idle(Admin) | 0 0 81 | 10.0.255.2 65002 00:12:32 Establ | 2 2 82 | 10.0.255.3 65003 00:10:29 Establ | 1 1 83 | ``` 84 | 85 | The state of 10.0.255.1 is `Idle(Admin)`. Let's enable the peer again. 86 | 87 | ```bash 88 | $ gobgp neighbor 10.0.255.1 enable 89 | $ gobgp neighbor 90 | Peer AS Up/Down State |#Received Accepted 91 | 10.0.255.1 65001 never Idle | 0 0 92 | 10.0.255.2 65002 00:13:33 Establ | 2 2 93 | 10.0.255.3 65003 00:11:30 Establ | 1 1 94 | ``` 95 | 96 | Eventually, the state should be `Established` again. 97 | 98 | ```bash 99 | $ gobgp neighbor 100 | Peer AS Up/Down State |#Received Accepted 101 | 10.0.255.1 65001 00:00:02 Establ | 2 2 102 | 10.0.255.2 65002 00:14:59 Establ | 2 2 103 | 10.0.255.3 65003 00:12:56 Establ | 1 1 104 | ``` 105 | 106 | ## Reset, Reset, and Reset 107 | 108 | Various reset operations are supported. 109 | 110 | ```bash 111 | $ gobgp neighbor 10.0.255.1 reset 112 | $ gobgp neighbor 10.0.255.1 softreset 113 | $ gobgp neighbor 10.0.255.1 softresetin 114 | $ gobgp neighbor 10.0.255.1 softresetout 115 | ``` 116 | 117 | You can know more about [CLI command syntax](cli-command-syntax.md). 118 | -------------------------------------------------------------------------------- /tools/grpc/cpp/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 gRPC authors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | HOST_SYSTEM = $(shell uname | cut -f 1 -d_) 18 | SYSTEM ?= $(HOST_SYSTEM) 19 | CXX = g++ 20 | CPPFLAGS += `pkg-config --cflags protobuf grpc` 21 | CXXFLAGS += -std=c++11 22 | ifeq ($(SYSTEM),Darwin) 23 | LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ 24 | -lgrpc++_reflection\ 25 | -ldl 26 | else 27 | LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ 28 | -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\ 29 | -ldl 30 | endif 31 | PROTOC = protoc 32 | GRPC_CPP_PLUGIN = grpc_cpp_plugin 33 | GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` 34 | 35 | PROTOS_PATH = ../../../api 36 | 37 | vpath %.proto $(PROTOS_PATH) 38 | 39 | #all: system-check greeter_client greeter_server greeter_async_client greeter_async_client2 greeter_async_server 40 | all: add_path 41 | 42 | add_path: gobgp.pb.o gobgp.grpc.pb.o attribute.pb.o attribute.grpc.pb.o capability.pb.o capability.grpc.pb.o add_path.o 43 | $(CXX) $^ $(LDFLAGS) -o $@ 44 | 45 | .PRECIOUS: %.grpc.pb.cc 46 | %.grpc.pb.cc: %.proto 47 | $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< 48 | 49 | .PRECIOUS: %.pb.cc 50 | %.pb.cc: %.proto 51 | $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< 52 | 53 | clean: 54 | rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server greeter_async_client greeter_async_client2 greeter_async_server 55 | 56 | 57 | # The following is to test your system and ensure a smoother experience. 58 | # They are by no means necessary to actually compile a grpc-enabled software. 59 | 60 | PROTOC_CMD = which $(PROTOC) 61 | PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3 62 | PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) 63 | HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) 64 | ifeq ($(HAS_PROTOC),true) 65 | HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) 66 | endif 67 | HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) 68 | 69 | SYSTEM_OK = false 70 | ifeq ($(HAS_VALID_PROTOC),true) 71 | ifeq ($(HAS_PLUGIN),true) 72 | SYSTEM_OK = true 73 | endif 74 | endif 75 | 76 | system-check: 77 | ifneq ($(HAS_VALID_PROTOC),true) 78 | @echo " DEPENDENCY ERROR" 79 | @echo 80 | @echo "You don't have protoc 3.0.0 installed in your path." 81 | @echo "Please install Google protocol buffers 3.0.0 and its compiler." 82 | @echo "You can find it here:" 83 | @echo 84 | @echo " https://github.com/google/protobuf/releases/tag/v3.0.0" 85 | @echo 86 | @echo "Here is what I get when trying to evaluate your version of protoc:" 87 | @echo 88 | -$(PROTOC) --version 89 | @echo 90 | @echo 91 | endif 92 | ifneq ($(HAS_PLUGIN),true) 93 | @echo " DEPENDENCY ERROR" 94 | @echo 95 | @echo "You don't have the grpc c++ protobuf plugin installed in your path." 96 | @echo "Please install grpc. You can find it here:" 97 | @echo 98 | @echo " https://github.com/grpc/grpc" 99 | @echo 100 | @echo "Here is what I get when trying to detect if you have the plugin:" 101 | @echo 102 | -which $(GRPC_CPP_PLUGIN) 103 | @echo 104 | @echo 105 | endif 106 | ifneq ($(SYSTEM_OK),true) 107 | @false 108 | endif 109 | -------------------------------------------------------------------------------- /pkg/config/server_config_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | "net/netip" 7 | "os" 8 | "testing" 9 | 10 | "github.com/osrg/gobgp/v4/api" 11 | "github.com/osrg/gobgp/v4/pkg/config/oc" 12 | "github.com/osrg/gobgp/v4/pkg/server" 13 | "github.com/stretchr/testify/assert" 14 | "github.com/stretchr/testify/require" 15 | ) 16 | 17 | type ErrorCaptureHandler struct { 18 | configErrors []string 19 | baseHandler slog.Handler 20 | } 21 | 22 | func (h *ErrorCaptureHandler) Enabled(_ context.Context, level slog.Level) bool { 23 | return h.baseHandler.Enabled(context.Background(), level) 24 | } 25 | 26 | func (h *ErrorCaptureHandler) Handle(ctx context.Context, record slog.Record) error { 27 | if record.Level >= slog.LevelError { 28 | h.configErrors = append(h.configErrors, record.Message) 29 | } 30 | return h.baseHandler.Handle(ctx, record) 31 | } 32 | 33 | func (h *ErrorCaptureHandler) WithAttrs(attrs []slog.Attr) slog.Handler { 34 | return &ErrorCaptureHandler{ 35 | configErrors: h.configErrors, 36 | baseHandler: h.baseHandler.WithAttrs(attrs), 37 | } 38 | } 39 | 40 | func (h *ErrorCaptureHandler) WithGroup(name string) slog.Handler { 41 | return &ErrorCaptureHandler{ 42 | configErrors: h.configErrors, 43 | baseHandler: h.baseHandler.WithGroup(name), 44 | } 45 | } 46 | 47 | func TestConfigErrors(t *testing.T) { 48 | globalCfg := oc.Global{ 49 | Config: oc.GlobalConfig{ 50 | As: 1, 51 | RouterId: netip.MustParseAddr("1.1.1.1"), 52 | Port: 11179, 53 | }, 54 | } 55 | 56 | for _, tt := range []struct { 57 | name string 58 | expectedErrors []string 59 | cfg *oc.BgpConfigSet 60 | }{ 61 | { 62 | name: "peer with a valid peer-group", 63 | cfg: &oc.BgpConfigSet{ 64 | Global: globalCfg, 65 | Neighbors: []oc.Neighbor{ 66 | { 67 | Config: oc.NeighborConfig{ 68 | PeerGroup: "router", 69 | NeighborAddress: netip.MustParseAddr("1.1.1.2"), 70 | }, 71 | }, 72 | }, 73 | PeerGroups: []oc.PeerGroup{ 74 | { 75 | Config: oc.PeerGroupConfig{ 76 | PeerGroupName: "router", 77 | PeerAs: 2, 78 | }, 79 | }, 80 | }, 81 | }, 82 | }, 83 | { 84 | name: "peer without peer-group", 85 | expectedErrors: []string{"Failed to add Peer"}, 86 | cfg: &oc.BgpConfigSet{ 87 | Global: globalCfg, 88 | Neighbors: []oc.Neighbor{ 89 | { 90 | Config: oc.NeighborConfig{ 91 | PeerGroup: "not-exists", 92 | NeighborAddress: netip.MustParseAddr("1.1.1.2"), 93 | }, 94 | }, 95 | }, 96 | }, 97 | }, 98 | { 99 | name: "policy without a set", 100 | expectedErrors: []string{"failed to create routing policy", "failed to set policies"}, 101 | cfg: &oc.BgpConfigSet{ 102 | Global: globalCfg, 103 | PolicyDefinitions: []oc.PolicyDefinition{ 104 | { 105 | Name: "policy-without-a-set", 106 | Statements: []oc.Statement{ 107 | { 108 | Conditions: oc.Conditions{ 109 | MatchNeighborSet: oc.MatchNeighborSet{ 110 | NeighborSet: "not-existing-neighbor-set", 111 | }, 112 | }, 113 | }, 114 | }, 115 | }, 116 | }, 117 | }, 118 | }, 119 | } { 120 | t.Run(tt.name, func(t *testing.T) { 121 | ctx := context.Background() 122 | basehandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}) 123 | handler := ErrorCaptureHandler{baseHandler: basehandler} 124 | logger := slog.New(&handler) 125 | 126 | bgpServer := server.NewBgpServer(server.LoggerOption(logger, &slog.LevelVar{})) 127 | go bgpServer.Serve() 128 | 129 | _, err := InitialConfig(ctx, bgpServer, tt.cfg, false) 130 | require.NoError(t, err) 131 | err = bgpServer.StopBgp(ctx, &api.StopBgpRequest{}) 132 | require.NoError(t, err) 133 | assert.Equal(t, tt.expectedErrors, handler.configErrors) 134 | }) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /docs/sources/lib.md: -------------------------------------------------------------------------------- 1 | # GoBGP as a Go Native BGP library 2 | 3 | This page explains how to use GoBGP as a Go Native BGP library. 4 | 5 | ## Contents 6 | 7 | - [Basic Example](#basic-example) 8 | 9 | ## Basic Example 10 | 11 | ```go 12 | package main 13 | 14 | import ( 15 | "context" 16 | "log/slog" 17 | "net/netip" 18 | "time" 19 | 20 | "github.com/osrg/gobgp/v4/api" 21 | "github.com/osrg/gobgp/v4/pkg/apiutil" 22 | "github.com/osrg/gobgp/v4/pkg/packet/bgp" 23 | "github.com/osrg/gobgp/v4/pkg/server" 24 | ) 25 | 26 | func main() { 27 | log := slog.Default() 28 | lvl := &slog.LevelVar{} 29 | lvl.Set(slog.LevelInfo) 30 | 31 | s := server.NewBgpServer(server.LoggerOption(log, lvl)) 32 | go s.Serve() 33 | 34 | // global configuration 35 | if err := s.StartBgp(context.Background(), &api.StartBgpRequest{ 36 | Global: &api.Global{ 37 | Asn: 65003, 38 | RouterId: "10.0.255.254", 39 | ListenPort: -1, // gobgp won't listen on tcp:179 40 | }, 41 | }); err != nil { 42 | log.Error("failed to start BGP", slog.String("Error", err.Error())) 43 | } 44 | 45 | // set default import policy 46 | s.SetPolicyAssignment(context.Background(), &api.SetPolicyAssignmentRequest{ 47 | Assignment: &api.PolicyAssignment{ 48 | Direction: api.PolicyDirection_POLICY_DIRECTION_IMPORT, 49 | DefaultAction: api.RouteAction_ROUTE_ACTION_REJECT, 50 | }, 51 | }) 52 | 53 | // monitor the change of the peer state 54 | if err := s.WatchEvent(context.Background(), server.WatchEventMessageCallbacks{ 55 | OnPeerUpdate: func(peer *apiutil.WatchEventMessage_PeerEvent, _ time.Time) { 56 | if peer.Type == apiutil.PEER_EVENT_STATE { 57 | log.Info("peer state changed", slog.Any("Peer", peer.Peer)) 58 | } 59 | }}); err != nil { 60 | log.Error("failed to watch event", slog.String("Error", err.Error())) 61 | } 62 | 63 | // neighbor configuration 64 | n := &api.Peer{ 65 | Conf: &api.PeerConf{ 66 | NeighborAddress: "172.17.0.2", 67 | PeerAsn: 65002, 68 | }, 69 | } 70 | 71 | if err := s.AddPeer(context.Background(), &api.AddPeerRequest{ 72 | Peer: n, 73 | }); err != nil { 74 | log.Error("failed to add peer", slog.String("Error", err.Error())) 75 | } 76 | 77 | // add routes 78 | nlri, _ := bgp.NewIPAddrPrefix(netip.MustParsePrefix("10.0.0.0/24")) 79 | a1 := bgp.NewPathAttributeOrigin(0) 80 | a2, _ := bgp.NewPathAttributeNextHop(netip.MustParseAddr("10.0.0.1")) 81 | a3 := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{6762, 39919, 65000, 35753, 65000})}) 82 | attrs := []bgp.PathAttributeInterface{a1, a2, a3} 83 | 84 | _, err := s.AddPath(apiutil.AddPathRequest{Paths: []*apiutil.Path{{ 85 | Nlri: nlri, 86 | Attrs: attrs, 87 | }}}) 88 | if err != nil { 89 | log.Error("failed to add path", slog.String("Error", err.Error())) 90 | } 91 | 92 | // add v6 route 93 | v6Nlri, _ := bgp.NewIPAddrPrefix(netip.MustParsePrefix("2001:db8:1::/64")) 94 | aMpr, _ := bgp.NewPathAttributeMpReachNLRI(bgp.RF_IPv4_UC, []bgp.PathNLRI{{NLRI: v6Nlri}}, netip.MustParseAddr("2001:db8::1")) 95 | aC := bgp.NewPathAttributeCommunities([]uint32{100, 200}) 96 | attrs = []bgp.PathAttributeInterface{aMpr, aC} 97 | 98 | _, err = s.AddPath(apiutil.AddPathRequest{Paths: []*apiutil.Path{{ 99 | Nlri: v6Nlri, 100 | Attrs: attrs, 101 | }}}) 102 | if err != nil { 103 | log.Error("failed to add v6 path", slog.String("Error", err.Error())) 104 | } 105 | 106 | s.ListPath(apiutil.ListPathRequest{ 107 | TableType: api.TableType_TABLE_TYPE_GLOBAL, 108 | }, func(prefix bgp.NLRI, paths []*apiutil.Path) { 109 | log.Info(prefix.String()) 110 | for _, p := range paths { 111 | log.Info("path", 112 | slog.Uint64("peer_asn", uint64(p.PeerASN)), 113 | slog.String("peer_address", p.PeerAddress.String()), 114 | slog.Uint64("age", uint64(p.Age)), 115 | slog.Bool("best", p.Best), 116 | ) 117 | } 118 | }) 119 | 120 | // do something useful here instead of exiting 121 | time.Sleep(time.Minute * 3) 122 | } 123 | ``` 124 | -------------------------------------------------------------------------------- /proto/api/capability.proto: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation files 5 | // (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, 7 | // publish, distribute, sublicense, and/or sell copies of the Software, 8 | // and to permit persons to whom the Software is furnished to do so, 9 | // subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | syntax = "proto3"; 23 | 24 | package api; 25 | 26 | import "api/common.proto"; 27 | 28 | option go_package = "github.com/osrg/gobgp/v4/api;api"; 29 | 30 | message Capability { 31 | oneof cap { 32 | UnknownCapability unknown = 1; 33 | MultiProtocolCapability multi_protocol = 2; 34 | RouteRefreshCapability route_refresh = 3; 35 | CarryingLabelInfoCapability carrying_label_info = 4; 36 | ExtendedNexthopCapability extended_nexthop = 5; 37 | GracefulRestartCapability graceful_restart = 6; 38 | FourOctetASNCapability four_octet_asn = 7; 39 | AddPathCapability add_path = 8; 40 | EnhancedRouteRefreshCapability enhanced_route_refresh = 9; 41 | LongLivedGracefulRestartCapability long_lived_graceful_restart = 10; 42 | RouteRefreshCiscoCapability route_refresh_cisco = 11; 43 | FqdnCapability fqdn = 12; 44 | SoftwareVersionCapability software_version = 13; 45 | } 46 | } 47 | 48 | message MultiProtocolCapability { 49 | api.Family family = 1; 50 | } 51 | 52 | message RouteRefreshCapability {} 53 | 54 | message CarryingLabelInfoCapability {} 55 | 56 | message ExtendedNexthopCapabilityTuple { 57 | api.Family nlri_family = 1; 58 | // Nexthop AFI must be either 59 | // gobgp.IPv4 or 60 | // gobgp.IPv6. 61 | api.Family nexthop_family = 2; 62 | } 63 | 64 | message ExtendedNexthopCapability { 65 | repeated ExtendedNexthopCapabilityTuple tuples = 1; 66 | } 67 | 68 | message GracefulRestartCapabilityTuple { 69 | api.Family family = 1; 70 | uint32 flags = 2; 71 | } 72 | 73 | message GracefulRestartCapability { 74 | uint32 flags = 1; 75 | uint32 time = 2; 76 | repeated GracefulRestartCapabilityTuple tuples = 3; 77 | } 78 | 79 | message FourOctetASNCapability { 80 | uint32 asn = 1; 81 | } 82 | 83 | message AddPathCapabilityTuple { 84 | api.Family family = 1; 85 | enum Mode { 86 | MODE_UNSPECIFIED = 0; // NONE 87 | MODE_RECEIVE = 1; 88 | MODE_SEND = 2; 89 | MODE_BOTH = 3; 90 | } 91 | Mode mode = 2; 92 | } 93 | 94 | message AddPathCapability { 95 | repeated AddPathCapabilityTuple tuples = 1; 96 | } 97 | 98 | message EnhancedRouteRefreshCapability {} 99 | 100 | message LongLivedGracefulRestartCapabilityTuple { 101 | api.Family family = 1; 102 | uint32 flags = 2; 103 | uint32 time = 3; 104 | } 105 | 106 | message LongLivedGracefulRestartCapability { 107 | repeated LongLivedGracefulRestartCapabilityTuple tuples = 1; 108 | } 109 | 110 | message RouteRefreshCiscoCapability {} 111 | 112 | message FqdnCapability { 113 | string host_name = 1; 114 | string domain_name = 2; 115 | } 116 | 117 | message SoftwareVersionCapability { 118 | string software_version = 1; 119 | } 120 | 121 | message UnknownCapability { 122 | uint32 code = 1; 123 | bytes value = 2; 124 | } 125 | -------------------------------------------------------------------------------- /proto/api/extcom.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package api; 4 | 5 | option go_package = "github.com/osrg/gobgp/v4/api;api"; 6 | 7 | // BGP Extended communities 8 | 9 | message TwoOctetAsSpecificExtended { 10 | bool is_transitive = 1; 11 | uint32 sub_type = 2; 12 | uint32 asn = 3; 13 | uint32 local_admin = 4; 14 | } 15 | 16 | message IPv4AddressSpecificExtended { 17 | bool is_transitive = 1; 18 | uint32 sub_type = 2; 19 | string address = 3; 20 | uint32 local_admin = 4; 21 | } 22 | 23 | message FourOctetAsSpecificExtended { 24 | bool is_transitive = 1; 25 | uint32 sub_type = 2; 26 | uint32 asn = 3; 27 | uint32 local_admin = 4; 28 | } 29 | 30 | message LinkBandwidthExtended { 31 | uint32 asn = 1; 32 | float bandwidth = 2; 33 | } 34 | 35 | message ValidationExtended { 36 | uint32 state = 1; 37 | } 38 | 39 | message ColorExtended { 40 | uint32 color = 1; 41 | } 42 | 43 | message EncapExtended { 44 | uint32 tunnel_type = 1; 45 | } 46 | 47 | message DefaultGatewayExtended {} 48 | 49 | message OpaqueExtended { 50 | bool is_transitive = 1; 51 | bytes value = 3; 52 | } 53 | 54 | message ESILabelExtended { 55 | bool is_single_active = 1; 56 | uint32 label = 2; 57 | } 58 | 59 | message ESImportRouteTarget { 60 | string es_import = 1; 61 | } 62 | 63 | message MacMobilityExtended { 64 | bool is_sticky = 1; 65 | uint32 sequence_num = 2; 66 | } 67 | 68 | message RouterMacExtended { 69 | string mac = 1; 70 | } 71 | 72 | message TrafficRateExtended { 73 | uint32 asn = 1; 74 | float rate = 2; 75 | } 76 | 77 | message TrafficActionExtended { 78 | bool terminal = 1; 79 | bool sample = 2; 80 | } 81 | 82 | message RedirectTwoOctetAsSpecificExtended { 83 | uint32 asn = 1; 84 | uint32 local_admin = 2; 85 | } 86 | 87 | message RedirectIPv4AddressSpecificExtended { 88 | string address = 1; 89 | uint32 local_admin = 2; 90 | } 91 | 92 | message RedirectFourOctetAsSpecificExtended { 93 | uint32 asn = 1; 94 | uint32 local_admin = 2; 95 | } 96 | 97 | message TrafficRemarkExtended { 98 | uint32 dscp = 1; 99 | } 100 | 101 | message MUPExtended { 102 | uint32 sub_type = 1; 103 | uint32 segment_id2 = 2; 104 | uint32 segment_id4 = 3; 105 | } 106 | 107 | message VPLSExtended { 108 | uint32 control_flags = 1; 109 | uint32 mtu = 2; 110 | } 111 | 112 | message ETreeExtended { 113 | bool is_leaf = 1; 114 | uint32 label = 2; 115 | } 116 | 117 | message MulticastFlagsExtended { 118 | bool is_igmp_proxy = 1; 119 | bool is_mld_proxy = 2; 120 | } 121 | 122 | message UnknownExtended { 123 | uint32 type = 1; 124 | bytes value = 2; 125 | } 126 | 127 | message ExtendedCommunity { 128 | oneof extcom { 129 | UnknownExtended unknown = 1; 130 | TwoOctetAsSpecificExtended two_octet_as_specific = 2; 131 | IPv4AddressSpecificExtended ipv4_address_specific = 3; 132 | FourOctetAsSpecificExtended four_octet_as_specific = 4; 133 | LinkBandwidthExtended link_bandwidth = 5; 134 | ValidationExtended validation = 6; 135 | ColorExtended color = 7; 136 | EncapExtended encap = 8; 137 | DefaultGatewayExtended default_gateway = 9; 138 | OpaqueExtended opaque = 10; 139 | ESILabelExtended esi_label = 11; 140 | ESImportRouteTarget es_import = 12; 141 | MacMobilityExtended mac_mobility = 13; 142 | RouterMacExtended router_mac = 14; 143 | TrafficRateExtended traffic_rate = 15; 144 | TrafficActionExtended traffic_action = 16; 145 | RedirectTwoOctetAsSpecificExtended redirect_two_octet_as_specific = 17; 146 | RedirectIPv4AddressSpecificExtended redirect_ipv4_address_specific = 18; 147 | RedirectFourOctetAsSpecificExtended redirect_four_octet_as_specific = 19; 148 | TrafficRemarkExtended traffic_remark = 20; 149 | MUPExtended mup = 21; 150 | VPLSExtended vpls = 22; 151 | ETreeExtended etree = 23; 152 | MulticastFlagsExtended multicast_flags = 24; 153 | } 154 | } 155 | 156 | message RouteTarget { 157 | oneof rt { 158 | TwoOctetAsSpecificExtended two_octet_as_specific = 1; 159 | IPv4AddressSpecificExtended ipv4_address_specific = 2; 160 | FourOctetAsSpecificExtended four_octet_as_specific = 3; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /pkg/config/oc/bgp_configs_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package oc 17 | 18 | import ( 19 | "bufio" 20 | "fmt" 21 | "net/netip" 22 | "os" 23 | "path" 24 | "runtime" 25 | "strings" 26 | "testing" 27 | 28 | "github.com/go-viper/mapstructure/v2" 29 | "github.com/spf13/viper" 30 | "github.com/stretchr/testify/assert" 31 | ) 32 | 33 | func TestEqual(t *testing.T) { 34 | assert := assert.New(t) 35 | p1 := Prefix{ 36 | IpPrefix: netip.MustParsePrefix("192.168.0.0/24"), 37 | MasklengthRange: "24..32", 38 | } 39 | p2 := Prefix{ 40 | IpPrefix: netip.MustParsePrefix("192.168.0.0/24"), 41 | MasklengthRange: "24..32", 42 | } 43 | assert.True(p1.Equal(&p2)) 44 | assert.False(p1.Equal(nil)) 45 | var p3 *Prefix 46 | assert.False(p3.Equal(&p1)) 47 | p3 = &Prefix{ 48 | IpPrefix: netip.MustParsePrefix("192.168.0.0/24"), 49 | MasklengthRange: "24..32", 50 | } 51 | assert.True(p3.Equal(&p1)) 52 | p3.IpPrefix = netip.MustParsePrefix("10.10.0.0/24") 53 | assert.False(p3.Equal(&p1)) 54 | ps1 := PrefixSet{ 55 | PrefixSetName: "ps", 56 | PrefixList: []Prefix{p1, p2}, 57 | } 58 | ps2 := PrefixSet{ 59 | PrefixSetName: "ps", 60 | PrefixList: []Prefix{p2, p1}, 61 | } 62 | assert.True(ps1.Equal(&ps2)) 63 | ps2.PrefixSetName = "ps2" 64 | assert.False(ps1.Equal(&ps2)) 65 | } 66 | 67 | func extractTomlFromMarkdown(fileMd string, fileToml string) error { 68 | fMd, err := os.Open(fileMd) 69 | if err != nil { 70 | return err 71 | } 72 | defer fMd.Close() 73 | 74 | fToml, err := os.Create(fileToml) 75 | if err != nil { 76 | return err 77 | } 78 | defer fToml.Close() 79 | 80 | isBody := false 81 | scanner := bufio.NewScanner(fMd) 82 | fTomlWriter := bufio.NewWriter(fToml) 83 | for scanner.Scan() { 84 | if curText := scanner.Text(); strings.HasPrefix(curText, "```toml") { 85 | isBody = true 86 | } else if strings.HasPrefix(curText, "```") { 87 | isBody = false 88 | } else if isBody { 89 | if _, err := fTomlWriter.WriteString(curText + "\n"); err != nil { 90 | return err 91 | } 92 | } 93 | } 94 | 95 | fTomlWriter.Flush() 96 | return scanner.Err() 97 | } 98 | 99 | func TestConfigExample(t *testing.T) { 100 | assert := assert.New(t) 101 | 102 | _, f, _, _ := runtime.Caller(0) 103 | fileMd := path.Join(path.Dir(f), "../../../docs/sources/configuration.md") 104 | fileToml := "/tmp/gobgpd.example.toml" 105 | assert.NoError(extractTomlFromMarkdown(fileMd, fileToml)) 106 | defer os.Remove(fileToml) 107 | 108 | opts := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(mapstructure.StringToNetIPAddrHookFunc(), mapstructure.StringToNetIPPrefixHookFunc())) 109 | format := detectConfigFileType(fileToml, "") 110 | c := &BgpConfigSet{} 111 | v := viper.New() 112 | v.SetConfigFile(fileToml) 113 | v.SetConfigType(format) 114 | assert.NoError(v.ReadInConfig()) 115 | fmt.Println(v) 116 | assert.NoError(v.UnmarshalExact(c, opts)) 117 | assert.NoError(setDefaultConfigValuesWithViper(v, c)) 118 | 119 | // Test if we can set the parameters for a peer-group 120 | for _, peerGroup := range c.PeerGroups { 121 | if peerGroup.Config.PeerGroupName != "my-peer-group" { 122 | continue 123 | } 124 | 125 | assert.True(peerGroup.Config.SendSoftwareVersion) 126 | } 127 | 128 | // Test if the peer-group inheritance works for neighbors 129 | for _, neighbor := range c.Neighbors { 130 | if neighbor.Config.PeerGroup != "my-peer-group" { 131 | continue 132 | } 133 | 134 | assert.True(neighbor.Config.SendSoftwareVersion) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /test/scenario_test/bgp_malformed_msg_handling_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import sys 18 | import time 19 | import unittest 20 | 21 | import collections 22 | collections.Callable = collections.abc.Callable 23 | 24 | import nose 25 | 26 | from lib.noseplugin import OptionParser, parser_option 27 | 28 | from lib import base 29 | from lib.base import BGP_FSM_ESTABLISHED, local 30 | from lib.gobgp import GoBGPContainer 31 | from lib.exabgp import ExaBGPContainer 32 | 33 | 34 | class GoBGPTestBase(unittest.TestCase): 35 | 36 | @classmethod 37 | def setUpClass(cls): 38 | gobgp_ctn_image_name = parser_option.gobgp_image 39 | base.TEST_PREFIX = parser_option.test_prefix 40 | 41 | g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 42 | ctn_image_name=gobgp_ctn_image_name, 43 | log_level=parser_option.gobgp_log_level) 44 | e1 = ExaBGPContainer(name='e1', asn=65001, router_id='192.168.0.2') 45 | 46 | ctns = [g1, e1] 47 | initial_wait_time = max(ctn.run() for ctn in ctns) 48 | time.sleep(initial_wait_time) 49 | 50 | g1.add_peer(e1, treat_as_withdraw=True) 51 | e1.add_peer(g1) 52 | 53 | cls.g1 = g1 54 | cls.e1 = e1 55 | 56 | # test each neighbor state is turned establish 57 | def test_01_neighbor_established(self): 58 | self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.e1) 59 | 60 | def test_02_attribute_discard(self): 61 | # Malformed attribute 'AGGREGATOR' should be discard, but the session should not be disconnected. 62 | self.e1.add_route('10.0.0.0/24', attribute='0x07 0xc0 0x0000006400') 63 | 64 | # Confirm the session is not disconnected 65 | for _ in range(5): 66 | state = self.g1.get_neighbor_state(self.e1) 67 | self.assertTrue(BGP_FSM_ESTABLISHED, state) 68 | time.sleep(1) 69 | 70 | # Confirm the path is added 71 | dests = self.g1.get_global_rib() 72 | self.assertEqual(len(dests), 1) 73 | routes = dests[0]['paths'] 74 | self.assertEqual(len(routes), 1) 75 | 76 | # Confirm the attribute 'AGGREGATOR(type=7)' is discarded 77 | for d in routes[0]['attrs']: 78 | self.assertFalse(d['type'] == 7) 79 | 80 | self.e1.del_route('10.0.0.0/24') 81 | 82 | def test_03_treat_as_withdraw(self): 83 | # Malformed attribute 'MULTI_EXIT_DESC' should be treated as withdraw, 84 | # but the session should not be disconnected. 85 | self.e1.add_route('20.0.0.0/24', attribute='0x04 0x80 0x00000064') 86 | self.e1.add_route('30.0.0.0/24', attribute='0x04 0x80 0x00000064') 87 | # Malformed 88 | self.e1.add_route('30.0.0.0/24', attribute='0x04 0x80 0x0000000064') 89 | 90 | # Confirm the session is not disconnected 91 | for _ in range(5): 92 | state = self.g1.get_neighbor_state(self.e1) 93 | self.assertTrue(BGP_FSM_ESTABLISHED, state) 94 | time.sleep(1) 95 | 96 | # Confirm the number of path in RIB is only one 97 | dests = self.g1.get_global_rib() 98 | self.assertEqual(len(dests), 1) 99 | self.assertEqual(dests[0]['paths'][0]['nlri']['prefix'], '20.0.0.0/24') 100 | 101 | 102 | if __name__ == '__main__': 103 | output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 104 | if int(output) != 0: 105 | print("docker not found") 106 | sys.exit(1) 107 | 108 | nose.main(argv=sys.argv, addplugins=[OptionParser()], 109 | defaultTest=sys.argv[0]) 110 | -------------------------------------------------------------------------------- /test/scenario_test/route_server_as2_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import unittest 18 | import sys 19 | import time 20 | 21 | import collections 22 | collections.Callable = collections.abc.Callable 23 | 24 | import nose 25 | 26 | from lib.noseplugin import OptionParser, parser_option 27 | 28 | from lib import base 29 | from lib.base import ( 30 | BGP_FSM_IDLE, 31 | BGP_FSM_ESTABLISHED, 32 | local, 33 | ) 34 | from lib.gobgp import GoBGPContainer 35 | from lib.exabgp import ExaBGPContainer 36 | 37 | 38 | class GoBGPTestBase(unittest.TestCase): 39 | 40 | wait_per_retry = 5 41 | retry_limit = 10 42 | 43 | @classmethod 44 | def setUpClass(cls): 45 | gobgp_ctn_image_name = parser_option.gobgp_image 46 | base.TEST_PREFIX = parser_option.test_prefix 47 | 48 | g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 49 | ctn_image_name=gobgp_ctn_image_name, 50 | log_level=parser_option.gobgp_log_level) 51 | 52 | rs_clients = [ 53 | ExaBGPContainer(name='q{0}'.format(i + 1), asn=(65001 + i), 54 | router_id='192.168.0.{0}'.format(i + 2)) 55 | for i in range(4)] 56 | ctns = [g1] + rs_clients 57 | 58 | initial_wait_time = max(ctn.run() for ctn in ctns) 59 | time.sleep(initial_wait_time) 60 | 61 | for i, rs_client in enumerate(rs_clients): 62 | g1.add_peer(rs_client, is_rs_client=True) 63 | as2 = False 64 | if i > 1: 65 | as2 = True 66 | rs_client.add_peer(g1, as2=as2) 67 | 68 | # advertise a route from route-server-clients 69 | for idx, rs_client in enumerate(rs_clients): 70 | route = '10.0.{0}.0/24'.format(idx + 1) 71 | rs_client.add_route(route) 72 | if idx < 2: 73 | route = '10.0.10.0/24' 74 | rs_client.add_route(route) 75 | 76 | cls.gobgp = g1 77 | cls.quaggas = {x.name: x for x in rs_clients} 78 | 79 | # test each neighbor state is turned establish 80 | def test_01_neighbor_established(self): 81 | for q in self.quaggas.values(): 82 | self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q) 83 | 84 | def test_02_check_gobgp_local_rib(self): 85 | for rs_client in self.quaggas.values(): 86 | done = False 87 | for _ in range(self.retry_limit): 88 | if done: 89 | break 90 | 91 | state = self.gobgp.get_neighbor_state(rs_client) 92 | self.assertEqual(state, BGP_FSM_ESTABLISHED) 93 | local_rib = self.gobgp.get_local_rib(rs_client) 94 | if len(local_rib) < (len(self.quaggas) - 1): 95 | time.sleep(self.wait_per_retry) 96 | continue 97 | 98 | self.assertEqual(len(local_rib), 4) 99 | done = True 100 | 101 | if done: 102 | continue 103 | # should not reach here 104 | raise AssertionError 105 | 106 | def test_03_stop_q2_and_check_neighbor_status(self): 107 | q2 = self.quaggas['q2'] 108 | q2.remove() 109 | self.gobgp.wait_for(expected_state=BGP_FSM_IDLE, peer=q2) 110 | 111 | 112 | if __name__ == '__main__': 113 | output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 114 | if int(output) != 0: 115 | print("docker not found") 116 | sys.exit(1) 117 | 118 | nose.main(argv=sys.argv, addplugins=[OptionParser()], 119 | defaultTest=sys.argv[0]) 120 | -------------------------------------------------------------------------------- /test/scenario_test/route_server_test2.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | import sys 18 | import time 19 | import unittest 20 | 21 | import collections 22 | collections.Callable = collections.abc.Callable 23 | 24 | import nose 25 | 26 | from lib.noseplugin import OptionParser, parser_option 27 | 28 | from lib import base 29 | from lib.base import BGP_FSM_ESTABLISHED, local 30 | from lib.gobgp import GoBGPContainer 31 | from lib.exabgp import ExaBGPContainer 32 | 33 | 34 | class GoBGPTestBase(unittest.TestCase): 35 | 36 | wait_per_retry = 5 37 | retry_limit = 15 38 | 39 | @classmethod 40 | def setUpClass(cls): 41 | gobgp_ctn_image_name = parser_option.gobgp_image 42 | base.TEST_PREFIX = parser_option.test_prefix 43 | 44 | g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 45 | ctn_image_name=gobgp_ctn_image_name, 46 | log_level=parser_option.gobgp_log_level) 47 | g2 = GoBGPContainer(name='g2', asn=65001, router_id='192.168.0.2', 48 | ctn_image_name=gobgp_ctn_image_name) 49 | e1 = ExaBGPContainer(name='e1', asn=65002, router_id='192.168.0.3') 50 | 51 | ctns = [g1, g2, e1] 52 | cls.clients = {cli.name: cli for cli in (g2, e1)} 53 | 54 | initial_wait_time = max(ctn.run() for ctn in ctns) 55 | time.sleep(initial_wait_time) 56 | 57 | for cli in list(cls.clients.values()): 58 | # Omit "passwd" to avoid a issue on ExaBGP version 4.0.5: 59 | # https://github.com/Exa-Networks/exabgp/issues/766 60 | g1.add_peer(cli, is_rs_client=True, passive=True, prefix_limit=10) 61 | cli.add_peer(g1) 62 | 63 | # advertise a route from route-server-clients 64 | g2.add_route('10.0.0.0/24') 65 | e1.add_route('10.0.1.0/24') 66 | 67 | cls.gobgp = g1 68 | 69 | # test each neighbor state is turned establish 70 | def test_01_neighbor_established(self): 71 | for cli in list(self.clients.values()): 72 | self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=cli) 73 | 74 | def test_02_add_neighbor(self): 75 | e2 = ExaBGPContainer(name='e2', asn=65001, router_id='192.168.0.4') 76 | time.sleep(e2.run()) 77 | self.gobgp.add_peer(e2, is_rs_client=True) 78 | e2.add_peer(self.gobgp) 79 | 80 | self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=e2) 81 | self.clients[e2.name] = e2 82 | 83 | def test_03_check_neighbor_rib(self): 84 | rib = self.gobgp.get_local_rib(self.clients['e2']) 85 | self.assertEqual(len(rib), 1) 86 | self.assertEqual(len(rib[0]['paths']), 1) 87 | path = rib[0]['paths'][0] 88 | self.assertTrue(65001 not in path['aspath']) 89 | 90 | def test_04_withdraw_path(self): 91 | self.clients['g2'].local('gobgp global rib del 10.0.0.0/24') 92 | time.sleep(1) 93 | afisafis = self.gobgp.get_neighbor(self.clients['g2'])['afi_safis'] 94 | advertised = 0 95 | for afisafi in afisafis: 96 | s = afisafi.get('state') 97 | advertised += s.get('advertised') 98 | self.assertEqual(s.get('accepted'), None) # means info['accepted'] == 0 99 | self.assertEqual(s.get('received'), None) # means info['received'] == 0 100 | 101 | self.assertEqual(advertised, 1) 102 | 103 | 104 | if __name__ == '__main__': 105 | output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 106 | if int(output) != 0: 107 | print("docker not found") 108 | sys.exit(1) 109 | 110 | nose.main(argv=sys.argv, addplugins=[OptionParser()], 111 | defaultTest=sys.argv[0]) 112 | -------------------------------------------------------------------------------- /pkg/packet/rtr/rtr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package rtr 17 | 18 | import ( 19 | "encoding/hex" 20 | "math/rand" 21 | "net/netip" 22 | "testing" 23 | "time" 24 | 25 | "github.com/stretchr/testify/assert" 26 | "github.com/stretchr/testify/require" 27 | ) 28 | 29 | func verifyRTRMessage(t *testing.T, m1 RTRMessage) { 30 | buf1, _ := m1.Serialize() 31 | m2, err := ParseRTR(buf1) 32 | require.NoError(t, err) 33 | 34 | buf2, err := m2.Serialize() 35 | require.NoError(t, err) 36 | 37 | assert.Equal(t, buf1, buf2, "buf1: %v buf2: %v", hex.EncodeToString(buf1), hex.EncodeToString(buf2)) 38 | } 39 | 40 | func randUint32() uint32 { 41 | return rand.Uint32() 42 | } 43 | 44 | func Test_RTRSerialNotify(t *testing.T) { 45 | id := uint16(time.Now().Unix()) 46 | sn := randUint32() 47 | verifyRTRMessage(t, NewRTRSerialNotify(id, sn)) 48 | } 49 | 50 | func Test_RTRSerialQuery(t *testing.T) { 51 | id := uint16(time.Now().Unix()) 52 | sn := randUint32() 53 | verifyRTRMessage(t, NewRTRSerialQuery(id, sn)) 54 | } 55 | 56 | func Test_RTRResetQuery(t *testing.T) { 57 | verifyRTRMessage(t, NewRTRResetQuery()) 58 | } 59 | 60 | func Test_RTRCacheResponse(t *testing.T) { 61 | id := uint16(time.Now().Unix()) 62 | verifyRTRMessage(t, NewRTRCacheResponse(id)) 63 | } 64 | 65 | type rtrIPPrefixTestCase struct { 66 | pString string 67 | pLen uint8 68 | mLen uint8 69 | asn uint32 70 | flags uint8 71 | } 72 | 73 | var rtrIPPrefixTestCases = []rtrIPPrefixTestCase{ 74 | {"192.168.0.0", 16, 32, 65001, ANNOUNCEMENT}, 75 | {"192.168.0.0", 16, 32, 65001, WITHDRAWAL}, 76 | {"2001:db8::", 32, 128, 65001, ANNOUNCEMENT}, 77 | {"2001:db8::", 32, 128, 65001, WITHDRAWAL}, 78 | {"::ffff:0.0.0.0", 96, 128, 65001, ANNOUNCEMENT}, 79 | {"::ffff:0.0.0.0", 96, 128, 65001, WITHDRAWAL}, 80 | } 81 | 82 | func Test_RTRIPPrefix(t *testing.T) { 83 | for i := range rtrIPPrefixTestCases { 84 | test := &rtrIPPrefixTestCases[i] 85 | verifyRTRMessage(t, NewRTRIPPrefix(netip.MustParseAddr(test.pString), test.pLen, test.mLen, test.asn, test.flags)) 86 | } 87 | } 88 | 89 | func Test_RTREndOfData(t *testing.T) { 90 | id := uint16(time.Now().Unix()) 91 | sn := randUint32() 92 | verifyRTRMessage(t, NewRTREndOfData(id, sn)) 93 | } 94 | 95 | func Test_RTRCacheReset(t *testing.T) { 96 | verifyRTRMessage(t, NewRTRCacheReset()) 97 | } 98 | 99 | func Test_RTRErrorReport(t *testing.T) { 100 | errPDU, _ := NewRTRResetQuery().Serialize() 101 | errText1 := []byte("Couldn't send CacheResponce PDU") 102 | errText2 := []byte("Wrong Length of PDU: 10 bytes") 103 | 104 | // See 5.10 ErrorReport in RFC6810 105 | // when it doesn't have both "erroneous PDU" and "Arbitrary Text" 106 | verifyRTRMessage(t, NewRTRErrorReport(NO_DATA_AVAILABLE, nil, nil)) 107 | 108 | // when it has "erroneous PDU" 109 | verifyRTRMessage(t, NewRTRErrorReport(UNSUPPORTED_PROTOCOL_VERSION, errPDU, nil)) 110 | 111 | // when it has "ArbitaryText" 112 | verifyRTRMessage(t, NewRTRErrorReport(INTERNAL_ERROR, nil, errText1)) 113 | 114 | // when it has both "erroneous PDU" and "Arbitrary Text" 115 | verifyRTRMessage(t, NewRTRErrorReport(CORRUPT_DATA, errPDU, errText2)) 116 | } 117 | 118 | //nolint:errcheck 119 | func FuzzParseRTR(f *testing.F) { 120 | f.Fuzz(func(t *testing.T, data []byte) { 121 | ParseRTR(data) 122 | }) 123 | } 124 | 125 | // grep -r DecodeFromBytes pkg/packet/rtr/ | grep -e ":func " | perl -pe 's|func \(.* \*(.*?)\).*|(&\1\{\})\.DecodeFromBytes(data)|g' | awk -F ':' '{print $2}' 126 | // 127 | //nolint:errcheck 128 | func FuzzDecodeFromBytes(f *testing.F) { 129 | f.Fuzz(func(t *testing.T, data []byte) { 130 | (&RTRCommon{}).DecodeFromBytes(data) 131 | (&RTRReset{}).DecodeFromBytes(data) 132 | (&RTRCacheResponse{}).DecodeFromBytes(data) 133 | (&RTRIPPrefix{}).DecodeFromBytes(data) 134 | (&RTRErrorReport{}).DecodeFromBytes(data) 135 | }) 136 | } 137 | -------------------------------------------------------------------------------- /cmd/gobgp/root.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "context" 20 | "net/http" 21 | _ "net/http/pprof" 22 | "strconv" 23 | 24 | "github.com/osrg/gobgp/v4/api" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | var globalOpts struct { 29 | Host string 30 | Port int 31 | Target string 32 | Debug bool 33 | Quiet bool 34 | Json bool 35 | GenCmpl bool 36 | BashCmplFile string 37 | PprofPort int 38 | TLS bool 39 | ClientCertFile string 40 | ClientKeyFile string 41 | CaFile string 42 | } 43 | 44 | var ( 45 | client api.GoBgpServiceClient 46 | ctx context.Context 47 | ) 48 | 49 | func newRootCmd() *cobra.Command { 50 | cobra.EnablePrefixMatching = true 51 | cleanup := func() {} 52 | 53 | rootCmd := &cobra.Command{ 54 | Use: "gobgp", 55 | PersistentPreRun: func(cmd *cobra.Command, args []string) { 56 | if globalOpts.PprofPort > 0 { 57 | go func() { 58 | address := "localhost:" + strconv.Itoa(globalOpts.PprofPort) 59 | if err := http.ListenAndServe(address, nil); err != nil { 60 | exitWithError(err) 61 | } 62 | }() 63 | } 64 | 65 | if !globalOpts.GenCmpl { 66 | conn, err := newConn() 67 | if err != nil { 68 | exitWithError(err) 69 | } 70 | var cancel context.CancelFunc 71 | ctx, cancel = context.WithCancel(context.Background()) 72 | client = api.NewGoBgpServiceClient(conn) 73 | cleanup = func() { 74 | conn.Close() 75 | cancel() 76 | } 77 | } 78 | }, 79 | RunE: func(cmd *cobra.Command, args []string) error { 80 | if globalOpts.GenCmpl { 81 | return cmd.GenBashCompletionFile(globalOpts.BashCmplFile) 82 | } 83 | cmd.HelpFunc()(cmd, args) 84 | return nil 85 | }, 86 | PersistentPostRun: func(cmd *cobra.Command, args []string) { 87 | defer cleanup() 88 | }, 89 | } 90 | 91 | rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host") 92 | rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 50051, "port") 93 | rootCmd.PersistentFlags().StringVarP(&globalOpts.Target, "target", "", "", "alternative to host/port when using UDS. Ex: unix:///var/run/go-bgp.sock if running gobgpd with a UDS socket.") 94 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Json, "json", "j", false, "use json format to output format") 95 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Debug, "debug", "d", false, "use debug") 96 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Quiet, "quiet", "q", false, "use quiet") 97 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.GenCmpl, "gen-cmpl", "c", false, "generate completion file") 98 | rootCmd.PersistentFlags().StringVarP(&globalOpts.BashCmplFile, "bash-cmpl-file", "", "gobgp-completion.bash", "bash cmpl filename") 99 | rootCmd.PersistentFlags().IntVarP(&globalOpts.PprofPort, "pprof-port", "r", 0, "pprof port") 100 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.TLS, "tls", "", false, "connection uses TLS if true, else plain TCP") 101 | rootCmd.PersistentFlags().StringVarP(&globalOpts.ClientCertFile, "tls-client-cert-file", "", "", "Optional file path to TLS client certificate") 102 | rootCmd.PersistentFlags().StringVarP(&globalOpts.ClientKeyFile, "tls-client-key-file", "", "", "Optional file path to TLS client key") 103 | rootCmd.PersistentFlags().StringVarP(&globalOpts.CaFile, "tls-ca-file", "", "", "The file containing the CA root cert file") 104 | 105 | globalCmd := newGlobalCmd() 106 | neighborCmd := newNeighborCmd() 107 | vrfCmd := newVrfCmd() 108 | policyCmd := newPolicyCmd() 109 | monitorCmd := newMonitorCmd() 110 | mrtCmd := newMrtCmd() 111 | rpkiCmd := newRPKICmd() 112 | bmpCmd := newBmpCmd() 113 | logLevelCmd := newLogLevelCmd() 114 | rootCmd.AddCommand(globalCmd, neighborCmd, vrfCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd, bmpCmd, logLevelCmd) 115 | return rootCmd 116 | } 117 | -------------------------------------------------------------------------------- /pkg/config/oc/serve.go: -------------------------------------------------------------------------------- 1 | package oc 2 | 3 | import ( 4 | "log/slog" 5 | 6 | "github.com/fsnotify/fsnotify" 7 | "github.com/go-viper/mapstructure/v2" 8 | "github.com/spf13/viper" 9 | ) 10 | 11 | type BgpConfigSet struct { 12 | Global Global `mapstructure:"global"` 13 | Neighbors []Neighbor `mapstructure:"neighbors"` 14 | PeerGroups []PeerGroup `mapstructure:"peer-groups"` 15 | RpkiServers []RpkiServer `mapstructure:"rpki-servers"` 16 | BmpServers []BmpServer `mapstructure:"bmp-servers"` 17 | Vrfs []Vrf `mapstructure:"vrfs"` 18 | MrtDump []Mrt `mapstructure:"mrt-dump"` 19 | Zebra Zebra `mapstructure:"zebra"` 20 | Collector Collector `mapstructure:"collector"` 21 | DefinedSets DefinedSets `mapstructure:"defined-sets"` 22 | PolicyDefinitions []PolicyDefinition `mapstructure:"policy-definitions"` 23 | DynamicNeighbors []DynamicNeighbor `mapstructure:"dynamic-neighbors"` 24 | } 25 | 26 | func ReadConfigfile(path, format string) (*BgpConfigSet, error) { 27 | // Update config file type, if detectable 28 | format = detectConfigFileType(path, format) 29 | opts := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(mapstructure.StringToNetIPAddrHookFunc(), mapstructure.StringToNetIPPrefixHookFunc())) 30 | 31 | config := &BgpConfigSet{} 32 | v := viper.New() 33 | v.SetConfigFile(path) 34 | v.SetConfigType(format) 35 | var err error 36 | if err = v.ReadInConfig(); err != nil { 37 | return nil, err 38 | } 39 | if err = v.UnmarshalExact(config, opts); err != nil { 40 | return nil, err 41 | } 42 | if err = setDefaultConfigValuesWithViper(v, config); err != nil { 43 | return nil, err 44 | } 45 | return config, nil 46 | } 47 | 48 | func WatchConfigFile(path, format string, callBack func()) { 49 | v := viper.New() 50 | v.SetConfigFile(path) 51 | v.SetConfigType(format) 52 | 53 | v.OnConfigChange(func(e fsnotify.Event) { 54 | callBack() 55 | }) 56 | 57 | v.WatchConfig() 58 | } 59 | 60 | func ConfigSetToRoutingPolicy(c *BgpConfigSet) *RoutingPolicy { 61 | return &RoutingPolicy{ 62 | DefinedSets: c.DefinedSets, 63 | PolicyDefinitions: c.PolicyDefinitions, 64 | } 65 | } 66 | 67 | func UpdatePeerGroupConfig(logger *slog.Logger, curC, newC *BgpConfigSet) ([]PeerGroup, []PeerGroup, []PeerGroup) { 68 | addedPg := []PeerGroup{} 69 | deletedPg := []PeerGroup{} 70 | updatedPg := []PeerGroup{} 71 | 72 | for _, n := range newC.PeerGroups { 73 | if idx := existPeerGroup(n.Config.PeerGroupName, curC.PeerGroups); idx < 0 { 74 | addedPg = append(addedPg, n) 75 | } else if !n.Equal(&curC.PeerGroups[idx]) { 76 | logger.Debug("Current peer-group config", slog.String("Topic", "Config"), slog.Any("Key", n)) 77 | updatedPg = append(updatedPg, n) 78 | } 79 | } 80 | 81 | for _, n := range curC.PeerGroups { 82 | if existPeerGroup(n.Config.PeerGroupName, newC.PeerGroups) < 0 { 83 | deletedPg = append(deletedPg, n) 84 | } 85 | } 86 | return addedPg, deletedPg, updatedPg 87 | } 88 | 89 | func UpdateNeighborConfig(logger *slog.Logger, curC, newC *BgpConfigSet) ([]Neighbor, []Neighbor, []Neighbor) { 90 | added := []Neighbor{} 91 | deleted := []Neighbor{} 92 | updated := []Neighbor{} 93 | 94 | for _, n := range newC.Neighbors { 95 | if idx := inSlice(n, curC.Neighbors); idx < 0 { 96 | added = append(added, n) 97 | } else if !n.Equal(&curC.Neighbors[idx]) { 98 | logger.Debug("Current neighbor config", slog.String("Topic", "Config"), slog.Any("Key", curC.Neighbors[idx])) 99 | logger.Debug("New neighbor config", slog.String("Topic", "Config"), slog.Any("Key", n)) 100 | updated = append(updated, n) 101 | } 102 | } 103 | 104 | for _, n := range curC.Neighbors { 105 | if inSlice(n, newC.Neighbors) < 0 { 106 | deleted = append(deleted, n) 107 | } 108 | } 109 | return added, deleted, updated 110 | } 111 | 112 | func CheckPolicyDifference(logger *slog.Logger, currentPolicy *RoutingPolicy, newPolicy *RoutingPolicy) bool { 113 | logger.Debug("Current policy", slog.String("Topic", "Config"), slog.Any("Key", currentPolicy)) 114 | logger.Debug("New policy", slog.String("Topic", "Config"), slog.Any("Key", newPolicy)) 115 | 116 | var result bool 117 | if currentPolicy == nil && newPolicy == nil { 118 | result = false 119 | } else { 120 | if currentPolicy != nil && newPolicy != nil { 121 | result = !currentPolicy.Equal(newPolicy) 122 | } else { 123 | result = true 124 | } 125 | } 126 | return result 127 | } 128 | -------------------------------------------------------------------------------- /cmd/gobgp/global_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "strings" 20 | "testing" 21 | 22 | "github.com/osrg/gobgp/v4/pkg/apiutil" 23 | "github.com/osrg/gobgp/v4/pkg/packet/bgp" 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | func Test_ParsePath(t *testing.T) { 28 | assert := assert.New(t) 29 | buf := "10.0.0.0/24 rt 100:100 med 10 nexthop 10.0.0.1 aigp metric 10 local-pref 100" 30 | 31 | path, err := parsePath(bgp.RF_IPv4_UC, strings.Split(buf, " ")) 32 | assert.NoError(err) 33 | i := 0 34 | attrs, _ := apiutil.GetNativePathAttributes(path) 35 | for _, a := range attrs { 36 | assert.True(i < int(a.GetType())) 37 | i = int(a.GetType()) 38 | } 39 | } 40 | 41 | func Test_ParseEvpnPath(t *testing.T) { 42 | tests := []struct { 43 | name string 44 | path string 45 | }{ 46 | {"Ethernet Auto-Discovery", "a-d esi LACP aa:bb:cc:dd:ee:ff 100 etag 200 label 300 rd 1.1.1.1:65000 rt 65000:200 encap vxlan esi-label 400 single-active"}, 47 | {"MAC/IP Advertisement", "macadv aa:bb:cc:dd:ee:ff 10.0.0.1 esi AS 65000 100 etag 200 label 300 rd 1.1.1.1:65000 rt 65000:400 encap vxlan default-gateway"}, 48 | {"I-PMSI", "i-pmsi etag 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan pmsi ingress-repl 100 1.1.1.1"}, 49 | {"IP Prefix", "prefix 10.0.0.0/24 172.16.0.1 esi MSTP aa:aa:aa:aa:aa:aa 100 etag 200 label 300 rd 1.1.1.1:65000 rt 65000:200 encap vxlan router-mac bb:bb:bb:bb:bb:bb"}, 50 | {"Multicast", "multicast 10.0.0.1 etag 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan pmsi ingress-repl 100 1.1.1.1"}, 51 | {"Ethernet Segment Identifier", "esi 10.0.0.1 esi MAC aa:bb:cc:dd:ee:ff 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan"}, 52 | } 53 | 54 | for _, tt := range tests { 55 | t.Run(tt.name, func(t *testing.T) { 56 | assert := assert.New(t) 57 | path, err := parsePath(bgp.RF_EVPN, strings.Split(tt.path, " ")) 58 | assert.NoError(err) 59 | i := 0 60 | attrs, _ := apiutil.GetNativePathAttributes(path) 61 | for _, a := range attrs { 62 | assert.True(i < int(a.GetType())) 63 | i = int(a.GetType()) 64 | } 65 | }) 66 | } 67 | } 68 | 69 | func Test_ParseFlowSpecPath(t *testing.T) { 70 | tests := []struct { 71 | name string 72 | rf bgp.Family 73 | path string 74 | expectedErr bool 75 | }{ 76 | {"FlowSpec Redirect OK: All SRv6 Policy parameters specified", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then redirect fd00:1::1:0 color 100 prefix 2001:db8:2:2::/64 locator-node-length 24 function-length 16 behavior END_DT6", false}, 77 | {"FlowSpec Redirect OK: Only color specified", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then redirect fd00:1::1:0 color 100", false}, 78 | {"FlowSpec Redirect OK: No color specified", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then redirect fd00:1::1:0", false}, 79 | {"FlowSpec Redirect NG: Missing 'color' of SR Policy", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then redirect fd00:1::1:0 prefix 2001:db8:2:2::/64 locator-node-length 24 function-length 16 behavior END_DT6", true}, 80 | {"FlowSpec Redirect NG: Missing 'behavior' of SR Policy", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then redirect fd00:1::1:0 color 100 prefix 2001:db8:2:2::/64 locator-node-length 24 function-length 16", true}, 81 | {"FlowSpec Redirect NG: Wrong action", bgp.RF_FS_IPv6_UC, "match destination 2001:db8::/64 then accept color 100 prefix 2001:db8:2:2::/64 locator-node-length 24 function-length 16 behavior END_DT6", true}, 82 | } 83 | for _, tt := range tests { 84 | t.Run(tt.name, func(t *testing.T) { 85 | assert := assert.New(t) 86 | path, err := parsePath(tt.rf, strings.Split(tt.path, " ")) 87 | if tt.expectedErr { 88 | assert.NotNil(err) 89 | } else { 90 | assert.NoError(err) 91 | i := 0 92 | attrs, _ := apiutil.GetNativePathAttributes(path) 93 | for _, a := range attrs { 94 | assert.True(i < int(a.GetType())) 95 | i = int(a.GetType()) 96 | } 97 | } 98 | }) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /test/lib/bird.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | 18 | import time 19 | 20 | from lib.base import ( 21 | BGPContainer, 22 | CmdBuffer, 23 | try_several_times, 24 | wait_for_completion, 25 | yellow, 26 | indent, 27 | local, 28 | ) 29 | 30 | 31 | class BirdContainer(BGPContainer): 32 | 33 | WAIT_FOR_BOOT = 1 34 | SHARED_VOLUME = '/etc/bird' 35 | 36 | def __init__(self, name, asn, router_id, ctn_image_name='osrg/bird'): 37 | super(BirdContainer, self).__init__(name, asn, router_id, 38 | ctn_image_name) 39 | self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME)) 40 | 41 | def _start_bird(self): 42 | c = CmdBuffer() 43 | c << '#!/bin/sh' 44 | c << 'bird' 45 | cmd = 'echo "{0:s}" > {1}/start.sh'.format(c, self.config_dir) 46 | local(cmd) 47 | cmd = 'chmod 755 {0}/start.sh'.format(self.config_dir) 48 | local(cmd) 49 | self.local('{0}/start.sh'.format(self.SHARED_VOLUME)) 50 | 51 | def _wait_for_boot(self): 52 | def _f(): 53 | ret = self.local('birdc show status > /dev/null 2>&1; echo $?', capture=True) 54 | return ret == '0' 55 | 56 | return wait_for_completion(_f) 57 | 58 | def run(self): 59 | super(BirdContainer, self).run() 60 | self.reload_config() 61 | return self.WAIT_FOR_BOOT 62 | 63 | def create_config(self): 64 | c = CmdBuffer() 65 | c << 'router id {0};'.format(self.router_id) 66 | for peer, info in self.peers.items(): 67 | c << 'protocol bgp {' 68 | c << ' local as {0};'.format(self.asn) 69 | n_addr = info['neigh_addr'].split('/')[0] 70 | c << ' neighbor {0} as {1};'.format(n_addr, peer.asn) 71 | c << ' multihop;' 72 | c << '}' 73 | 74 | with open('{0}/bird.conf'.format(self.config_dir), 'w') as f: 75 | print(yellow('[{0}\'s new bird.conf]'.format(self.name))) 76 | print(yellow(indent(str(c)))) 77 | f.writelines(str(c)) 78 | 79 | def reload_config(self): 80 | if len(self.peers) == 0: 81 | return 82 | 83 | def _reload(): 84 | def _is_running(): 85 | ps = self.local('ps', capture=True) 86 | running = False 87 | for line in ps.split('\n')[1:]: 88 | if 'bird' in line: 89 | running = True 90 | return running 91 | 92 | if _is_running(): 93 | self.local('birdc configure') 94 | else: 95 | self._start_bird() 96 | 97 | self._wait_for_boot() 98 | if not _is_running(): 99 | raise RuntimeError() 100 | 101 | try_several_times(_reload) 102 | 103 | 104 | class RawBirdContainer(BirdContainer): 105 | def __init__(self, name, config, ctn_image_name='osrg/bird'): 106 | asn = None 107 | router_id = None 108 | for line in config.split('\n'): 109 | line = line.strip() 110 | if line.startswith('local as'): 111 | asn = int(line[len('local as'):].strip('; ')) 112 | if line.startswith('router id'): 113 | router_id = line[len('router id'):].strip('; ') 114 | if not asn: 115 | raise Exception('asn not in bird config') 116 | if not router_id: 117 | raise Exception('router-id not in bird config') 118 | self.config = config 119 | super(RawBirdContainer, self).__init__(name, asn, router_id, 120 | ctn_image_name) 121 | 122 | def create_config(self): 123 | with open('{0}/bird.conf'.format(self.config_dir), 'w') as f: 124 | print(yellow('[{0}\'s new bird.conf]'.format(self.name))) 125 | print(yellow(indent(self.config))) 126 | f.writelines(self.config) 127 | -------------------------------------------------------------------------------- /tools/config/example_toml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net/netip" 7 | 8 | "github.com/BurntSushi/toml" 9 | "github.com/osrg/gobgp/v4/pkg/config/oc" 10 | ) 11 | 12 | func main() { 13 | b := oc.Bgp{ 14 | Global: oc.Global{ 15 | Config: oc.GlobalConfig{ 16 | As: 12332, 17 | RouterId: netip.MustParseAddr("10.0.0.1"), 18 | }, 19 | }, 20 | Neighbors: []oc.Neighbor{ 21 | { 22 | Config: oc.NeighborConfig{ 23 | PeerAs: 12333, 24 | AuthPassword: "apple", 25 | NeighborAddress: netip.MustParseAddr("192.168.177.33"), 26 | }, 27 | AfiSafis: []oc.AfiSafi{ 28 | { 29 | Config: oc.AfiSafiConfig{ 30 | AfiSafiName: "ipv4-unicast", 31 | }, 32 | }, 33 | { 34 | Config: oc.AfiSafiConfig{ 35 | AfiSafiName: "ipv6-unicast", 36 | }, 37 | }, 38 | }, 39 | ApplyPolicy: oc.ApplyPolicy{ 40 | Config: oc.ApplyPolicyConfig{ 41 | ImportPolicyList: []string{"pd1"}, 42 | DefaultImportPolicy: oc.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE, 43 | }, 44 | }, 45 | }, 46 | 47 | { 48 | Config: oc.NeighborConfig{ 49 | PeerAs: 12334, 50 | AuthPassword: "orange", 51 | NeighborAddress: netip.MustParseAddr("192.168.177.32"), 52 | }, 53 | }, 54 | 55 | { 56 | Config: oc.NeighborConfig{ 57 | PeerAs: 12335, 58 | AuthPassword: "grape", 59 | NeighborAddress: netip.MustParseAddr("192.168.177.34"), 60 | }, 61 | }, 62 | }, 63 | } 64 | 65 | var buffer bytes.Buffer 66 | encoder := toml.NewEncoder(&buffer) 67 | err := encoder.Encode(b) 68 | if err != nil { 69 | panic(err) 70 | } 71 | 72 | err = encoder.Encode(policy()) 73 | if err != nil { 74 | panic(err) 75 | } 76 | fmt.Printf("%v\n", buffer.String()) 77 | } 78 | 79 | func policy() oc.RoutingPolicy { 80 | ps := oc.PrefixSet{ 81 | PrefixSetName: "ps1", 82 | PrefixList: []oc.Prefix{ 83 | { 84 | IpPrefix: netip.MustParsePrefix("10.3.192.0/21"), 85 | MasklengthRange: "21..24", 86 | }, 87 | }, 88 | } 89 | 90 | ns := oc.NeighborSet{ 91 | NeighborSetName: "ns1", 92 | NeighborInfoList: []string{"10.0.0.2"}, 93 | } 94 | 95 | cs := oc.CommunitySet{ 96 | CommunitySetName: "community1", 97 | CommunityList: []string{"65100:10"}, 98 | } 99 | 100 | ecs := oc.ExtCommunitySet{ 101 | ExtCommunitySetName: "ecommunity1", 102 | ExtCommunityList: []string{"RT:65001:200"}, 103 | } 104 | 105 | as := oc.AsPathSet{ 106 | AsPathSetName: "aspath1", 107 | AsPathList: []string{"^65100"}, 108 | } 109 | 110 | bds := oc.BgpDefinedSets{ 111 | CommunitySets: []oc.CommunitySet{cs}, 112 | ExtCommunitySets: []oc.ExtCommunitySet{ecs}, 113 | AsPathSets: []oc.AsPathSet{as}, 114 | } 115 | 116 | ds := oc.DefinedSets{ 117 | PrefixSets: []oc.PrefixSet{ps}, 118 | NeighborSets: []oc.NeighborSet{ns}, 119 | BgpDefinedSets: bds, 120 | } 121 | 122 | al := oc.AsPathLength{ 123 | Operator: "eq", 124 | Value: 2, 125 | } 126 | 127 | s := oc.Statement{ 128 | Name: "statement1", 129 | Conditions: oc.Conditions{ 130 | MatchPrefixSet: oc.MatchPrefixSet{ 131 | PrefixSet: "ps1", 132 | MatchSetOptions: oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY, 133 | }, 134 | 135 | MatchNeighborSet: oc.MatchNeighborSet{ 136 | NeighborSet: "ns1", 137 | MatchSetOptions: oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY, 138 | }, 139 | 140 | BgpConditions: oc.BgpConditions{ 141 | MatchCommunitySet: oc.MatchCommunitySet{ 142 | CommunitySet: "community1", 143 | MatchSetOptions: oc.MATCH_SET_OPTIONS_TYPE_ANY, 144 | }, 145 | 146 | MatchExtCommunitySet: oc.MatchExtCommunitySet{ 147 | ExtCommunitySet: "ecommunity1", 148 | MatchSetOptions: oc.MATCH_SET_OPTIONS_TYPE_ANY, 149 | }, 150 | 151 | MatchAsPathSet: oc.MatchAsPathSet{ 152 | AsPathSet: "aspath1", 153 | MatchSetOptions: oc.MATCH_SET_OPTIONS_TYPE_ANY, 154 | }, 155 | AsPathLength: al, 156 | }, 157 | }, 158 | Actions: oc.Actions{ 159 | RouteDisposition: "reject-route", 160 | BgpActions: oc.BgpActions{ 161 | SetCommunity: oc.SetCommunity{ 162 | SetCommunityMethod: oc.SetCommunityMethod{ 163 | CommunitiesList: []string{"65100:20"}, 164 | }, 165 | Options: "ADD", 166 | }, 167 | SetMed: "-200", 168 | }, 169 | }, 170 | } 171 | 172 | pd := oc.PolicyDefinition{ 173 | Name: "pd1", 174 | Statements: []oc.Statement{s}, 175 | } 176 | 177 | p := oc.RoutingPolicy{ 178 | DefinedSets: ds, 179 | PolicyDefinitions: []oc.PolicyDefinition{pd}, 180 | } 181 | 182 | return p 183 | } 184 | -------------------------------------------------------------------------------- /cmd/gobgp/bmp.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | // implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | "io" 21 | "net" 22 | "strconv" 23 | 24 | "github.com/osrg/gobgp/v4/api" 25 | "github.com/osrg/gobgp/v4/pkg/packet/bmp" 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | func showStations() error { 30 | stream, err := client.ListBmp(ctx, &api.ListBmpRequest{}) 31 | if err != nil { 32 | fmt.Println(err) 33 | return err 34 | } 35 | stations := make([]*api.ListBmpResponse_BmpStation, 0) 36 | for { 37 | rsp, err := stream.Recv() 38 | if err == io.EOF { 39 | break 40 | } else if err != nil { 41 | return err 42 | } 43 | stations = append(stations, rsp.Station) 44 | } 45 | format := "%-23s %-6s %-10s\n" 46 | fmt.Printf(format, "Session", "State", "Uptime") 47 | for _, r := range stations { 48 | s := "Down" 49 | uptime := "Never" 50 | if r.State.Uptime.AsTime().Unix() != 0 { 51 | uptime = fmt.Sprint(formatTimedelta(r.State.Uptime.AsTime())) 52 | if r.State.Uptime.AsTime().After(r.State.Downtime.AsTime()) { 53 | s = "Up" 54 | } else { 55 | uptime = fmt.Sprint(formatTimedelta(r.State.Downtime.AsTime())) 56 | s = "Down" 57 | } 58 | } 59 | fmt.Printf(format, net.JoinHostPort(r.Conf.Address, fmt.Sprintf("%d", r.Conf.Port)), s, uptime) 60 | } 61 | 62 | return nil 63 | } 64 | 65 | func modBmpServer(cmdType string, args []string) error { 66 | if len(args) < 1 { 67 | return fmt.Errorf("usage: gobgp bmp %s [:] [{pre|post|both|local-rib|all}]", cmdType) 68 | } 69 | 70 | var address string 71 | port := uint32(bmp.BMP_DEFAULT_PORT) 72 | if host, p, err := net.SplitHostPort(args[0]); err != nil { 73 | ip := net.ParseIP(args[0]) 74 | if ip == nil { 75 | return nil 76 | } 77 | address = args[0] 78 | } else { 79 | address = host 80 | // Note: BmpServerConfig.Port is uint32 type, but the TCP/UDP port is 81 | // 16-bit length. 82 | pn, _ := strconv.ParseUint(p, 10, 16) 83 | port = uint32(pn) 84 | } 85 | 86 | var err error 87 | switch cmdType { 88 | case cmdAdd: 89 | statisticsTimeout := 0 90 | if bmpOpts.StatisticsTimeout >= 0 && bmpOpts.StatisticsTimeout <= 65535 { 91 | statisticsTimeout = bmpOpts.StatisticsTimeout 92 | } else { 93 | return fmt.Errorf("invalid statistics-timeout value. it must be in the range 0-65535. default value is 0 and means disabled") 94 | } 95 | 96 | policyType := api.AddBmpRequest_MONITORING_POLICY_PRE 97 | if len(args) > 1 { 98 | switch args[1] { 99 | case "pre": 100 | policyType = api.AddBmpRequest_MONITORING_POLICY_PRE 101 | case "post": 102 | policyType = api.AddBmpRequest_MONITORING_POLICY_POST 103 | case "both": 104 | policyType = api.AddBmpRequest_MONITORING_POLICY_BOTH 105 | case "local-rib": 106 | policyType = api.AddBmpRequest_MONITORING_POLICY_LOCAL 107 | case "all": 108 | policyType = api.AddBmpRequest_MONITORING_POLICY_ALL 109 | default: 110 | return fmt.Errorf("invalid bmp policy type. valid type is {pre|post|both|local-rib|all}") 111 | } 112 | } 113 | _, err = client.AddBmp(ctx, &api.AddBmpRequest{ 114 | Address: address, 115 | Port: port, 116 | Policy: policyType, 117 | StatisticsTimeout: int32(statisticsTimeout), 118 | }) 119 | case cmdDel: 120 | _, err = client.DeleteBmp(ctx, &api.DeleteBmpRequest{ 121 | Address: address, 122 | Port: port, 123 | }) 124 | } 125 | return err 126 | } 127 | 128 | func newBmpCmd() *cobra.Command { 129 | bmpCmd := &cobra.Command{ 130 | Use: cmdBMP, 131 | RunE: func(cmd *cobra.Command, args []string) error { 132 | return showStations() 133 | }, 134 | } 135 | 136 | for _, w := range []string{cmdAdd, cmdDel} { 137 | subcmd := &cobra.Command{ 138 | Use: w, 139 | Run: func(cmd *cobra.Command, args []string) { 140 | err := modBmpServer(cmd.Use, args) 141 | if err != nil { 142 | exitWithError(err) 143 | } 144 | }, 145 | } 146 | if w == cmdAdd { 147 | subcmd.PersistentFlags().IntVarP(&bmpOpts.StatisticsTimeout, "statistics-timeout", "s", 0, "Timeout of statistics report") 148 | } 149 | bmpCmd.AddCommand(subcmd) 150 | } 151 | 152 | return bmpCmd 153 | } 154 | --------------------------------------------------------------------------------