Add app source, add vendoring and module support

This commit is contained in:
Mayuresh Gaitonde
2019-10-16 15:57:55 -07:00
parent b49447a374
commit a8fd79c0e1
991 changed files with 505284 additions and 415 deletions

201
vendor/github.com/osrg/gobgp/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2088
vendor/github.com/osrg/gobgp/api/attribute.pb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

505
vendor/github.com/osrg/gobgp/api/attribute.proto generated vendored Normal file
View File

@@ -0,0 +1,505 @@
// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
syntax = "proto3";
import "google/protobuf/any.proto";
import "gobgp.proto";
package gobgpapi;
message OriginAttribute {
uint32 origin = 1;
}
message AsSegment {
uint32 type = 1;
repeated uint32 numbers = 2;
}
message AsPathAttribute {
repeated AsSegment segments = 1;
}
message NextHopAttribute {
string next_hop = 1;
}
message MultiExitDiscAttribute {
uint32 med = 1;
}
message LocalPrefAttribute {
uint32 local_pref = 1;
}
message AtomicAggregateAttribute {
}
message AggregatorAttribute {
uint32 as = 2;
string address = 3;
}
message CommunitiesAttribute {
repeated uint32 communities = 1;
}
message OriginatorIdAttribute {
string id = 1;
}
message ClusterListAttribute {
repeated string ids = 1;
}
// IPAddressPrefix represents the NLRI for:
// - AFI=1, SAFI=1
// - AFI=2, SAFI=1
message IPAddressPrefix {
uint32 prefix_len = 1;
string prefix = 2;
}
// LabeledIPAddressPrefix represents the NLRI for:
// - AFI=1, SAFI=4
// - AFI=2, SAFI=4
message LabeledIPAddressPrefix {
repeated uint32 labels = 1;
uint32 prefix_len = 2;
string prefix = 3;
}
// EncapsulationNLRI represents the NLRI for:
// - AFI=1, SAFI=7
// - AFI=2, SAFI=7
message EncapsulationNLRI {
string address = 1;
}
message RouteDistinguisherTwoOctetAS {
uint32 admin = 1;
uint32 assigned = 2;
}
message RouteDistinguisherIPAddress {
string admin = 1;
uint32 assigned = 2;
}
message RouteDistinguisherFourOctetAS {
uint32 admin = 1;
uint32 assigned = 2;
}
message EthernetSegmentIdentifier {
uint32 type = 1;
bytes value = 2;
}
// EVPNEthernetAutoDiscoveryRoute represents the NLRI for:
// - AFI=25, SAFI=70, RouteType=1
message EVPNEthernetAutoDiscoveryRoute {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
EthernetSegmentIdentifier esi = 2;
uint32 ethernet_tag = 3;
uint32 label = 4;
}
// EVPNMACIPAdvertisementRoute represents the NLRI for:
// - AFI=25, SAFI=70, RouteType=2
message EVPNMACIPAdvertisementRoute {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
EthernetSegmentIdentifier esi = 2;
uint32 ethernet_tag = 3;
string mac_address = 4;
string ip_address = 5;
repeated uint32 labels = 6;
}
// EVPNInclusiveMulticastEthernetTagRoute represents the NLRI for:
// - AFI=25, SAFI=70, RouteType=3
message EVPNInclusiveMulticastEthernetTagRoute {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
uint32 ethernet_tag = 2;
string ip_address = 3;
}
// EVPNEthernetSegmentRoute represents the NLRI for:
// - AFI=25, SAFI=70, RouteType=4
message EVPNEthernetSegmentRoute {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
EthernetSegmentIdentifier esi = 2;
string ip_address = 3;
}
// EVPNIPPrefixRoute represents the NLRI for:
// - AFI=25, SAFI=70, RouteType=5
message EVPNIPPrefixRoute {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
EthernetSegmentIdentifier esi = 2;
uint32 ethernet_tag = 3;
string ip_prefix = 4;
uint32 ip_prefix_len = 5;
string gw_address = 6;
uint32 label = 7;
}
// LabeledVPNIPAddressPrefix represents the NLRI for:
// - AFI=1, SAFI=128
// - AFI=2, SAFI=128
message LabeledVPNIPAddressPrefix {
repeated uint32 labels = 1;
// One of:
// - TwoOctetAsSpecificExtended
// - IPv4AddressSpecificExtended
// - FourOctetAsSpecificExtended
google.protobuf.Any rd = 2;
uint32 prefix_len = 3;
string prefix = 4;
}
// RouteTargetMembershipNLRI represents the NLRI for:
// - AFI=1, SAFI=132
message RouteTargetMembershipNLRI {
uint32 as = 1;
// One of:
// - TwoOctetAsSpecificExtended
// - IPv4AddressSpecificExtended
// - FourOctetAsSpecificExtended
google.protobuf.Any rt = 2;
}
message FlowSpecIPPrefix {
uint32 type = 1;
uint32 prefix_len = 2;
string prefix = 3;
// IPv6 only
uint32 offset = 4;
}
message FlowSpecMAC {
uint32 type = 1;
string address = 2;
}
message FlowSpecComponentItem {
// Operator for Numeric type, Operand for Bitmask type
uint32 op = 1;
uint64 value = 2;
}
message FlowSpecComponent {
uint32 type = 1;
repeated FlowSpecComponentItem items = 2;
}
// FlowSpecNLRI represents the NLRI for:
// - AFI=1, SAFI=133
// - AFI=2, SAFI=133
message FlowSpecNLRI {
// One of:
// - FlowSpecIPPrefix
// - FlowSpecMAC
// - FlowSpecComponent
repeated google.protobuf.Any rules = 1;
}
// VPNFlowSpecNLRI represents the NLRI for:
// - AFI=1, SAFI=134
// - AFI=2, SAFI=134
// - AFI=25, SAFI=134
message VPNFlowSpecNLRI {
// One of:
// - RouteDistinguisherTwoOctetAS
// - RouteDistinguisherIPAddressAS
// - RouteDistinguisherFourOctetAS
google.protobuf.Any rd = 1;
// One of:
// - FlowSpecIPPrefix
// - FlowSpecMAC
// - FlowSpecComponent
repeated google.protobuf.Any rules = 2;
}
// OpaqueNLRI represents the NLRI for:
// - AFI=16397, SAFI=241
message OpaqueNLRI {
bytes key = 1;
bytes value = 2;
}
message MpReachNLRIAttribute {
gobgpapi.Family family = 1;
repeated string next_hops = 2;
// Each NLRI must be one of:
// - IPAddressPrefix
// - LabeledIPAddressPrefix
// - EncapsulationNLRI
// - EVPNEthernetAutoDiscoveryRoute
// - EVPNMACIPAdvertisementRoute
// - EVPNInclusiveMulticastEthernetTagRoute
// - EVPNEthernetSegmentRoute
// - EVPNIPPrefixRoute
// - LabeledVPNIPAddressPrefix
// - RouteTargetMembershipNLRI
// - FlowSpecNLRI
// - VPNFlowSpecNLRI
// - OpaqueNLRI
repeated google.protobuf.Any nlris = 3;
}
message MpUnreachNLRIAttribute {
gobgpapi.Family family = 1;
// The same as NLRI field of MpReachNLRIAttribute
repeated google.protobuf.Any nlris = 3;
}
message TwoOctetAsSpecificExtended {
bool is_transitive = 1;
uint32 sub_type = 2;
uint32 as = 3;
uint32 local_admin = 4;
}
message IPv4AddressSpecificExtended {
bool is_transitive = 1;
uint32 sub_type = 2;
string address = 3;
uint32 local_admin = 4;
}
message FourOctetAsSpecificExtended {
bool is_transitive = 1;
uint32 sub_type = 2;
uint32 as = 3;
uint32 local_admin = 4;
}
message ValidationExtended {
uint32 state = 1;
}
message ColorExtended {
uint32 color = 1;
}
message EncapExtended {
uint32 tunnel_type = 1;
}
message DefaultGatewayExtended {
}
message OpaqueExtended {
bool is_transitive = 1;
bytes value = 3;
}
message ESILabelExtended {
bool is_single_active = 1;
uint32 label = 2;
}
message ESImportRouteTarget {
string es_import = 1;
}
message MacMobilityExtended {
bool is_sticky = 1;
uint32 sequence_num = 2;
}
message RouterMacExtended {
string mac = 1;
}
message TrafficRateExtended {
uint32 as = 1;
float rate = 2;
}
message TrafficActionExtended {
bool terminal = 1;
bool sample = 2;
}
message RedirectTwoOctetAsSpecificExtended {
uint32 as = 1;
uint32 local_admin = 2;
}
message RedirectIPv4AddressSpecificExtended {
string address = 1;
uint32 local_admin = 2;
}
message RedirectFourOctetAsSpecificExtended {
uint32 as = 1;
uint32 local_admin = 2;
}
message TrafficRemarkExtended {
uint32 dscp = 1;
}
message UnknownExtended {
uint32 type = 1;
bytes value = 2;
}
message ExtendedCommunitiesAttribute {
// Each Community must be one of:
// - TwoOctetAsSpecificExtended
// - IPv4AddressSpecificExtended
// - FourOctetAsSpecificExtended
// - OpaqueExtended
// - ESILabelExtended
// - MacMobilityExtended
// - RouterMacExtended
// - TrafficRateExtended
// - TrafficActionExtended
// - RedirectTwoOctetAsSpecificExtended
// - RedirectIPv4AddressSpecificExtended
// - RedirectFourOctetAsSpecificExtended
// - TrafficRemarkExtended
// - UnknownExtended
repeated google.protobuf.Any communities = 1;
}
message As4PathAttribute {
repeated AsSegment segments = 1;
}
message As4AggregatorAttribute {
uint32 as = 2;
string address = 3;
}
message PmsiTunnelAttribute {
uint32 flags = 1;
uint32 type = 2;
uint32 label = 3;
bytes id = 4;
}
message TunnelEncapSubTLVEncapsulation {
uint32 key = 1;
bytes cookie = 2;
}
message TunnelEncapSubTLVProtocol {
uint32 protocol = 1;
}
message TunnelEncapSubTLVColor {
uint32 color = 1;
}
message TunnelEncapSubTLVUnknown {
uint32 type = 1;
bytes value = 2;
}
message TunnelEncapTLV {
uint32 type = 1;
// Each TLV must be one of:
// - TunnelEncapSubTLVEncapsulation
// - TunnelEncapSubTLVProtocol
// - TunnelEncapSubTLVColor
// - TunnelEncapSubTLVUnknown
repeated google.protobuf.Any tlvs = 2;
}
message TunnelEncapAttribute {
repeated TunnelEncapTLV tlvs = 1;
}
message IPv6AddressSpecificExtended {
bool is_transitive = 1;
uint32 sub_type = 2;
string address = 3;
uint32 local_admin = 4;
}
message RedirectIPv6AddressSpecificExtended {
string address = 1;
uint32 local_admin = 2;
}
message IP6ExtendedCommunitiesAttribute {
// Each Community must be one of:
// - IPv6AddressSpecificExtended
// - RedirectIPv6AddressSpecificExtended
repeated google.protobuf.Any communities = 1;
}
message AigpTLVIGPMetric {
uint64 metric = 1;
}
message AigpTLVUnknown {
uint32 type = 1;
bytes value = 2;
}
message AigpAttribute {
// Each TLV must be one of:
// - AigpTLVIGPMetric
// - AigpTLVUnknown
repeated google.protobuf.Any tlvs = 1;
}
message LargeCommunity {
uint32 global_admin = 1;
uint32 local_data1 = 2;
uint32 local_data2 = 3;
}
message LargeCommunitiesAttribute {
repeated LargeCommunity communities = 1;
}
message UnknownAttribute {
uint32 flags = 1;
uint32 type = 2;
bytes value = 3;
}

380
vendor/github.com/osrg/gobgp/api/capability.pb.go generated vendored Normal file
View File

@@ -0,0 +1,380 @@
// Code generated by protoc-gen-go.
// source: capability.proto
// DO NOT EDIT!
package gobgpapi
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type AddPathMode int32
const (
AddPathMode_MODE_NONE AddPathMode = 0
AddPathMode_MODE_RECEIVE AddPathMode = 1
AddPathMode_MODE_SEND AddPathMode = 2
AddPathMode_MODE_BOTH AddPathMode = 3
)
var AddPathMode_name = map[int32]string{
0: "MODE_NONE",
1: "MODE_RECEIVE",
2: "MODE_SEND",
3: "MODE_BOTH",
}
var AddPathMode_value = map[string]int32{
"MODE_NONE": 0,
"MODE_RECEIVE": 1,
"MODE_SEND": 2,
"MODE_BOTH": 3,
}
func (x AddPathMode) String() string {
return proto.EnumName(AddPathMode_name, int32(x))
}
func (AddPathMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
type MultiProtocolCapability struct {
Family *Family `protobuf:"bytes,1,opt,name=family" json:"family,omitempty"`
}
func (m *MultiProtocolCapability) Reset() { *m = MultiProtocolCapability{} }
func (m *MultiProtocolCapability) String() string { return proto.CompactTextString(m) }
func (*MultiProtocolCapability) ProtoMessage() {}
func (*MultiProtocolCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (m *MultiProtocolCapability) GetFamily() *Family {
if m != nil {
return m.Family
}
return nil
}
type RouteRefreshCapability struct {
}
func (m *RouteRefreshCapability) Reset() { *m = RouteRefreshCapability{} }
func (m *RouteRefreshCapability) String() string { return proto.CompactTextString(m) }
func (*RouteRefreshCapability) ProtoMessage() {}
func (*RouteRefreshCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} }
type CarryingLabelInfoCapability struct {
}
func (m *CarryingLabelInfoCapability) Reset() { *m = CarryingLabelInfoCapability{} }
func (m *CarryingLabelInfoCapability) String() string { return proto.CompactTextString(m) }
func (*CarryingLabelInfoCapability) ProtoMessage() {}
func (*CarryingLabelInfoCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{2} }
type ExtendedNexthopCapabilityTuple struct {
NlriFamily *Family `protobuf:"bytes,1,opt,name=nlri_family,json=nlriFamily" json:"nlri_family,omitempty"`
// Nexthop AFI must be either
// gobgp.IPv4 or
// gobgp.IPv6.
NexthopFamily *Family `protobuf:"bytes,2,opt,name=nexthop_family,json=nexthopFamily" json:"nexthop_family,omitempty"`
}
func (m *ExtendedNexthopCapabilityTuple) Reset() { *m = ExtendedNexthopCapabilityTuple{} }
func (m *ExtendedNexthopCapabilityTuple) String() string { return proto.CompactTextString(m) }
func (*ExtendedNexthopCapabilityTuple) ProtoMessage() {}
func (*ExtendedNexthopCapabilityTuple) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{3} }
func (m *ExtendedNexthopCapabilityTuple) GetNlriFamily() *Family {
if m != nil {
return m.NlriFamily
}
return nil
}
func (m *ExtendedNexthopCapabilityTuple) GetNexthopFamily() *Family {
if m != nil {
return m.NexthopFamily
}
return nil
}
type ExtendedNexthopCapability struct {
Tuples []*ExtendedNexthopCapabilityTuple `protobuf:"bytes,1,rep,name=tuples" json:"tuples,omitempty"`
}
func (m *ExtendedNexthopCapability) Reset() { *m = ExtendedNexthopCapability{} }
func (m *ExtendedNexthopCapability) String() string { return proto.CompactTextString(m) }
func (*ExtendedNexthopCapability) ProtoMessage() {}
func (*ExtendedNexthopCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{4} }
func (m *ExtendedNexthopCapability) GetTuples() []*ExtendedNexthopCapabilityTuple {
if m != nil {
return m.Tuples
}
return nil
}
type GracefulRestartCapabilityTuple struct {
Family *Family `protobuf:"bytes,1,opt,name=family" json:"family,omitempty"`
Flags uint32 `protobuf:"varint,2,opt,name=flags" json:"flags,omitempty"`
}
func (m *GracefulRestartCapabilityTuple) Reset() { *m = GracefulRestartCapabilityTuple{} }
func (m *GracefulRestartCapabilityTuple) String() string { return proto.CompactTextString(m) }
func (*GracefulRestartCapabilityTuple) ProtoMessage() {}
func (*GracefulRestartCapabilityTuple) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{5} }
func (m *GracefulRestartCapabilityTuple) GetFamily() *Family {
if m != nil {
return m.Family
}
return nil
}
func (m *GracefulRestartCapabilityTuple) GetFlags() uint32 {
if m != nil {
return m.Flags
}
return 0
}
type GracefulRestartCapability struct {
Flags uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"`
Time uint32 `protobuf:"varint,2,opt,name=time" json:"time,omitempty"`
Tuples []*GracefulRestartCapabilityTuple `protobuf:"bytes,3,rep,name=tuples" json:"tuples,omitempty"`
}
func (m *GracefulRestartCapability) Reset() { *m = GracefulRestartCapability{} }
func (m *GracefulRestartCapability) String() string { return proto.CompactTextString(m) }
func (*GracefulRestartCapability) ProtoMessage() {}
func (*GracefulRestartCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{6} }
func (m *GracefulRestartCapability) GetFlags() uint32 {
if m != nil {
return m.Flags
}
return 0
}
func (m *GracefulRestartCapability) GetTime() uint32 {
if m != nil {
return m.Time
}
return 0
}
func (m *GracefulRestartCapability) GetTuples() []*GracefulRestartCapabilityTuple {
if m != nil {
return m.Tuples
}
return nil
}
type FourOctetASNumberCapability struct {
As uint32 `protobuf:"varint,1,opt,name=as" json:"as,omitempty"`
}
func (m *FourOctetASNumberCapability) Reset() { *m = FourOctetASNumberCapability{} }
func (m *FourOctetASNumberCapability) String() string { return proto.CompactTextString(m) }
func (*FourOctetASNumberCapability) ProtoMessage() {}
func (*FourOctetASNumberCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{7} }
func (m *FourOctetASNumberCapability) GetAs() uint32 {
if m != nil {
return m.As
}
return 0
}
type AddPathCapabilityTuple struct {
Family *Family `protobuf:"bytes,1,opt,name=family" json:"family,omitempty"`
Mode AddPathMode `protobuf:"varint,2,opt,name=mode,enum=gobgpapi.AddPathMode" json:"mode,omitempty"`
}
func (m *AddPathCapabilityTuple) Reset() { *m = AddPathCapabilityTuple{} }
func (m *AddPathCapabilityTuple) String() string { return proto.CompactTextString(m) }
func (*AddPathCapabilityTuple) ProtoMessage() {}
func (*AddPathCapabilityTuple) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{8} }
func (m *AddPathCapabilityTuple) GetFamily() *Family {
if m != nil {
return m.Family
}
return nil
}
func (m *AddPathCapabilityTuple) GetMode() AddPathMode {
if m != nil {
return m.Mode
}
return AddPathMode_MODE_NONE
}
type AddPathCapability struct {
Tuples []*AddPathCapabilityTuple `protobuf:"bytes,1,rep,name=tuples" json:"tuples,omitempty"`
}
func (m *AddPathCapability) Reset() { *m = AddPathCapability{} }
func (m *AddPathCapability) String() string { return proto.CompactTextString(m) }
func (*AddPathCapability) ProtoMessage() {}
func (*AddPathCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{9} }
func (m *AddPathCapability) GetTuples() []*AddPathCapabilityTuple {
if m != nil {
return m.Tuples
}
return nil
}
type EnhancedRouteRefreshCapability struct {
}
func (m *EnhancedRouteRefreshCapability) Reset() { *m = EnhancedRouteRefreshCapability{} }
func (m *EnhancedRouteRefreshCapability) String() string { return proto.CompactTextString(m) }
func (*EnhancedRouteRefreshCapability) ProtoMessage() {}
func (*EnhancedRouteRefreshCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{10} }
type LongLivedGracefulRestartCapabilityTuple struct {
Family *Family `protobuf:"bytes,1,opt,name=family" json:"family,omitempty"`
Flags uint32 `protobuf:"varint,2,opt,name=flags" json:"flags,omitempty"`
Time uint32 `protobuf:"varint,3,opt,name=time" json:"time,omitempty"`
}
func (m *LongLivedGracefulRestartCapabilityTuple) Reset() {
*m = LongLivedGracefulRestartCapabilityTuple{}
}
func (m *LongLivedGracefulRestartCapabilityTuple) String() string { return proto.CompactTextString(m) }
func (*LongLivedGracefulRestartCapabilityTuple) ProtoMessage() {}
func (*LongLivedGracefulRestartCapabilityTuple) Descriptor() ([]byte, []int) {
return fileDescriptor2, []int{11}
}
func (m *LongLivedGracefulRestartCapabilityTuple) GetFamily() *Family {
if m != nil {
return m.Family
}
return nil
}
func (m *LongLivedGracefulRestartCapabilityTuple) GetFlags() uint32 {
if m != nil {
return m.Flags
}
return 0
}
func (m *LongLivedGracefulRestartCapabilityTuple) GetTime() uint32 {
if m != nil {
return m.Time
}
return 0
}
type LongLivedGracefulRestartCapability struct {
Tuples []*LongLivedGracefulRestartCapabilityTuple `protobuf:"bytes,1,rep,name=tuples" json:"tuples,omitempty"`
}
func (m *LongLivedGracefulRestartCapability) Reset() { *m = LongLivedGracefulRestartCapability{} }
func (m *LongLivedGracefulRestartCapability) String() string { return proto.CompactTextString(m) }
func (*LongLivedGracefulRestartCapability) ProtoMessage() {}
func (*LongLivedGracefulRestartCapability) Descriptor() ([]byte, []int) {
return fileDescriptor2, []int{12}
}
func (m *LongLivedGracefulRestartCapability) GetTuples() []*LongLivedGracefulRestartCapabilityTuple {
if m != nil {
return m.Tuples
}
return nil
}
type RouteRefreshCiscoCapability struct {
}
func (m *RouteRefreshCiscoCapability) Reset() { *m = RouteRefreshCiscoCapability{} }
func (m *RouteRefreshCiscoCapability) String() string { return proto.CompactTextString(m) }
func (*RouteRefreshCiscoCapability) ProtoMessage() {}
func (*RouteRefreshCiscoCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{13} }
type UnknownCapability struct {
Code uint32 `protobuf:"varint,1,opt,name=code" json:"code,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (m *UnknownCapability) Reset() { *m = UnknownCapability{} }
func (m *UnknownCapability) String() string { return proto.CompactTextString(m) }
func (*UnknownCapability) ProtoMessage() {}
func (*UnknownCapability) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{14} }
func (m *UnknownCapability) GetCode() uint32 {
if m != nil {
return m.Code
}
return 0
}
func (m *UnknownCapability) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
func init() {
proto.RegisterType((*MultiProtocolCapability)(nil), "gobgpapi.MultiProtocolCapability")
proto.RegisterType((*RouteRefreshCapability)(nil), "gobgpapi.RouteRefreshCapability")
proto.RegisterType((*CarryingLabelInfoCapability)(nil), "gobgpapi.CarryingLabelInfoCapability")
proto.RegisterType((*ExtendedNexthopCapabilityTuple)(nil), "gobgpapi.ExtendedNexthopCapabilityTuple")
proto.RegisterType((*ExtendedNexthopCapability)(nil), "gobgpapi.ExtendedNexthopCapability")
proto.RegisterType((*GracefulRestartCapabilityTuple)(nil), "gobgpapi.GracefulRestartCapabilityTuple")
proto.RegisterType((*GracefulRestartCapability)(nil), "gobgpapi.GracefulRestartCapability")
proto.RegisterType((*FourOctetASNumberCapability)(nil), "gobgpapi.FourOctetASNumberCapability")
proto.RegisterType((*AddPathCapabilityTuple)(nil), "gobgpapi.AddPathCapabilityTuple")
proto.RegisterType((*AddPathCapability)(nil), "gobgpapi.AddPathCapability")
proto.RegisterType((*EnhancedRouteRefreshCapability)(nil), "gobgpapi.EnhancedRouteRefreshCapability")
proto.RegisterType((*LongLivedGracefulRestartCapabilityTuple)(nil), "gobgpapi.LongLivedGracefulRestartCapabilityTuple")
proto.RegisterType((*LongLivedGracefulRestartCapability)(nil), "gobgpapi.LongLivedGracefulRestartCapability")
proto.RegisterType((*RouteRefreshCiscoCapability)(nil), "gobgpapi.RouteRefreshCiscoCapability")
proto.RegisterType((*UnknownCapability)(nil), "gobgpapi.UnknownCapability")
proto.RegisterEnum("gobgpapi.AddPathMode", AddPathMode_name, AddPathMode_value)
}
func init() { proto.RegisterFile("capability.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 520 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x4d, 0x6f, 0xd3, 0x40,
0x10, 0xc5, 0x49, 0x88, 0x60, 0xd2, 0x44, 0xee, 0x0a, 0x4a, 0x4a, 0xd4, 0x28, 0xda, 0x0b, 0x01,
0x89, 0x48, 0x0d, 0x07, 0xb8, 0x20, 0x51, 0x52, 0x17, 0x22, 0xe5, 0xa3, 0x72, 0x0b, 0x37, 0x54,
0x36, 0xf6, 0xc6, 0x59, 0xb1, 0xde, 0xb5, 0xec, 0x75, 0x69, 0x0e, 0x9c, 0xb9, 0xf0, 0xa3, 0x91,
0x3f, 0x62, 0x9b, 0x54, 0x6e, 0x2b, 0xa4, 0xde, 0x66, 0xbc, 0x33, 0x6f, 0xde, 0x9b, 0xb7, 0x6b,
0xd0, 0x2d, 0xe2, 0x91, 0x05, 0xe3, 0x4c, 0xad, 0x07, 0x9e, 0x2f, 0x95, 0x44, 0x8f, 0x1c, 0xb9,
0x70, 0x3c, 0xe2, 0xb1, 0xe7, 0x8d, 0x38, 0x4a, 0x3e, 0xe3, 0x11, 0x3c, 0x9b, 0x86, 0x5c, 0xb1,
0xd3, 0x28, 0xb3, 0x24, 0x1f, 0x65, 0x7d, 0xa8, 0x0f, 0xf5, 0x25, 0x71, 0x19, 0x5f, 0xb7, 0xb5,
0x9e, 0xd6, 0x6f, 0x0c, 0xf5, 0xc1, 0x06, 0x62, 0x70, 0x12, 0x7f, 0x37, 0xd3, 0x73, 0xdc, 0x86,
0x3d, 0x53, 0x86, 0x8a, 0x9a, 0x74, 0xe9, 0xd3, 0x60, 0x95, 0x63, 0xe0, 0x03, 0xe8, 0x8c, 0x88,
0xef, 0xaf, 0x99, 0x70, 0x26, 0x64, 0x41, 0xf9, 0x58, 0x2c, 0x65, 0xe1, 0xf8, 0x8f, 0x06, 0x5d,
0xe3, 0x4a, 0x51, 0x61, 0x53, 0x7b, 0x46, 0xaf, 0xd4, 0x4a, 0x7a, 0xf9, 0xe9, 0x79, 0xe8, 0x71,
0x8a, 0x0e, 0xa1, 0x21, 0xb8, 0xcf, 0x2e, 0x6e, 0xa1, 0x02, 0x51, 0x51, 0x12, 0xa3, 0xb7, 0xd0,
0x12, 0x09, 0xd8, 0xa6, 0xab, 0x52, 0xd2, 0xd5, 0x4c, 0xeb, 0x92, 0x14, 0x7f, 0x83, 0xfd, 0x52,
0x36, 0xe8, 0x03, 0xd4, 0x55, 0xc4, 0x28, 0x68, 0x6b, 0xbd, 0x6a, 0xbf, 0x31, 0xec, 0xe7, 0x68,
0x37, 0x4b, 0x30, 0xd3, 0x3e, 0xfc, 0x1d, 0xba, 0x9f, 0x7c, 0x62, 0xd1, 0x65, 0xc8, 0x4d, 0x1a,
0x28, 0xe2, 0xab, 0x6d, 0xb1, 0x77, 0x5e, 0x39, 0x7a, 0x02, 0x0f, 0x97, 0x9c, 0x38, 0x41, 0x2c,
0xad, 0x69, 0x26, 0x09, 0xfe, 0xad, 0xc1, 0x7e, 0xe9, 0x88, 0xbc, 0x47, 0x2b, 0xf4, 0x20, 0x04,
0x35, 0xc5, 0x5c, 0x9a, 0x02, 0xc5, 0x71, 0x41, 0x6b, 0x75, 0x5b, 0xeb, 0xcd, 0x0a, 0x32, 0xad,
0xaf, 0xa1, 0x73, 0x22, 0x43, 0x7f, 0x6e, 0x29, 0xaa, 0x8e, 0xce, 0x66, 0xa1, 0xbb, 0xa0, 0x7e,
0x81, 0x4a, 0x0b, 0x2a, 0x64, 0xc3, 0xa3, 0x42, 0x02, 0xec, 0xc2, 0xde, 0x91, 0x6d, 0x9f, 0x12,
0xb5, 0xfa, 0xff, 0x95, 0xbc, 0x84, 0x9a, 0x2b, 0xed, 0x44, 0x48, 0x6b, 0xf8, 0x34, 0xaf, 0x4b,
0x91, 0xa7, 0xd2, 0xa6, 0x66, 0x5c, 0x82, 0xa7, 0xb0, 0x7b, 0x6d, 0x1c, 0x7a, 0xb7, 0x65, 0x70,
0xef, 0x1a, 0x42, 0x99, 0xd8, 0x1e, 0x74, 0x0d, 0xb1, 0x22, 0xc2, 0xa2, 0x76, 0xc9, 0x3b, 0xf8,
0x05, 0x2f, 0x26, 0x52, 0x38, 0x13, 0x76, 0x49, 0xed, 0xfb, 0xbd, 0x03, 0x99, 0x9f, 0xd5, 0xdc,
0x4f, 0x2c, 0x01, 0xdf, 0x3e, 0x1e, 0x8d, 0xb7, 0x16, 0x70, 0x98, 0x4f, 0xbe, 0x23, 0xf9, 0x6c,
0x23, 0x07, 0xd0, 0xf9, 0x67, 0x13, 0x2c, 0xb0, 0x8a, 0xef, 0xfe, 0x3d, 0xec, 0x7e, 0x11, 0x3f,
0x84, 0xfc, 0x29, 0x0a, 0xe3, 0x11, 0xd4, 0xac, 0xc8, 0xbf, 0xe4, 0x56, 0xc4, 0x71, 0x24, 0xf1,
0x92, 0xf0, 0x30, 0x31, 0x75, 0xc7, 0x4c, 0x92, 0x57, 0x13, 0x68, 0x14, 0x3c, 0x45, 0x4d, 0x78,
0x3c, 0x9d, 0x1f, 0x1b, 0x17, 0xb3, 0xf9, 0xcc, 0xd0, 0x1f, 0x20, 0x1d, 0x76, 0xe2, 0xd4, 0x34,
0x46, 0xc6, 0xf8, 0xab, 0xa1, 0x6b, 0x59, 0xc1, 0x99, 0x31, 0x3b, 0xd6, 0x2b, 0x59, 0xfa, 0x71,
0x7e, 0xfe, 0x59, 0xaf, 0x2e, 0xea, 0xf1, 0x9f, 0xf0, 0xcd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff,
0x3b, 0xec, 0xd3, 0x4d, 0x34, 0x05, 0x00, 0x00,
}

100
vendor/github.com/osrg/gobgp/api/capability.proto generated vendored Normal file
View File

@@ -0,0 +1,100 @@
// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
syntax = "proto3";
import "gobgp.proto";
package gobgpapi;
enum AddPathMode {
MODE_NONE = 0;
MODE_RECEIVE = 1;
MODE_SEND = 2;
MODE_BOTH = 3;
}
message MultiProtocolCapability {
gobgpapi.Family family = 1;
}
message RouteRefreshCapability {
}
message CarryingLabelInfoCapability {
}
message ExtendedNexthopCapabilityTuple {
gobgpapi.Family nlri_family = 1;
// Nexthop AFI must be either
// gobgp.IPv4 or
// gobgp.IPv6.
gobgpapi.Family nexthop_family = 2;
}
message ExtendedNexthopCapability {
repeated ExtendedNexthopCapabilityTuple tuples = 1;
}
message GracefulRestartCapabilityTuple {
gobgpapi.Family family = 1;
uint32 flags = 2;
}
message GracefulRestartCapability {
uint32 flags = 1;
uint32 time = 2;
repeated GracefulRestartCapabilityTuple tuples = 3;
}
message FourOctetASNumberCapability {
uint32 as = 1;
}
message AddPathCapabilityTuple {
gobgpapi.Family family = 1;
AddPathMode mode = 2;
}
message AddPathCapability {
repeated AddPathCapabilityTuple tuples = 1;
}
message EnhancedRouteRefreshCapability {
}
message LongLivedGracefulRestartCapabilityTuple {
gobgpapi.Family family = 1;
uint32 flags = 2;
uint32 time = 3;
}
message LongLivedGracefulRestartCapability {
repeated LongLivedGracefulRestartCapabilityTuple tuples = 1;
}
message RouteRefreshCiscoCapability {
}
message UnknownCapability {
uint32 code = 1;
bytes value = 2;
}

8400
vendor/github.com/osrg/gobgp/api/gobgp.pb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1175
vendor/github.com/osrg/gobgp/api/gobgp.proto generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apiutil
import (
"fmt"
proto "github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
api "github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
func NewMultiProtocolCapability(a *bgp.CapMultiProtocol) *api.MultiProtocolCapability {
afi, safi := bgp.RouteFamilyToAfiSafi(a.CapValue)
return &api.MultiProtocolCapability{
Family: ToApiFamily(afi, safi),
}
}
func NewRouteRefreshCapability(a *bgp.CapRouteRefresh) *api.RouteRefreshCapability {
return &api.RouteRefreshCapability{}
}
func NewCarryingLabelInfoCapability(a *bgp.CapCarryingLabelInfo) *api.CarryingLabelInfoCapability {
return &api.CarryingLabelInfoCapability{}
}
func NewExtendedNexthopCapability(a *bgp.CapExtendedNexthop) *api.ExtendedNexthopCapability {
tuples := make([]*api.ExtendedNexthopCapabilityTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
tuples = append(tuples, &api.ExtendedNexthopCapabilityTuple{
NlriFamily: ToApiFamily(t.NLRIAFI, uint8(t.NLRISAFI)),
NexthopFamily: ToApiFamily(t.NexthopAFI, bgp.SAFI_UNICAST),
})
}
return &api.ExtendedNexthopCapability{
Tuples: tuples,
}
}
func NewGracefulRestartCapability(a *bgp.CapGracefulRestart) *api.GracefulRestartCapability {
tuples := make([]*api.GracefulRestartCapabilityTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
tuples = append(tuples, &api.GracefulRestartCapabilityTuple{
Family: ToApiFamily(t.AFI, t.SAFI),
Flags: uint32(t.Flags),
})
}
return &api.GracefulRestartCapability{
Flags: uint32(a.Flags),
Time: uint32(a.Time),
Tuples: tuples,
}
}
func NewFourOctetASNumberCapability(a *bgp.CapFourOctetASNumber) *api.FourOctetASNumberCapability {
return &api.FourOctetASNumberCapability{
As: a.CapValue,
}
}
func NewAddPathCapability(a *bgp.CapAddPath) *api.AddPathCapability {
tuples := make([]*api.AddPathCapabilityTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
afi, safi := bgp.RouteFamilyToAfiSafi(t.RouteFamily)
tuples = append(tuples, &api.AddPathCapabilityTuple{
Family: ToApiFamily(afi, safi),
Mode: api.AddPathMode(t.Mode),
})
}
return &api.AddPathCapability{
Tuples: tuples,
}
}
func NewEnhancedRouteRefreshCapability(a *bgp.CapEnhancedRouteRefresh) *api.EnhancedRouteRefreshCapability {
return &api.EnhancedRouteRefreshCapability{}
}
func NewLongLivedGracefulRestartCapability(a *bgp.CapLongLivedGracefulRestart) *api.LongLivedGracefulRestartCapability {
tuples := make([]*api.LongLivedGracefulRestartCapabilityTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
tuples = append(tuples, &api.LongLivedGracefulRestartCapabilityTuple{
Family: ToApiFamily(t.AFI, uint8(t.SAFI)),
Flags: uint32(t.Flags),
Time: t.RestartTime,
})
}
return &api.LongLivedGracefulRestartCapability{
Tuples: tuples,
}
}
func NewRouteRefreshCiscoCapability(a *bgp.CapRouteRefreshCisco) *api.RouteRefreshCiscoCapability {
return &api.RouteRefreshCiscoCapability{}
}
func NewUnknownCapability(a *bgp.CapUnknown) *api.UnknownCapability {
return &api.UnknownCapability{
Code: uint32(a.CapCode),
Value: a.CapValue,
}
}
func MarshalCapability(value bgp.ParameterCapabilityInterface) (*any.Any, error) {
var m proto.Message
switch n := value.(type) {
case *bgp.CapMultiProtocol:
m = NewMultiProtocolCapability(n)
case *bgp.CapRouteRefresh:
m = NewRouteRefreshCapability(n)
case *bgp.CapCarryingLabelInfo:
m = NewCarryingLabelInfoCapability(n)
case *bgp.CapExtendedNexthop:
m = NewExtendedNexthopCapability(n)
case *bgp.CapGracefulRestart:
m = NewGracefulRestartCapability(n)
case *bgp.CapFourOctetASNumber:
m = NewFourOctetASNumberCapability(n)
case *bgp.CapAddPath:
m = NewAddPathCapability(n)
case *bgp.CapEnhancedRouteRefresh:
m = NewEnhancedRouteRefreshCapability(n)
case *bgp.CapLongLivedGracefulRestart:
m = NewLongLivedGracefulRestartCapability(n)
case *bgp.CapRouteRefreshCisco:
m = NewRouteRefreshCiscoCapability(n)
case *bgp.CapUnknown:
m = NewUnknownCapability(n)
default:
return nil, fmt.Errorf("invalid capability type to marshal: %+v", value)
}
return ptypes.MarshalAny(m)
}
func MarshalCapabilities(values []bgp.ParameterCapabilityInterface) ([]*any.Any, error) {
caps := make([]*any.Any, 0, len(values))
for _, value := range values {
a, err := MarshalCapability(value)
if err != nil {
return nil, err
}
caps = append(caps, a)
}
return caps, nil
}
func unmarshalCapability(a *any.Any) (bgp.ParameterCapabilityInterface, error) {
var value ptypes.DynamicAny
if err := ptypes.UnmarshalAny(a, &value); err != nil {
return nil, fmt.Errorf("failed to unmarshal capability: %s", err)
}
switch a := value.Message.(type) {
case *api.MultiProtocolCapability:
return bgp.NewCapMultiProtocol(ToRouteFamily(a.Family)), nil
case *api.RouteRefreshCapability:
return bgp.NewCapRouteRefresh(), nil
case *api.CarryingLabelInfoCapability:
return bgp.NewCapCarryingLabelInfo(), nil
case *api.ExtendedNexthopCapability:
tuples := make([]*bgp.CapExtendedNexthopTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
var nhAfi uint16
switch t.NexthopFamily.Afi {
case api.Family_AFI_IP:
nhAfi = bgp.AFI_IP
case api.Family_AFI_IP6:
nhAfi = bgp.AFI_IP6
default:
return nil, fmt.Errorf("invalid address family for nexthop afi in extended nexthop capability: %s", t.NexthopFamily)
}
tuples = append(tuples, bgp.NewCapExtendedNexthopTuple(ToRouteFamily(t.NlriFamily), nhAfi))
}
return bgp.NewCapExtendedNexthop(tuples), nil
case *api.GracefulRestartCapability:
tuples := make([]*bgp.CapGracefulRestartTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
var forward bool
if t.Flags&0x80 > 0 {
forward = true
}
tuples = append(tuples, bgp.NewCapGracefulRestartTuple(ToRouteFamily(t.Family), forward))
}
var restarting bool
if a.Flags&0x08 > 0 {
restarting = true
}
var notification bool
if a.Flags&0x04 > 0 {
notification = true
}
return bgp.NewCapGracefulRestart(restarting, notification, uint16(a.Time), tuples), nil
case *api.FourOctetASNumberCapability:
return bgp.NewCapFourOctetASNumber(a.As), nil
case *api.AddPathCapability:
tuples := make([]*bgp.CapAddPathTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
tuples = append(tuples, bgp.NewCapAddPathTuple(ToRouteFamily(t.Family), bgp.BGPAddPathMode(t.Mode)))
}
return bgp.NewCapAddPath(tuples), nil
case *api.EnhancedRouteRefreshCapability:
return bgp.NewCapEnhancedRouteRefresh(), nil
case *api.LongLivedGracefulRestartCapability:
tuples := make([]*bgp.CapLongLivedGracefulRestartTuple, 0, len(a.Tuples))
for _, t := range a.Tuples {
var forward bool
if t.Flags&0x80 > 0 {
forward = true
}
tuples = append(tuples, bgp.NewCapLongLivedGracefulRestartTuple(ToRouteFamily(t.Family), forward, t.Time))
}
return bgp.NewCapLongLivedGracefulRestart(tuples), nil
case *api.RouteRefreshCiscoCapability:
return bgp.NewCapRouteRefreshCisco(), nil
case *api.UnknownCapability:
return bgp.NewCapUnknown(bgp.BGPCapabilityCode(a.Code), a.Value), nil
}
return nil, fmt.Errorf("invalid capability type to unmarshal: %s", a.TypeUrl)
}
func UnmarshalCapabilities(values []*any.Any) ([]bgp.ParameterCapabilityInterface, error) {
caps := make([]bgp.ParameterCapabilityInterface, 0, len(values))
for _, value := range values {
c, err := unmarshalCapability(value)
if err != nil {
return nil, err
}
caps = append(caps, c)
}
return caps, nil
}

View File

@@ -0,0 +1,125 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apiutil
import (
"encoding/json"
"net"
"time"
api "github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
// workaround. This for the json format compatibility. Once we update senario tests, we can remove this.
type Path struct {
Nlri bgp.AddrPrefixInterface `json:"nlri"`
Age int64 `json:"age"`
Best bool `json:"best"`
Attrs []bgp.PathAttributeInterface `json:"attrs"`
Stale bool `json:"stale"`
Withdrawal bool `json:"withdrawal,omitempty"`
SourceID net.IP `json:"source-id,omitempty"`
NeighborIP net.IP `json:"neighbor-ip,omitempty"`
}
type Destination struct {
Paths []*Path
}
func (d *Destination) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Paths)
}
func NewDestination(dst *api.Destination) *Destination {
l := make([]*Path, 0, len(dst.Paths))
for _, p := range dst.Paths {
nlri, _ := GetNativeNlri(p)
attrs, _ := GetNativePathAttributes(p)
l = append(l, &Path{
Nlri: nlri,
Age: p.Age,
Best: p.Best,
Attrs: attrs,
Stale: p.Stale,
Withdrawal: p.IsWithdraw,
SourceID: net.ParseIP(p.SourceId),
NeighborIP: net.ParseIP(p.NeighborIp),
})
}
return &Destination{Paths: l}
}
func NewPath(nlri bgp.AddrPrefixInterface, isWithdraw bool, attrs []bgp.PathAttributeInterface, age time.Time) *api.Path {
return &api.Path{
AnyNlri: MarshalNLRI(nlri),
AnyPattrs: MarshalPathAttributes(attrs),
Age: age.Unix(),
IsWithdraw: isWithdraw,
Family: ToApiFamily(nlri.AFI(), nlri.SAFI()),
Identifier: nlri.PathIdentifier(),
}
}
func getNLRI(family bgp.RouteFamily, buf []byte) (bgp.AddrPrefixInterface, error) {
afi, safi := bgp.RouteFamilyToAfiSafi(family)
nlri, err := bgp.NewPrefixFromRouteFamily(afi, safi)
if err != nil {
return nil, err
}
if err := nlri.DecodeFromBytes(buf); err != nil {
return nil, err
}
return nlri, nil
}
func GetNativeNlri(p *api.Path) (bgp.AddrPrefixInterface, error) {
if len(p.Nlri) > 0 {
return getNLRI(ToRouteFamily(p.Family), p.Nlri)
}
return UnmarshalNLRI(ToRouteFamily(p.Family), p.AnyNlri)
}
func GetNativePathAttributes(p *api.Path) ([]bgp.PathAttributeInterface, error) {
pattrsLen := len(p.Pattrs)
if pattrsLen > 0 {
pattrs := make([]bgp.PathAttributeInterface, 0, pattrsLen)
for _, attr := range p.Pattrs {
a, err := bgp.GetPathAttribute(attr)
if err != nil {
return nil, err
}
err = a.DecodeFromBytes(attr)
if err != nil {
return nil, err
}
pattrs = append(pattrs, a)
}
return pattrs, nil
}
return UnmarshalPathAttributes(p.AnyPattrs)
}
func ToRouteFamily(f *api.Family) bgp.RouteFamily {
return bgp.AfiSafiToRouteFamily(uint16(f.Afi), uint8(f.Safi))
}
func ToApiFamily(afi uint16, safi uint8) *api.Family {
return &api.Family{
Afi: api.Family_Afi(afi),
Safi: api.Family_Safi(safi),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,524 @@
package config
import (
"encoding/binary"
"fmt"
"math"
"net"
"reflect"
"strconv"
"github.com/osrg/gobgp/pkg/packet/bgp"
"github.com/osrg/gobgp/pkg/packet/bmp"
"github.com/osrg/gobgp/pkg/packet/rtr"
"github.com/spf13/viper"
)
const (
DEFAULT_HOLDTIME = 90
DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30
DEFAULT_CONNECT_RETRY = 120
)
var forcedOverwrittenConfig = []string{
"neighbor.config.peer-as",
"neighbor.timers.config.minimum-advertisement-interval",
}
var configuredFields map[string]interface{}
func RegisterConfiguredFields(addr string, n interface{}) {
if configuredFields == nil {
configuredFields = make(map[string]interface{})
}
configuredFields[addr] = n
}
func defaultAfiSafi(typ AfiSafiType, enable bool) AfiSafi {
return AfiSafi{
Config: AfiSafiConfig{
AfiSafiName: typ,
Enabled: enable,
},
State: AfiSafiState{
AfiSafiName: typ,
Family: bgp.AddressFamilyValueMap[string(typ)],
},
}
}
func SetDefaultNeighborConfigValues(n *Neighbor, pg *PeerGroup, g *Global) error {
// Determines this function is called against the same Neighbor struct,
// and if already called, returns immediately.
if n.State.LocalAs != 0 {
return nil
}
return setDefaultNeighborConfigValuesWithViper(nil, n, g, pg)
}
func setDefaultNeighborConfigValuesWithViper(v *viper.Viper, n *Neighbor, g *Global, pg *PeerGroup) error {
if n == nil {
return fmt.Errorf("neighbor config is nil")
}
if g == nil {
return fmt.Errorf("global config is nil")
}
if v == nil {
v = viper.New()
}
if pg != nil {
if err := OverwriteNeighborConfigWithPeerGroup(n, pg); err != nil {
return err
}
}
if n.Config.LocalAs == 0 {
n.Config.LocalAs = g.Config.As
if !g.Confederation.Config.Enabled || n.IsConfederation(g) {
n.Config.LocalAs = g.Config.As
} else {
n.Config.LocalAs = g.Confederation.Config.Identifier
}
}
n.State.LocalAs = n.Config.LocalAs
if n.Config.PeerAs != n.Config.LocalAs {
n.Config.PeerType = PEER_TYPE_EXTERNAL
n.State.PeerType = PEER_TYPE_EXTERNAL
n.State.RemovePrivateAs = n.Config.RemovePrivateAs
n.AsPathOptions.State.ReplacePeerAs = n.AsPathOptions.Config.ReplacePeerAs
} else {
n.Config.PeerType = PEER_TYPE_INTERNAL
n.State.PeerType = PEER_TYPE_INTERNAL
if string(n.Config.RemovePrivateAs) != "" {
return fmt.Errorf("can't set remove-private-as for iBGP peer")
}
if n.AsPathOptions.Config.ReplacePeerAs {
return fmt.Errorf("can't set replace-peer-as for iBGP peer")
}
}
if n.State.NeighborAddress == "" {
n.State.NeighborAddress = n.Config.NeighborAddress
}
n.State.PeerAs = n.Config.PeerAs
n.AsPathOptions.State.AllowOwnAs = n.AsPathOptions.Config.AllowOwnAs
if !v.IsSet("neighbor.error-handling.config.treat-as-withdraw") {
n.ErrorHandling.Config.TreatAsWithdraw = true
}
if !v.IsSet("neighbor.timers.config.connect-retry") && n.Timers.Config.ConnectRetry == 0 {
n.Timers.Config.ConnectRetry = float64(DEFAULT_CONNECT_RETRY)
}
if !v.IsSet("neighbor.timers.config.hold-time") && n.Timers.Config.HoldTime == 0 {
n.Timers.Config.HoldTime = float64(DEFAULT_HOLDTIME)
}
if !v.IsSet("neighbor.timers.config.keepalive-interval") && n.Timers.Config.KeepaliveInterval == 0 {
n.Timers.Config.KeepaliveInterval = n.Timers.Config.HoldTime / 3
}
if !v.IsSet("neighbor.timers.config.idle-hold-time-after-reset") && n.Timers.Config.IdleHoldTimeAfterReset == 0 {
n.Timers.Config.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
}
if n.Config.NeighborInterface != "" {
if n.RouteServer.Config.RouteServerClient {
return fmt.Errorf("configuring route server client as unnumbered peer is not supported")
}
addr, err := GetIPv6LinkLocalNeighborAddress(n.Config.NeighborInterface)
if err != nil {
return err
}
n.State.NeighborAddress = addr
}
if n.Transport.Config.LocalAddress == "" {
if n.State.NeighborAddress == "" {
return fmt.Errorf("no neighbor address/interface specified")
}
ipAddr, err := net.ResolveIPAddr("ip", n.State.NeighborAddress)
if err != nil {
return err
}
localAddress := "0.0.0.0"
if ipAddr.IP.To4() == nil {
localAddress = "::"
if ipAddr.Zone != "" {
localAddress, err = getIPv6LinkLocalAddress(ipAddr.Zone)
if err != nil {
return err
}
}
}
n.Transport.Config.LocalAddress = localAddress
}
if len(n.AfiSafis) == 0 {
if n.Config.NeighborInterface != "" {
n.AfiSafis = []AfiSafi{
defaultAfiSafi(AFI_SAFI_TYPE_IPV4_UNICAST, true),
defaultAfiSafi(AFI_SAFI_TYPE_IPV6_UNICAST, true),
}
} else if ipAddr, err := net.ResolveIPAddr("ip", n.State.NeighborAddress); err != nil {
return fmt.Errorf("invalid neighbor address: %s", n.State.NeighborAddress)
} else if ipAddr.IP.To4() != nil {
n.AfiSafis = []AfiSafi{defaultAfiSafi(AFI_SAFI_TYPE_IPV4_UNICAST, true)}
} else {
n.AfiSafis = []AfiSafi{defaultAfiSafi(AFI_SAFI_TYPE_IPV6_UNICAST, true)}
}
for i := range n.AfiSafis {
n.AfiSafis[i].AddPaths.Config.Receive = n.AddPaths.Config.Receive
n.AfiSafis[i].AddPaths.State.Receive = n.AddPaths.Config.Receive
n.AfiSafis[i].AddPaths.Config.SendMax = n.AddPaths.Config.SendMax
n.AfiSafis[i].AddPaths.State.SendMax = n.AddPaths.Config.SendMax
}
} else {
afs, err := extractArray(v.Get("neighbor.afi-safis"))
if err != nil {
return err
}
for i := range n.AfiSafis {
vv := viper.New()
if len(afs) > i {
vv.Set("afi-safi", afs[i])
}
rf, err := bgp.GetRouteFamily(string(n.AfiSafis[i].Config.AfiSafiName))
if err != nil {
return err
}
n.AfiSafis[i].State.Family = rf
n.AfiSafis[i].State.AfiSafiName = n.AfiSafis[i].Config.AfiSafiName
if !vv.IsSet("afi-safi.config.enabled") {
n.AfiSafis[i].Config.Enabled = true
}
n.AfiSafis[i].MpGracefulRestart.State.Enabled = n.AfiSafis[i].MpGracefulRestart.Config.Enabled
if !vv.IsSet("afi-safi.add-paths.config.receive") {
n.AfiSafis[i].AddPaths.Config.Receive = n.AddPaths.Config.Receive
}
n.AfiSafis[i].AddPaths.State.Receive = n.AfiSafis[i].AddPaths.Config.Receive
if !vv.IsSet("afi-safi.add-paths.config.send-max") {
n.AfiSafis[i].AddPaths.Config.SendMax = n.AddPaths.Config.SendMax
}
n.AfiSafis[i].AddPaths.State.SendMax = n.AfiSafis[i].AddPaths.Config.SendMax
}
}
n.State.Description = n.Config.Description
n.State.AdminDown = n.Config.AdminDown
if n.GracefulRestart.Config.Enabled {
if !v.IsSet("neighbor.graceful-restart.config.restart-time") && n.GracefulRestart.Config.RestartTime == 0 {
// RFC 4724 4. Operation
// A suggested default for the Restart Time is a value less than or
// equal to the HOLDTIME carried in the OPEN.
n.GracefulRestart.Config.RestartTime = uint16(n.Timers.Config.HoldTime)
}
if !v.IsSet("neighbor.graceful-restart.config.deferral-time") && n.GracefulRestart.Config.DeferralTime == 0 {
// RFC 4724 4.1. Procedures for the Restarting Speaker
// The value of this timer should be large
// enough, so as to provide all the peers of the Restarting Speaker with
// enough time to send all the routes to the Restarting Speaker
n.GracefulRestart.Config.DeferralTime = uint16(360)
}
}
if n.EbgpMultihop.Config.Enabled {
if n.TtlSecurity.Config.Enabled {
return fmt.Errorf("ebgp-multihop and ttl-security are mututally exclusive")
}
if n.EbgpMultihop.Config.MultihopTtl == 0 {
n.EbgpMultihop.Config.MultihopTtl = 255
}
} else if n.TtlSecurity.Config.Enabled {
if n.TtlSecurity.Config.TtlMin == 0 {
n.TtlSecurity.Config.TtlMin = 255
}
}
if n.RouteReflector.Config.RouteReflectorClient {
if n.RouteReflector.Config.RouteReflectorClusterId == "" {
n.RouteReflector.State.RouteReflectorClusterId = RrClusterIdType(g.Config.RouterId)
} else {
id := string(n.RouteReflector.Config.RouteReflectorClusterId)
if ip := net.ParseIP(id).To4(); ip != nil {
n.RouteReflector.State.RouteReflectorClusterId = n.RouteReflector.Config.RouteReflectorClusterId
} else if num, err := strconv.ParseUint(id, 10, 32); err == nil {
ip = make(net.IP, 4)
binary.BigEndian.PutUint32(ip, uint32(num))
n.RouteReflector.State.RouteReflectorClusterId = RrClusterIdType(ip.String())
} else {
return fmt.Errorf("route-reflector-cluster-id should be specified as IPv4 address or 32-bit unsigned integer")
}
}
}
return nil
}
func SetDefaultGlobalConfigValues(g *Global) error {
if len(g.AfiSafis) == 0 {
g.AfiSafis = []AfiSafi{}
for k := range AfiSafiTypeToIntMap {
g.AfiSafis = append(g.AfiSafis, defaultAfiSafi(k, true))
}
}
if g.Config.Port == 0 {
g.Config.Port = bgp.BGP_PORT
}
if len(g.Config.LocalAddressList) == 0 {
g.Config.LocalAddressList = []string{"0.0.0.0", "::"}
}
return nil
}
func setDefaultVrfConfigValues(v *Vrf) error {
if v == nil {
return fmt.Errorf("cannot set default values for nil vrf config")
}
if v.Config.Name == "" {
return fmt.Errorf("specify vrf name")
}
_, err := bgp.ParseRouteDistinguisher(v.Config.Rd)
if err != nil {
return fmt.Errorf("invalid rd for vrf %s: %s", v.Config.Name, v.Config.Rd)
}
if len(v.Config.ImportRtList) == 0 {
v.Config.ImportRtList = v.Config.BothRtList
}
for _, rtString := range v.Config.ImportRtList {
_, err := bgp.ParseRouteTarget(rtString)
if err != nil {
return fmt.Errorf("invalid import rt for vrf %s: %s", v.Config.Name, rtString)
}
}
if len(v.Config.ExportRtList) == 0 {
v.Config.ExportRtList = v.Config.BothRtList
}
for _, rtString := range v.Config.ExportRtList {
_, err := bgp.ParseRouteTarget(rtString)
if err != nil {
return fmt.Errorf("invalid export rt for vrf %s: %s", v.Config.Name, rtString)
}
}
return nil
}
func SetDefaultConfigValues(b *BgpConfigSet) error {
return setDefaultConfigValuesWithViper(nil, b)
}
func setDefaultPolicyConfigValuesWithViper(v *viper.Viper, p *PolicyDefinition) error {
stmts, err := extractArray(v.Get("policy.statements"))
if err != nil {
return err
}
for i := range p.Statements {
vv := viper.New()
if len(stmts) > i {
vv.Set("statement", stmts[i])
}
if !vv.IsSet("statement.actions.route-disposition") {
p.Statements[i].Actions.RouteDisposition = ROUTE_DISPOSITION_NONE
}
}
return nil
}
func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error {
if v == nil {
v = viper.New()
}
if err := SetDefaultGlobalConfigValues(&b.Global); err != nil {
return err
}
for idx, server := range b.BmpServers {
if server.Config.Port == 0 {
server.Config.Port = bmp.BMP_DEFAULT_PORT
}
if server.Config.RouteMonitoringPolicy == "" {
server.Config.RouteMonitoringPolicy = BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY
}
// statistics-timeout is uint16 value and implicitly less than 65536
if server.Config.StatisticsTimeout != 0 && server.Config.StatisticsTimeout < 15 {
return fmt.Errorf("too small statistics-timeout value: %d", server.Config.StatisticsTimeout)
}
b.BmpServers[idx] = server
}
vrfNames := make(map[string]struct{})
vrfIDs := make(map[uint32]struct{})
for idx, vrf := range b.Vrfs {
if err := setDefaultVrfConfigValues(&vrf); err != nil {
return err
}
if _, ok := vrfNames[vrf.Config.Name]; ok {
return fmt.Errorf("duplicated vrf name: %s", vrf.Config.Name)
}
vrfNames[vrf.Config.Name] = struct{}{}
if vrf.Config.Id != 0 {
if _, ok := vrfIDs[vrf.Config.Id]; ok {
return fmt.Errorf("duplicated vrf id: %d", vrf.Config.Id)
}
vrfIDs[vrf.Config.Id] = struct{}{}
}
b.Vrfs[idx] = vrf
}
// Auto assign VRF identifier
for idx, vrf := range b.Vrfs {
if vrf.Config.Id == 0 {
for id := uint32(1); id < math.MaxUint32; id++ {
if _, ok := vrfIDs[id]; !ok {
vrf.Config.Id = id
vrfIDs[id] = struct{}{}
break
}
}
}
b.Vrfs[idx] = vrf
}
if b.Zebra.Config.Url == "" {
b.Zebra.Config.Url = "unix:/var/run/quagga/zserv.api"
}
if b.Zebra.Config.Version < 2 {
b.Zebra.Config.Version = 2
} else if b.Zebra.Config.Version > 5 {
b.Zebra.Config.Version = 5
}
if !v.IsSet("zebra.config.nexthop-trigger-enable") && !b.Zebra.Config.NexthopTriggerEnable && b.Zebra.Config.Version > 2 {
b.Zebra.Config.NexthopTriggerEnable = true
}
if b.Zebra.Config.NexthopTriggerDelay == 0 {
b.Zebra.Config.NexthopTriggerDelay = 5
}
list, err := extractArray(v.Get("neighbors"))
if err != nil {
return err
}
for idx, n := range b.Neighbors {
vv := viper.New()
if len(list) > idx {
vv.Set("neighbor", list[idx])
}
pg, err := b.getPeerGroup(n.Config.PeerGroup)
if err != nil {
return nil
}
if pg != nil {
identifier := vv.Get("neighbor.config.neighbor-address")
if identifier == nil {
identifier = vv.Get("neighbor.config.neighbor-interface")
}
RegisterConfiguredFields(identifier.(string), list[idx])
}
if err := setDefaultNeighborConfigValuesWithViper(vv, &n, &b.Global, pg); err != nil {
return err
}
b.Neighbors[idx] = n
}
for _, d := range b.DynamicNeighbors {
if err := d.validate(b); err != nil {
return err
}
}
for idx, r := range b.RpkiServers {
if r.Config.Port == 0 {
b.RpkiServers[idx].Config.Port = rtr.RPKI_DEFAULT_PORT
}
}
list, err = extractArray(v.Get("policy-definitions"))
if err != nil {
return err
}
for idx, p := range b.PolicyDefinitions {
vv := viper.New()
if len(list) > idx {
vv.Set("policy", list[idx])
}
if err := setDefaultPolicyConfigValuesWithViper(vv, &p); err != nil {
return err
}
b.PolicyDefinitions[idx] = p
}
return nil
}
func OverwriteNeighborConfigWithPeerGroup(c *Neighbor, pg *PeerGroup) error {
v := viper.New()
val, ok := configuredFields[c.Config.NeighborAddress]
if ok {
v.Set("neighbor", val)
} else {
v.Set("neighbor.config.peer-group", c.Config.PeerGroup)
}
overwriteConfig(&c.Config, &pg.Config, "neighbor.config", v)
overwriteConfig(&c.Timers.Config, &pg.Timers.Config, "neighbor.timers.config", v)
overwriteConfig(&c.Transport.Config, &pg.Transport.Config, "neighbor.transport.config", v)
overwriteConfig(&c.ErrorHandling.Config, &pg.ErrorHandling.Config, "neighbor.error-handling.config", v)
overwriteConfig(&c.LoggingOptions.Config, &pg.LoggingOptions.Config, "neighbor.logging-options.config", v)
overwriteConfig(&c.EbgpMultihop.Config, &pg.EbgpMultihop.Config, "neighbor.ebgp-multihop.config", v)
overwriteConfig(&c.RouteReflector.Config, &pg.RouteReflector.Config, "neighbor.route-reflector.config", v)
overwriteConfig(&c.AsPathOptions.Config, &pg.AsPathOptions.Config, "neighbor.as-path-options.config", v)
overwriteConfig(&c.AddPaths.Config, &pg.AddPaths.Config, "neighbor.add-paths.config", v)
overwriteConfig(&c.GracefulRestart.Config, &pg.GracefulRestart.Config, "neighbor.gradeful-restart.config", v)
overwriteConfig(&c.ApplyPolicy.Config, &pg.ApplyPolicy.Config, "neighbor.apply-policy.config", v)
overwriteConfig(&c.UseMultiplePaths.Config, &pg.UseMultiplePaths.Config, "neighbor.use-multiple-paths.config", v)
overwriteConfig(&c.RouteServer.Config, &pg.RouteServer.Config, "neighbor.route-server.config", v)
overwriteConfig(&c.TtlSecurity.Config, &pg.TtlSecurity.Config, "neighbor.ttl-security.config", v)
if !v.IsSet("neighbor.afi-safis") {
c.AfiSafis = append(c.AfiSafis, pg.AfiSafis...)
}
return nil
}
func overwriteConfig(c, pg interface{}, tagPrefix string, v *viper.Viper) {
nValue := reflect.Indirect(reflect.ValueOf(c))
nType := reflect.Indirect(nValue).Type()
pgValue := reflect.Indirect(reflect.ValueOf(pg))
pgType := reflect.Indirect(pgValue).Type()
for i := 0; i < pgType.NumField(); i++ {
field := pgType.Field(i).Name
tag := tagPrefix + "." + nType.Field(i).Tag.Get("mapstructure")
if func() bool {
for _, t := range forcedOverwrittenConfig {
if t == tag {
return true
}
}
return false
}() || !v.IsSet(tag) {
nValue.FieldByName(field).Set(pgValue.FieldByName(field))
}
}
}

View File

@@ -0,0 +1,72 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
package config
import (
"fmt"
"net"
"github.com/vishvananda/netlink"
)
func GetIPv6LinkLocalNeighborAddress(ifname string) (string, error) {
ifi, err := net.InterfaceByName(ifname)
if err != nil {
return "", err
}
neighs, err := netlink.NeighList(ifi.Index, netlink.FAMILY_V6)
if err != nil {
return "", err
}
cnt := 0
var addr net.IP
for _, neigh := range neighs {
local, err := isLocalLinkLocalAddress(ifi.Index, neigh.IP)
if err != nil {
return "", err
}
if neigh.State&netlink.NUD_FAILED == 0 && neigh.IP.IsLinkLocalUnicast() && !local {
addr = neigh.IP
cnt++
}
}
if cnt == 0 {
return "", fmt.Errorf("no ipv6 link-local neighbor found")
} else if cnt > 1 {
return "", fmt.Errorf("found %d link-local neighbors. only support p2p link", cnt)
}
return fmt.Sprintf("%s%%%s", addr, ifname), nil
}
func isLocalLinkLocalAddress(ifindex int, addr net.IP) (bool, error) {
ifi, err := net.InterfaceByIndex(ifindex)
if err != nil {
return false, err
}
addrs, err := ifi.Addrs()
if err != nil {
return false, err
}
for _, a := range addrs {
if ip, _, _ := net.ParseCIDR(a.String()); addr.Equal(ip) {
return true, nil
}
}
return false, nil
}

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !linux
package config
import (
"fmt"
)
func GetIPv6LinkLocalNeighborAddress(ifname string) (string, error) {
return "", fmt.Errorf("unnumbered peering is not supported")
}

View File

@@ -0,0 +1,159 @@
package config
import (
"os"
"os/signal"
"syscall"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
type BgpConfigSet struct {
Global Global `mapstructure:"global"`
Neighbors []Neighbor `mapstructure:"neighbors"`
PeerGroups []PeerGroup `mapstructure:"peer-groups"`
RpkiServers []RpkiServer `mapstructure:"rpki-servers"`
BmpServers []BmpServer `mapstructure:"bmp-servers"`
Vrfs []Vrf `mapstructure:"vrfs"`
MrtDump []Mrt `mapstructure:"mrt-dump"`
Zebra Zebra `mapstructure:"zebra"`
Collector Collector `mapstructure:"collector"`
DefinedSets DefinedSets `mapstructure:"defined-sets"`
PolicyDefinitions []PolicyDefinition `mapstructure:"policy-definitions"`
DynamicNeighbors []DynamicNeighbor `mapstructure:"dynamic-neighbors"`
}
func ReadConfigfileServe(path, format string, configCh chan *BgpConfigSet) {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGHUP)
// Update config file type, if detectable
format = detectConfigFileType(path, format)
cnt := 0
for {
c := &BgpConfigSet{}
v := viper.New()
v.SetConfigFile(path)
v.SetConfigType(format)
var err error
if err = v.ReadInConfig(); err != nil {
goto ERROR
}
if err = v.UnmarshalExact(c); err != nil {
goto ERROR
}
if err = setDefaultConfigValuesWithViper(v, c); err != nil {
goto ERROR
}
if cnt == 0 {
log.WithFields(log.Fields{
"Topic": "Config",
}).Info("Finished reading the config file")
}
cnt++
configCh <- c
goto NEXT
ERROR:
if cnt == 0 {
log.WithFields(log.Fields{
"Topic": "Config",
"Error": err,
}).Fatalf("Can't read config file %s", path)
} else {
log.WithFields(log.Fields{
"Topic": "Config",
"Error": err,
}).Warningf("Can't read config file %s", path)
}
NEXT:
<-sigCh
log.WithFields(log.Fields{
"Topic": "Config",
}).Info("Reload the config file")
}
}
func ConfigSetToRoutingPolicy(c *BgpConfigSet) *RoutingPolicy {
return &RoutingPolicy{
DefinedSets: c.DefinedSets,
PolicyDefinitions: c.PolicyDefinitions,
}
}
func UpdatePeerGroupConfig(curC, newC *BgpConfigSet) ([]PeerGroup, []PeerGroup, []PeerGroup) {
addedPg := []PeerGroup{}
deletedPg := []PeerGroup{}
updatedPg := []PeerGroup{}
for _, n := range newC.PeerGroups {
if idx := existPeerGroup(n.Config.PeerGroupName, curC.PeerGroups); idx < 0 {
addedPg = append(addedPg, n)
} else if !n.Equal(&curC.PeerGroups[idx]) {
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("Current peer-group config:%v", curC.PeerGroups[idx])
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("New peer-group config:%v", n)
updatedPg = append(updatedPg, n)
}
}
for _, n := range curC.PeerGroups {
if existPeerGroup(n.Config.PeerGroupName, newC.PeerGroups) < 0 {
deletedPg = append(deletedPg, n)
}
}
return addedPg, deletedPg, updatedPg
}
func UpdateNeighborConfig(curC, newC *BgpConfigSet) ([]Neighbor, []Neighbor, []Neighbor) {
added := []Neighbor{}
deleted := []Neighbor{}
updated := []Neighbor{}
for _, n := range newC.Neighbors {
if idx := inSlice(n, curC.Neighbors); idx < 0 {
added = append(added, n)
} else if !n.Equal(&curC.Neighbors[idx]) {
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("Current neighbor config:%v", curC.Neighbors[idx])
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("New neighbor config:%v", n)
updated = append(updated, n)
}
}
for _, n := range curC.Neighbors {
if inSlice(n, newC.Neighbors) < 0 {
deleted = append(deleted, n)
}
}
return added, deleted, updated
}
func CheckPolicyDifference(currentPolicy *RoutingPolicy, newPolicy *RoutingPolicy) bool {
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("Current policy:%v", currentPolicy)
log.WithFields(log.Fields{
"Topic": "Config",
}).Debugf("New policy:%v", newPolicy)
var result bool
if currentPolicy == nil && newPolicy == nil {
result = false
} else {
if currentPolicy != nil && newPolicy != nil {
result = !currentPolicy.Equal(newPolicy)
} else {
result = true
}
}
return result
}

View File

@@ -0,0 +1,264 @@
// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"fmt"
"net"
"path/filepath"
"regexp"
"strconv"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
// Returns config file type by retrieving extension from the given path.
// If no corresponding type found, returns the given def as the default value.
func detectConfigFileType(path, def string) string {
switch ext := filepath.Ext(path); ext {
case ".toml":
return "toml"
case ".yaml", ".yml":
return "yaml"
case ".json":
return "json"
default:
return def
}
}
// yaml is decoded as []interface{}
// but toml is decoded as []map[string]interface{}.
// currently, viper can't hide this difference.
// handle the difference here.
func extractArray(intf interface{}) ([]interface{}, error) {
if intf != nil {
list, ok := intf.([]interface{})
if ok {
return list, nil
}
l, ok := intf.([]map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid configuration: neither []interface{} nor []map[string]interface{}")
}
list = make([]interface{}, 0, len(l))
for _, m := range l {
list = append(list, m)
}
return list, nil
}
return nil, nil
}
func getIPv6LinkLocalAddress(ifname string) (string, error) {
ifi, err := net.InterfaceByName(ifname)
if err != nil {
return "", err
}
addrs, err := ifi.Addrs()
if err != nil {
return "", err
}
for _, addr := range addrs {
ip := addr.(*net.IPNet).IP
if ip.To4() == nil && ip.IsLinkLocalUnicast() {
return fmt.Sprintf("%s%%%s", ip.String(), ifname), nil
}
}
return "", fmt.Errorf("no ipv6 link local address for %s", ifname)
}
func (b *BgpConfigSet) getPeerGroup(n string) (*PeerGroup, error) {
if n == "" {
return nil, nil
}
for _, pg := range b.PeerGroups {
if n == pg.Config.PeerGroupName {
return &pg, nil
}
}
return nil, fmt.Errorf("no such peer-group: %s", n)
}
func (d *DynamicNeighbor) validate(b *BgpConfigSet) error {
if d.Config.PeerGroup == "" {
return fmt.Errorf("dynamic neighbor requires the peer group config")
}
if _, err := b.getPeerGroup(d.Config.PeerGroup); err != nil {
return err
}
if _, _, err := net.ParseCIDR(d.Config.Prefix); err != nil {
return fmt.Errorf("invalid dynamic neighbor prefix %s", d.Config.Prefix)
}
return nil
}
func (n *Neighbor) IsConfederationMember(g *Global) bool {
for _, member := range g.Confederation.Config.MemberAsList {
if member == n.Config.PeerAs {
return true
}
}
return false
}
func (n *Neighbor) IsConfederation(g *Global) bool {
if n.Config.PeerAs == g.Config.As {
return true
}
return n.IsConfederationMember(g)
}
func (n *Neighbor) IsEBGPPeer(g *Global) bool {
return n.Config.PeerAs != g.Config.As
}
func (n *Neighbor) CreateRfMap() map[bgp.RouteFamily]bgp.BGPAddPathMode {
rfMap := make(map[bgp.RouteFamily]bgp.BGPAddPathMode)
for _, af := range n.AfiSafis {
mode := bgp.BGP_ADD_PATH_NONE
if af.AddPaths.State.Receive {
mode |= bgp.BGP_ADD_PATH_RECEIVE
}
if af.AddPaths.State.SendMax > 0 {
mode |= bgp.BGP_ADD_PATH_SEND
}
rfMap[af.State.Family] = mode
}
return rfMap
}
func (n *Neighbor) GetAfiSafi(family bgp.RouteFamily) *AfiSafi {
for _, a := range n.AfiSafis {
if string(a.Config.AfiSafiName) == family.String() {
return &a
}
}
return nil
}
func (n *Neighbor) ExtractNeighborAddress() (string, error) {
addr := n.State.NeighborAddress
if addr == "" {
addr = n.Config.NeighborAddress
if addr == "" {
return "", fmt.Errorf("NeighborAddress is not configured")
}
}
return addr, nil
}
func (n *Neighbor) IsAddPathReceiveEnabled(family bgp.RouteFamily) bool {
for _, af := range n.AfiSafis {
if af.State.Family == family {
return af.AddPaths.State.Receive
}
}
return false
}
type AfiSafis []AfiSafi
func (c AfiSafis) ToRfList() ([]bgp.RouteFamily, error) {
rfs := make([]bgp.RouteFamily, 0, len(c))
for _, af := range c {
rfs = append(rfs, af.State.Family)
}
return rfs, nil
}
func inSlice(n Neighbor, b []Neighbor) int {
for i, nb := range b {
if nb.State.NeighborAddress == n.State.NeighborAddress {
return i
}
}
return -1
}
func existPeerGroup(n string, b []PeerGroup) int {
for i, nb := range b {
if nb.Config.PeerGroupName == n {
return i
}
}
return -1
}
func isAfiSafiChanged(x, y []AfiSafi) bool {
if len(x) != len(y) {
return true
}
m := make(map[string]bool)
for _, e := range x {
m[string(e.Config.AfiSafiName)] = true
}
for _, e := range y {
if !m[string(e.Config.AfiSafiName)] {
return true
}
}
return false
}
func (n *Neighbor) NeedsResendOpenMessage(new *Neighbor) bool {
return !n.Config.Equal(&new.Config) ||
!n.Transport.Config.Equal(&new.Transport.Config) ||
!n.AddPaths.Config.Equal(&new.AddPaths.Config) ||
!n.GracefulRestart.Config.Equal(&new.GracefulRestart.Config) ||
isAfiSafiChanged(n.AfiSafis, new.AfiSafis)
}
// TODO: these regexp are duplicated in api
var _regexpPrefixMaskLengthRange = regexp.MustCompile(`(\d+)\.\.(\d+)`)
func ParseMaskLength(prefix, mask string) (int, int, error) {
_, ipNet, err := net.ParseCIDR(prefix)
if err != nil {
return 0, 0, fmt.Errorf("invalid prefix: %s", prefix)
}
if mask == "" {
l, _ := ipNet.Mask.Size()
return l, l, nil
}
elems := _regexpPrefixMaskLengthRange.FindStringSubmatch(mask)
if len(elems) != 3 {
return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
}
// we've already checked the range is sane by regexp
min, _ := strconv.ParseUint(elems[1], 10, 8)
max, _ := strconv.ParseUint(elems[2], 10, 8)
if min > max {
return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
}
if ipv4 := ipNet.IP.To4(); ipv4 != nil {
f := func(i uint64) bool {
return i <= 32
}
if !f(min) || !f(max) {
return 0, 0, fmt.Errorf("ipv4 mask length range outside scope :%s", mask)
}
} else {
f := func(i uint64) bool {
return i <= 128
}
if !f(min) || !f(max) {
return 0, 0, fmt.Errorf("ipv6 mask length range outside scope :%s", mask)
}
}
return int(min), int(max), nil
}

186
vendor/github.com/osrg/gobgp/internal/pkg/table/adj.go generated vendored Normal file
View File

@@ -0,0 +1,186 @@
// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"fmt"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
type AdjRib struct {
accepted map[bgp.RouteFamily]int
table map[bgp.RouteFamily]map[string]*Path
}
func NewAdjRib(rfList []bgp.RouteFamily) *AdjRib {
table := make(map[bgp.RouteFamily]map[string]*Path)
for _, rf := range rfList {
table[rf] = make(map[string]*Path)
}
return &AdjRib{
table: table,
accepted: make(map[bgp.RouteFamily]int),
}
}
func (adj *AdjRib) Update(pathList []*Path) {
for _, path := range pathList {
if path == nil || path.IsEOR() {
continue
}
rf := path.GetRouteFamily()
key := fmt.Sprintf("%d:%s", path.GetNlri().PathIdentifier(), path.getPrefix())
old, found := adj.table[rf][key]
if path.IsWithdraw {
if found {
delete(adj.table[rf], key)
if !old.IsAsLooped() {
adj.accepted[rf]--
}
}
} else {
if found {
if old.IsAsLooped() && !path.IsAsLooped() {
adj.accepted[rf]++
} else if !old.IsAsLooped() && path.IsAsLooped() {
adj.accepted[rf]--
}
} else {
if !path.IsAsLooped() {
adj.accepted[rf]++
}
}
if found && old.Equal(path) {
path.setTimestamp(old.GetTimestamp())
}
adj.table[rf][key] = path
}
}
}
func (adj *AdjRib) PathList(rfList []bgp.RouteFamily, accepted bool) []*Path {
pathList := make([]*Path, 0, adj.Count(rfList))
for _, rf := range rfList {
for _, rr := range adj.table[rf] {
if accepted && rr.IsAsLooped() {
continue
}
pathList = append(pathList, rr)
}
}
return pathList
}
func (adj *AdjRib) Count(rfList []bgp.RouteFamily) int {
count := 0
for _, rf := range rfList {
if table, ok := adj.table[rf]; ok {
count += len(table)
}
}
return count
}
func (adj *AdjRib) Accepted(rfList []bgp.RouteFamily) int {
count := 0
for _, rf := range rfList {
if n, ok := adj.accepted[rf]; ok {
count += n
}
}
return count
}
func (adj *AdjRib) Drop(rfList []bgp.RouteFamily) {
for _, rf := range rfList {
if _, ok := adj.table[rf]; ok {
adj.table[rf] = make(map[string]*Path)
adj.accepted[rf] = 0
}
}
}
func (adj *AdjRib) DropStale(rfList []bgp.RouteFamily) []*Path {
pathList := make([]*Path, 0, adj.Count(rfList))
for _, rf := range rfList {
if table, ok := adj.table[rf]; ok {
for k, p := range table {
if p.IsStale() {
delete(table, k)
if !p.IsAsLooped() {
adj.accepted[rf]--
}
pathList = append(pathList, p.Clone(true))
}
}
}
}
return pathList
}
func (adj *AdjRib) StaleAll(rfList []bgp.RouteFamily) []*Path {
pathList := make([]*Path, 0)
for _, rf := range rfList {
if table, ok := adj.table[rf]; ok {
l := make([]*Path, 0, len(table))
for k, p := range table {
n := p.Clone(false)
n.MarkStale(true)
table[k] = n
l = append(l, n)
}
if len(l) > 0 {
pathList = append(pathList, l...)
}
}
}
return pathList
}
func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) {
m := make(map[string][]*Path)
pl := adj.PathList([]bgp.RouteFamily{family}, accepted)
for _, path := range pl {
key := path.GetNlri().String()
if _, y := m[key]; y {
m[key] = append(m[key], path)
} else {
m[key] = []*Path{path}
}
}
d := make([]*Destination, 0, len(pl))
for _, l := range m {
d = append(d, NewDestination(l[0].GetNlri(), 0, l...))
}
tbl := NewTable(family, d...)
option = append(option, TableSelectOption{adj: true})
return tbl.Select(option...)
}
func (adj *AdjRib) TableInfo(family bgp.RouteFamily) (*TableInfo, error) {
if _, ok := adj.table[family]; !ok {
return nil, fmt.Errorf("%s unsupported", family)
}
c := adj.Count([]bgp.RouteFamily{family})
a := adj.Accepted([]bgp.RouteFamily{family})
return &TableInfo{
NumDestination: c,
NumPath: c,
NumAccepted: a,
}, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,502 @@
// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"bytes"
"reflect"
"github.com/osrg/gobgp/pkg/packet/bgp"
log "github.com/sirupsen/logrus"
)
func UpdatePathAttrs2ByteAs(msg *bgp.BGPUpdate) error {
ps := msg.PathAttributes
msg.PathAttributes = make([]bgp.PathAttributeInterface, len(ps))
copy(msg.PathAttributes, ps)
var asAttr *bgp.PathAttributeAsPath
idx := 0
for i, attr := range msg.PathAttributes {
if a, ok := attr.(*bgp.PathAttributeAsPath); ok {
asAttr = a
idx = i
break
}
}
if asAttr == nil {
return nil
}
as4Params := make([]*bgp.As4PathParam, 0, len(asAttr.Value))
as2Params := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
mkAs4 := false
for _, param := range asAttr.Value {
segType := param.GetType()
asList := param.GetAS()
as2Path := make([]uint16, 0, len(asList))
for _, as := range asList {
if as > (1<<16)-1 {
mkAs4 = true
as2Path = append(as2Path, bgp.AS_TRANS)
} else {
as2Path = append(as2Path, uint16(as))
}
}
as2Params = append(as2Params, bgp.NewAsPathParam(segType, as2Path))
// RFC 6793 4.2.2 Generating Updates
//
// Whenever the AS path information contains the AS_CONFED_SEQUENCE or
// AS_CONFED_SET path segment, the NEW BGP speaker MUST exclude such
// path segments from the AS4_PATH attribute being constructed.
switch segType {
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
// pass
default:
if as4param, ok := param.(*bgp.As4PathParam); ok {
as4Params = append(as4Params, as4param)
}
}
}
msg.PathAttributes[idx] = bgp.NewPathAttributeAsPath(as2Params)
if mkAs4 {
msg.PathAttributes = append(msg.PathAttributes, bgp.NewPathAttributeAs4Path(as4Params))
}
return nil
}
func UpdatePathAttrs4ByteAs(msg *bgp.BGPUpdate) error {
var asAttr *bgp.PathAttributeAsPath
var as4Attr *bgp.PathAttributeAs4Path
asAttrPos := 0
as4AttrPos := 0
for i, attr := range msg.PathAttributes {
switch attr.(type) {
case *bgp.PathAttributeAsPath:
asAttr = attr.(*bgp.PathAttributeAsPath)
for j, param := range asAttr.Value {
as2Param, ok := param.(*bgp.AsPathParam)
if ok {
asPath := make([]uint32, 0, len(as2Param.AS))
for _, as := range as2Param.AS {
asPath = append(asPath, uint32(as))
}
as4Param := bgp.NewAs4PathParam(as2Param.Type, asPath)
asAttr.Value[j] = as4Param
}
}
asAttrPos = i
msg.PathAttributes[i] = asAttr
case *bgp.PathAttributeAs4Path:
as4AttrPos = i
as4Attr = attr.(*bgp.PathAttributeAs4Path)
}
}
if as4Attr != nil {
msg.PathAttributes = append(msg.PathAttributes[:as4AttrPos], msg.PathAttributes[as4AttrPos+1:]...)
}
if asAttr == nil || as4Attr == nil {
return nil
}
asLen := 0
asConfedLen := 0
asParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
for _, param := range asAttr.Value {
asLen += param.ASLen()
switch param.GetType() {
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
asConfedLen++
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
asConfedLen += len(param.GetAS())
}
asParams = append(asParams, param)
}
as4Len := 0
as4Params := make([]bgp.AsPathParamInterface, 0, len(as4Attr.Value))
if as4Attr != nil {
for _, p := range as4Attr.Value {
// RFC 6793 6. Error Handling
//
// the path segment types AS_CONFED_SEQUENCE and AS_CONFED_SET [RFC5065]
// MUST NOT be carried in the AS4_PATH attribute of an UPDATE message.
// A NEW BGP speaker that receives these path segment types in the AS4_PATH
// attribute of an UPDATE message from an OLD BGP speaker MUST discard
// these path segments, adjust the relevant attribute fields accordingly,
// and continue processing the UPDATE message.
// This case SHOULD be logged locally for analysis.
switch p.Type {
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
typ := "CONFED_SEQ"
if p.Type == bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET {
typ = "CONFED_SET"
}
log.WithFields(log.Fields{
"Topic": "Table",
}).Warnf("AS4_PATH contains %s segment %s. ignore", typ, p.String())
continue
}
as4Len += p.ASLen()
as4Params = append(as4Params, p)
}
}
if asLen+asConfedLen < as4Len {
log.WithFields(log.Fields{
"Topic": "Table",
}).Warn("AS4_PATH is longer than AS_PATH. ignore AS4_PATH")
return nil
}
keepNum := asLen + asConfedLen - as4Len
newParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
for _, param := range asParams {
if keepNum-param.ASLen() >= 0 {
newParams = append(newParams, param)
keepNum -= param.ASLen()
} else {
// only SEQ param reaches here
newParams = append(newParams, bgp.NewAs4PathParam(param.GetType(), param.GetAS()[:keepNum]))
keepNum = 0
}
if keepNum <= 0 {
break
}
}
for _, param := range as4Params {
lastParam := newParams[len(newParams)-1]
lastParamAS := lastParam.GetAS()
paramType := param.GetType()
paramAS := param.GetAS()
if paramType == lastParam.GetType() && paramType == bgp.BGP_ASPATH_ATTR_TYPE_SEQ {
if len(lastParamAS)+len(paramAS) > 255 {
newParams[len(newParams)-1] = bgp.NewAs4PathParam(paramType, append(lastParamAS, paramAS[:255-len(lastParamAS)]...))
newParams = append(newParams, bgp.NewAs4PathParam(paramType, paramAS[255-len(lastParamAS):]))
} else {
newParams[len(newParams)-1] = bgp.NewAs4PathParam(paramType, append(lastParamAS, paramAS...))
}
} else {
newParams = append(newParams, param)
}
}
newIntfParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
newIntfParams = append(newIntfParams, newParams...)
msg.PathAttributes[asAttrPos] = bgp.NewPathAttributeAsPath(newIntfParams)
return nil
}
func UpdatePathAggregator2ByteAs(msg *bgp.BGPUpdate) {
as := uint32(0)
var addr string
for i, attr := range msg.PathAttributes {
switch attr.(type) {
case *bgp.PathAttributeAggregator:
agg := attr.(*bgp.PathAttributeAggregator)
addr = agg.Value.Address.String()
if agg.Value.AS > (1<<16)-1 {
as = agg.Value.AS
msg.PathAttributes[i] = bgp.NewPathAttributeAggregator(uint16(bgp.AS_TRANS), addr)
} else {
msg.PathAttributes[i] = bgp.NewPathAttributeAggregator(uint16(agg.Value.AS), addr)
}
}
}
if as != 0 {
msg.PathAttributes = append(msg.PathAttributes, bgp.NewPathAttributeAs4Aggregator(as, addr))
}
}
func UpdatePathAggregator4ByteAs(msg *bgp.BGPUpdate) error {
var aggAttr *bgp.PathAttributeAggregator
var agg4Attr *bgp.PathAttributeAs4Aggregator
agg4AttrPos := 0
for i, attr := range msg.PathAttributes {
switch attr.(type) {
case *bgp.PathAttributeAggregator:
attr := attr.(*bgp.PathAttributeAggregator)
if attr.Value.Askind == reflect.Uint16 {
aggAttr = attr
aggAttr.Value.Askind = reflect.Uint32
}
case *bgp.PathAttributeAs4Aggregator:
agg4Attr = attr.(*bgp.PathAttributeAs4Aggregator)
agg4AttrPos = i
}
}
if aggAttr == nil && agg4Attr == nil {
return nil
}
if aggAttr == nil && agg4Attr != nil {
return bgp.NewMessageError(bgp.BGP_ERROR_UPDATE_MESSAGE_ERROR, bgp.BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "AS4 AGGREGATOR attribute exists, but AGGREGATOR doesn't")
}
if agg4Attr != nil {
msg.PathAttributes = append(msg.PathAttributes[:agg4AttrPos], msg.PathAttributes[agg4AttrPos+1:]...)
aggAttr.Value.AS = agg4Attr.Value.AS
}
return nil
}
type cage struct {
attrsBytes []byte
paths []*Path
}
func newCage(b []byte, path *Path) *cage {
return &cage{
attrsBytes: b,
paths: []*Path{path},
}
}
type packerInterface interface {
add(*Path)
pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage
}
type packer struct {
eof bool
family bgp.RouteFamily
total uint32
}
type packerMP struct {
packer
paths []*Path
withdrawals []*Path
}
func (p *packerMP) add(path *Path) {
p.packer.total++
if path.IsEOR() {
p.packer.eof = true
return
}
if path.IsWithdraw {
p.withdrawals = append(p.withdrawals, path)
return
}
p.paths = append(p.paths, path)
}
func createMPReachMessage(path *Path) *bgp.BGPMessage {
oattrs := path.GetPathAttrs()
attrs := make([]bgp.PathAttributeInterface, 0, len(oattrs))
for _, a := range oattrs {
if a.GetType() == bgp.BGP_ATTR_TYPE_MP_REACH_NLRI {
attrs = append(attrs, bgp.NewPathAttributeMpReachNLRI(path.GetNexthop().String(), []bgp.AddrPrefixInterface{path.GetNlri()}))
} else {
attrs = append(attrs, a)
}
}
return bgp.NewBGPUpdateMessage(nil, attrs, nil)
}
func (p *packerMP) pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
msgs := make([]*bgp.BGPMessage, 0, p.packer.total)
for _, path := range p.withdrawals {
nlris := []bgp.AddrPrefixInterface{path.GetNlri()}
msgs = append(msgs, bgp.NewBGPUpdateMessage(nil, []bgp.PathAttributeInterface{bgp.NewPathAttributeMpUnreachNLRI(nlris)}, nil))
}
for _, path := range p.paths {
msgs = append(msgs, createMPReachMessage(path))
}
if p.eof {
msgs = append(msgs, bgp.NewEndOfRib(p.family))
}
return msgs
}
func newPackerMP(f bgp.RouteFamily) *packerMP {
return &packerMP{
packer: packer{
family: f,
},
withdrawals: make([]*Path, 0),
paths: make([]*Path, 0),
}
}
type packerV4 struct {
packer
hashmap map[uint32][]*cage
mpPaths []*Path
withdrawals []*Path
}
func (p *packerV4) add(path *Path) {
p.packer.total++
if path.IsEOR() {
p.packer.eof = true
return
}
if path.IsWithdraw {
p.withdrawals = append(p.withdrawals, path)
return
}
if path.GetNexthop().To4() == nil {
// RFC 5549
p.mpPaths = append(p.mpPaths, path)
return
}
key := path.GetHash()
attrsB := bytes.NewBuffer(make([]byte, 0))
for _, v := range path.GetPathAttrs() {
b, _ := v.Serialize()
attrsB.Write(b)
}
if cages, y := p.hashmap[key]; y {
added := false
for _, c := range cages {
if bytes.Equal(c.attrsBytes, attrsB.Bytes()) {
c.paths = append(c.paths, path)
added = true
break
}
}
if !added {
p.hashmap[key] = append(p.hashmap[key], newCage(attrsB.Bytes(), path))
}
} else {
p.hashmap[key] = []*cage{newCage(attrsB.Bytes(), path)}
}
}
func (p *packerV4) pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
split := func(max int, paths []*Path) ([]*bgp.IPAddrPrefix, []*Path) {
nlris := make([]*bgp.IPAddrPrefix, 0, max)
i := 0
if max > len(paths) {
max = len(paths)
}
for ; i < max; i++ {
nlris = append(nlris, paths[i].GetNlri().(*bgp.IPAddrPrefix))
}
return nlris, paths[i:]
}
addpathNLRILen := 0
if bgp.IsAddPathEnabled(false, p.packer.family, options) {
addpathNLRILen = 4
}
// Header + Update (WithdrawnRoutesLen +
// TotalPathAttributeLen + attributes + maxlen of NLRI).
// the max size of NLRI is 5bytes (plus 4bytes with addpath enabled)
maxNLRIs := func(attrsLen int) int {
return (bgp.BGP_MAX_MESSAGE_LENGTH - (19 + 2 + 2 + attrsLen)) / (5 + addpathNLRILen)
}
loop := func(attrsLen int, paths []*Path, cb func([]*bgp.IPAddrPrefix)) {
max := maxNLRIs(attrsLen)
var nlris []*bgp.IPAddrPrefix
for {
nlris, paths = split(max, paths)
if len(nlris) == 0 {
break
}
cb(nlris)
}
}
msgs := make([]*bgp.BGPMessage, 0, p.packer.total)
loop(0, p.withdrawals, func(nlris []*bgp.IPAddrPrefix) {
msgs = append(msgs, bgp.NewBGPUpdateMessage(nlris, nil, nil))
})
for _, cages := range p.hashmap {
for _, c := range cages {
paths := c.paths
attrs := paths[0].GetPathAttrs()
attrsLen := 0
for _, a := range attrs {
attrsLen += a.Len()
}
loop(attrsLen, paths, func(nlris []*bgp.IPAddrPrefix) {
msgs = append(msgs, bgp.NewBGPUpdateMessage(nil, attrs, nlris))
})
}
}
for _, path := range p.mpPaths {
msgs = append(msgs, createMPReachMessage(path))
}
if p.eof {
msgs = append(msgs, bgp.NewEndOfRib(p.family))
}
return msgs
}
func newPackerV4(f bgp.RouteFamily) *packerV4 {
return &packerV4{
packer: packer{
family: f,
},
hashmap: make(map[uint32][]*cage),
withdrawals: make([]*Path, 0),
mpPaths: make([]*Path, 0),
}
}
func newPacker(f bgp.RouteFamily) packerInterface {
switch f {
case bgp.RF_IPv4_UC:
return newPackerV4(bgp.RF_IPv4_UC)
default:
return newPackerMP(f)
}
}
func CreateUpdateMsgFromPaths(pathList []*Path, options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
msgs := make([]*bgp.BGPMessage, 0, len(pathList))
m := make(map[bgp.RouteFamily]packerInterface)
for _, path := range pathList {
f := path.GetRouteFamily()
if _, y := m[f]; !y {
m[f] = newPacker(f)
}
m[f].add(path)
}
for _, p := range m {
msgs = append(msgs, p.pack(options...)...)
}
return msgs
}

1179
vendor/github.com/osrg/gobgp/internal/pkg/table/path.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

3895
vendor/github.com/osrg/gobgp/internal/pkg/table/policy.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

60
vendor/github.com/osrg/gobgp/internal/pkg/table/roa.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"fmt"
"net"
)
type IPPrefix struct {
Prefix net.IP
Length uint8
}
func (p *IPPrefix) String() string {
return fmt.Sprintf("%s/%d", p.Prefix, p.Length)
}
type ROA struct {
Family int
Prefix *IPPrefix
MaxLen uint8
AS uint32
Src string
}
func NewROA(family int, prefixByte []byte, prefixLen uint8, maxLen uint8, as uint32, src string) *ROA {
p := make([]byte, len(prefixByte))
copy(p, prefixByte)
return &ROA{
Family: family,
Prefix: &IPPrefix{
Prefix: p,
Length: prefixLen,
},
MaxLen: maxLen,
AS: as,
Src: src,
}
}
func (r *ROA) Equal(roa *ROA) bool {
if r.MaxLen == roa.MaxLen && r.Src == roa.Src && r.AS == roa.AS {
return true
}
return false
}

View File

@@ -0,0 +1,451 @@
// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"fmt"
"net"
"strings"
"unsafe"
"github.com/armon/go-radix"
"github.com/osrg/gobgp/pkg/packet/bgp"
log "github.com/sirupsen/logrus"
)
type LookupOption uint8
const (
LOOKUP_EXACT LookupOption = iota
LOOKUP_LONGER
LOOKUP_SHORTER
)
type LookupPrefix struct {
Prefix string
LookupOption
}
type TableSelectOption struct {
ID string
AS uint32
LookupPrefixes []*LookupPrefix
VRF *Vrf
adj bool
Best bool
MultiPath bool
}
type Table struct {
routeFamily bgp.RouteFamily
destinations map[string]*Destination
}
func NewTable(rf bgp.RouteFamily, dsts ...*Destination) *Table {
t := &Table{
routeFamily: rf,
destinations: make(map[string]*Destination),
}
for _, dst := range dsts {
t.setDestination(dst)
}
return t
}
func (t *Table) GetRoutefamily() bgp.RouteFamily {
return t.routeFamily
}
func (t *Table) deletePathsByVrf(vrf *Vrf) []*Path {
pathList := make([]*Path, 0)
for _, dest := range t.destinations {
for _, p := range dest.knownPathList {
var rd bgp.RouteDistinguisherInterface
nlri := p.GetNlri()
switch nlri.(type) {
case *bgp.LabeledVPNIPAddrPrefix:
rd = nlri.(*bgp.LabeledVPNIPAddrPrefix).RD
case *bgp.LabeledVPNIPv6AddrPrefix:
rd = nlri.(*bgp.LabeledVPNIPv6AddrPrefix).RD
case *bgp.EVPNNLRI:
rd = nlri.(*bgp.EVPNNLRI).RD()
default:
return pathList
}
if p.IsLocal() && vrf.Rd.String() == rd.String() {
pathList = append(pathList, p.Clone(true))
break
}
}
}
return pathList
}
func (t *Table) deleteRTCPathsByVrf(vrf *Vrf, vrfs map[string]*Vrf) []*Path {
pathList := make([]*Path, 0)
if t.routeFamily != bgp.RF_RTC_UC {
return pathList
}
for _, target := range vrf.ImportRt {
lhs := target.String()
for _, dest := range t.destinations {
nlri := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI)
rhs := nlri.RouteTarget.String()
if lhs == rhs && isLastTargetUser(vrfs, target) {
for _, p := range dest.knownPathList {
if p.IsLocal() {
pathList = append(pathList, p.Clone(true))
break
}
}
}
}
}
return pathList
}
func (t *Table) deleteDestByNlri(nlri bgp.AddrPrefixInterface) *Destination {
if dst := t.GetDestination(nlri); dst != nil {
t.deleteDest(dst)
return dst
}
return nil
}
func (t *Table) deleteDest(dest *Destination) {
destinations := t.GetDestinations()
delete(destinations, t.tableKey(dest.GetNlri()))
if len(destinations) == 0 {
t.destinations = make(map[string]*Destination)
}
}
func (t *Table) validatePath(path *Path) {
if path == nil {
log.WithFields(log.Fields{
"Topic": "Table",
"Key": t.routeFamily,
}).Error("path is nil")
}
if path.GetRouteFamily() != t.routeFamily {
log.WithFields(log.Fields{
"Topic": "Table",
"Key": t.routeFamily,
"Prefix": path.GetNlri().String(),
"ReceivedRf": path.GetRouteFamily().String(),
}).Error("Invalid path. RouteFamily mismatch")
}
if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); attr != nil {
pathParam := attr.(*bgp.PathAttributeAsPath).Value
for _, as := range pathParam {
_, y := as.(*bgp.As4PathParam)
if !y {
log.WithFields(log.Fields{
"Topic": "Table",
"Key": t.routeFamily,
"As": as,
}).Fatal("AsPathParam must be converted to As4PathParam")
}
}
}
if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS4_PATH); attr != nil {
log.WithFields(log.Fields{
"Topic": "Table",
"Key": t.routeFamily,
}).Fatal("AS4_PATH must be converted to AS_PATH")
}
if path.GetNlri() == nil {
log.WithFields(log.Fields{
"Topic": "Table",
"Key": t.routeFamily,
}).Fatal("path's nlri is nil")
}
}
func (t *Table) getOrCreateDest(nlri bgp.AddrPrefixInterface) *Destination {
dest := t.GetDestination(nlri)
// If destination for given prefix does not exist we create it.
if dest == nil {
log.WithFields(log.Fields{
"Topic": "Table",
"Nlri": nlri,
}).Debugf("create Destination")
dest = NewDestination(nlri, 64)
t.setDestination(dest)
}
return dest
}
func (t *Table) GetDestinations() map[string]*Destination {
return t.destinations
}
func (t *Table) setDestinations(destinations map[string]*Destination) {
t.destinations = destinations
}
func (t *Table) GetDestination(nlri bgp.AddrPrefixInterface) *Destination {
dest, ok := t.destinations[t.tableKey(nlri)]
if ok {
return dest
} else {
return nil
}
}
func (t *Table) GetLongerPrefixDestinations(key string) ([]*Destination, error) {
results := make([]*Destination, 0, len(t.GetDestinations()))
switch t.routeFamily {
case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC, bgp.RF_IPv4_MPLS, bgp.RF_IPv6_MPLS:
_, prefix, err := net.ParseCIDR(key)
if err != nil {
return nil, err
}
k := CidrToRadixkey(prefix.String())
r := radix.New()
for _, dst := range t.GetDestinations() {
r.Insert(AddrToRadixkey(dst.nlri), dst)
}
r.WalkPrefix(k, func(s string, v interface{}) bool {
results = append(results, v.(*Destination))
return false
})
default:
for _, dst := range t.GetDestinations() {
results = append(results, dst)
}
}
return results, nil
}
func (t *Table) GetEvpnDestinationsWithRouteType(typ string) ([]*Destination, error) {
var routeType uint8
switch strings.ToLower(typ) {
case "a-d":
routeType = bgp.EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY
case "macadv":
routeType = bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT
case "multicast":
routeType = bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG
case "esi":
routeType = bgp.EVPN_ETHERNET_SEGMENT_ROUTE
case "prefix":
routeType = bgp.EVPN_IP_PREFIX
default:
return nil, fmt.Errorf("unsupported evpn route type: %s", typ)
}
destinations := t.GetDestinations()
results := make([]*Destination, 0, len(destinations))
switch t.routeFamily {
case bgp.RF_EVPN:
for _, dst := range destinations {
if nlri, ok := dst.nlri.(*bgp.EVPNNLRI); !ok {
return nil, fmt.Errorf("invalid evpn nlri type detected: %T", dst.nlri)
} else if nlri.RouteType == routeType {
results = append(results, dst)
}
}
default:
for _, dst := range destinations {
results = append(results, dst)
}
}
return results, nil
}
func (t *Table) setDestination(dst *Destination) {
t.destinations[t.tableKey(dst.nlri)] = dst
}
func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string {
switch T := nlri.(type) {
case *bgp.IPAddrPrefix:
b := make([]byte, 5)
copy(b, T.Prefix.To4())
b[4] = T.Length
return *(*string)(unsafe.Pointer(&b))
case *bgp.IPv6AddrPrefix:
b := make([]byte, 17)
copy(b, T.Prefix.To16())
b[16] = T.Length
return *(*string)(unsafe.Pointer(&b))
}
return nlri.String()
}
func (t *Table) Bests(id string, as uint32) []*Path {
paths := make([]*Path, 0, len(t.destinations))
for _, dst := range t.destinations {
path := dst.GetBestPath(id, as)
if path != nil {
paths = append(paths, path)
}
}
return paths
}
func (t *Table) MultiBests(id string) [][]*Path {
paths := make([][]*Path, 0, len(t.destinations))
for _, dst := range t.destinations {
path := dst.GetMultiBestPath(id)
if path != nil {
paths = append(paths, path)
}
}
return paths
}
func (t *Table) GetKnownPathList(id string, as uint32) []*Path {
paths := make([]*Path, 0, len(t.destinations))
for _, dst := range t.destinations {
paths = append(paths, dst.GetKnownPathList(id, as)...)
}
return paths
}
func (t *Table) Select(option ...TableSelectOption) (*Table, error) {
id := GLOBAL_RIB_NAME
var vrf *Vrf
adj := false
prefixes := make([]*LookupPrefix, 0, len(option))
best := false
mp := false
as := uint32(0)
for _, o := range option {
if o.ID != "" {
id = o.ID
}
if o.VRF != nil {
vrf = o.VRF
}
adj = o.adj
prefixes = append(prefixes, o.LookupPrefixes...)
best = o.Best
mp = o.MultiPath
as = o.AS
}
dOption := DestinationSelectOption{ID: id, AS: as, VRF: vrf, adj: adj, Best: best, MultiPath: mp}
r := &Table{
routeFamily: t.routeFamily,
destinations: make(map[string]*Destination),
}
if len(prefixes) != 0 {
switch t.routeFamily {
case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
f := func(prefixStr string) bool {
var nlri bgp.AddrPrefixInterface
if t.routeFamily == bgp.RF_IPv4_UC {
nlri, _ = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP, bgp.SAFI_UNICAST, prefixStr)
} else {
nlri, _ = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP6, bgp.SAFI_UNICAST, prefixStr)
}
if dst := t.GetDestination(nlri); dst != nil {
if d := dst.Select(dOption); d != nil {
r.setDestination(d)
return true
}
}
return false
}
for _, p := range prefixes {
key := p.Prefix
switch p.LookupOption {
case LOOKUP_LONGER:
ds, err := t.GetLongerPrefixDestinations(key)
if err != nil {
return nil, err
}
for _, dst := range ds {
if d := dst.Select(dOption); d != nil {
r.setDestination(d)
}
}
case LOOKUP_SHORTER:
addr, prefix, err := net.ParseCIDR(key)
if err != nil {
return nil, err
}
ones, _ := prefix.Mask.Size()
for i := ones; i >= 0; i-- {
_, prefix, _ := net.ParseCIDR(fmt.Sprintf("%s/%d", addr.String(), i))
f(prefix.String())
}
default:
if host := net.ParseIP(key); host != nil {
masklen := 32
if t.routeFamily == bgp.RF_IPv6_UC {
masklen = 128
}
for i := masklen; i >= 0; i-- {
_, prefix, err := net.ParseCIDR(fmt.Sprintf("%s/%d", key, i))
if err != nil {
return nil, err
}
if f(prefix.String()) {
break
}
}
} else {
f(key)
}
}
}
case bgp.RF_EVPN:
for _, p := range prefixes {
// Uses LookupPrefix.Prefix as EVPN Route Type string
ds, err := t.GetEvpnDestinationsWithRouteType(p.Prefix)
if err != nil {
return nil, err
}
for _, dst := range ds {
if d := dst.Select(dOption); d != nil {
r.setDestination(d)
}
}
}
default:
return nil, fmt.Errorf("route filtering is not supported for this family")
}
} else {
for _, dst := range t.GetDestinations() {
if d := dst.Select(dOption); d != nil {
r.setDestination(d)
}
}
}
return r, nil
}
type TableInfo struct {
NumDestination int
NumPath int
NumAccepted int
}
func (t *Table) Info(id string, as uint32) *TableInfo {
var numD, numP int
for _, d := range t.destinations {
ps := d.GetKnownPathList(id, as)
if len(ps) > 0 {
numD += 1
numP += len(ps)
}
}
return &TableInfo{
NumDestination: numD,
NumPath: numP,
}
}

View File

@@ -0,0 +1,370 @@
// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"bytes"
"fmt"
"net"
"time"
farm "github.com/dgryski/go-farm"
log "github.com/sirupsen/logrus"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
const (
GLOBAL_RIB_NAME = "global"
)
func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo, timestamp time.Time) []*Path {
update := m.Body.(*bgp.BGPUpdate)
if y, f := update.IsEndOfRib(); y {
// this message has no normal updates or withdrawals.
return []*Path{NewEOR(f)}
}
adds := make([]bgp.AddrPrefixInterface, 0, len(update.NLRI))
for _, nlri := range update.NLRI {
adds = append(adds, nlri)
}
dels := make([]bgp.AddrPrefixInterface, 0, len(update.WithdrawnRoutes))
for _, nlri := range update.WithdrawnRoutes {
dels = append(dels, nlri)
}
attrs := make([]bgp.PathAttributeInterface, 0, len(update.PathAttributes))
var reach *bgp.PathAttributeMpReachNLRI
for _, attr := range update.PathAttributes {
switch a := attr.(type) {
case *bgp.PathAttributeMpReachNLRI:
reach = a
case *bgp.PathAttributeMpUnreachNLRI:
l := make([]bgp.AddrPrefixInterface, 0, len(a.Value))
l = append(l, a.Value...)
dels = append(dels, l...)
default:
attrs = append(attrs, attr)
}
}
listLen := len(adds) + len(dels)
if reach != nil {
listLen += len(reach.Value)
}
var hash uint32
if len(adds) > 0 || reach != nil {
total := bytes.NewBuffer(make([]byte, 0))
for _, a := range attrs {
b, _ := a.Serialize()
total.Write(b)
}
hash = farm.Hash32(total.Bytes())
}
pathList := make([]*Path, 0, listLen)
for _, nlri := range adds {
p := NewPath(peerInfo, nlri, false, attrs, timestamp, false)
p.SetHash(hash)
pathList = append(pathList, p)
}
if reach != nil {
reachAttrs := make([]bgp.PathAttributeInterface, len(attrs)+1)
copy(reachAttrs, attrs)
// we sort attributes when creating a bgp message from paths
reachAttrs[len(reachAttrs)-1] = reach
for _, nlri := range reach.Value {
p := NewPath(peerInfo, nlri, false, reachAttrs, timestamp, false)
p.SetHash(hash)
pathList = append(pathList, p)
}
}
for _, nlri := range dels {
p := NewPath(peerInfo, nlri, true, []bgp.PathAttributeInterface{}, timestamp, false)
pathList = append(pathList, p)
}
return pathList
}
type TableManager struct {
Tables map[bgp.RouteFamily]*Table
Vrfs map[string]*Vrf
rfList []bgp.RouteFamily
}
func NewTableManager(rfList []bgp.RouteFamily) *TableManager {
t := &TableManager{
Tables: make(map[bgp.RouteFamily]*Table),
Vrfs: make(map[string]*Vrf),
rfList: rfList,
}
for _, rf := range rfList {
t.Tables[rf] = NewTable(rf)
}
return t
}
func (manager *TableManager) GetRFlist() []bgp.RouteFamily {
return manager.rfList
}
func (manager *TableManager) AddVrf(name string, id uint32, rd bgp.RouteDistinguisherInterface, importRt, exportRt []bgp.ExtendedCommunityInterface, info *PeerInfo) ([]*Path, error) {
if _, ok := manager.Vrfs[name]; ok {
return nil, fmt.Errorf("vrf %s already exists", name)
}
log.WithFields(log.Fields{
"Topic": "Vrf",
"Key": name,
"Rd": rd,
"ImportRt": importRt,
"ExportRt": exportRt,
}).Debugf("add vrf")
manager.Vrfs[name] = &Vrf{
Name: name,
Id: id,
Rd: rd,
ImportRt: importRt,
ExportRt: exportRt,
}
msgs := make([]*Path, 0, len(importRt))
nexthop := "0.0.0.0"
for _, target := range importRt {
nlri := bgp.NewRouteTargetMembershipNLRI(info.AS, target)
pattr := make([]bgp.PathAttributeInterface, 0, 2)
pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP))
pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
msgs = append(msgs, NewPath(info, nlri, false, pattr, time.Now(), false))
}
return msgs, nil
}
func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) {
if _, ok := manager.Vrfs[name]; !ok {
return nil, fmt.Errorf("vrf %s not found", name)
}
msgs := make([]*Path, 0)
vrf := manager.Vrfs[name]
for _, t := range manager.Tables {
msgs = append(msgs, t.deletePathsByVrf(vrf)...)
}
log.WithFields(log.Fields{
"Topic": "Vrf",
"Key": vrf.Name,
"Rd": vrf.Rd,
"ImportRt": vrf.ImportRt,
"ExportRt": vrf.ExportRt,
}).Debugf("delete vrf")
delete(manager.Vrfs, name)
rtcTable := manager.Tables[bgp.RF_RTC_UC]
msgs = append(msgs, rtcTable.deleteRTCPathsByVrf(vrf, manager.Vrfs)...)
return msgs, nil
}
func (tm *TableManager) update(newPath *Path) *Update {
t := tm.Tables[newPath.GetRouteFamily()]
t.validatePath(newPath)
dst := t.getOrCreateDest(newPath.GetNlri())
u := dst.Calculate(newPath)
if len(dst.knownPathList) == 0 {
t.deleteDest(dst)
}
return u
}
func (manager *TableManager) GetPathListByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Path {
if t, ok := manager.Tables[rf]; ok {
pathList := make([]*Path, 0, len(t.destinations))
for _, dst := range t.destinations {
for _, p := range dst.knownPathList {
if p.GetSource().Equal(info) {
pathList = append(pathList, p)
}
}
}
return pathList
}
return nil
}
func (manager *TableManager) Update(newPath *Path) []*Update {
if newPath == nil || newPath.IsEOR() {
return nil
}
// Except for a special case with EVPN, we'll have one destination.
updates := make([]*Update, 0, 1)
family := newPath.GetRouteFamily()
if _, ok := manager.Tables[family]; ok {
updates = append(updates, manager.update(newPath))
if family == bgp.RF_EVPN {
for _, p := range manager.handleMacMobility(newPath) {
updates = append(updates, manager.update(p))
}
}
}
return updates
}
// EVPN MAC MOBILITY HANDLING
//
// RFC7432 15. MAC Mobility
//
// A PE receiving a MAC/IP Advertisement route for a MAC address with a
// different Ethernet segment identifier and a higher sequence number
// than that which it had previously advertised withdraws its MAC/IP
// Advertisement route.
func (manager *TableManager) handleMacMobility(path *Path) []*Path {
pathList := make([]*Path, 0)
nlri := path.GetNlri().(*bgp.EVPNNLRI)
if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
return nil
}
for _, path2 := range manager.GetPathList(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}) {
if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
continue
}
f := func(p *Path) (bgp.EthernetSegmentIdentifier, net.HardwareAddr, int) {
nlri := p.GetNlri().(*bgp.EVPNNLRI)
d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
ecs := p.GetExtCommunities()
seq := -1
for _, ec := range ecs {
if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY {
seq = int(ec.(*bgp.MacMobilityExtended).Sequence)
break
}
}
return d.ESI, d.MacAddress, seq
}
e1, m1, s1 := f(path)
e2, m2, s2 := f(path2)
if bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) && s1 > s2 {
pathList = append(pathList, path2.Clone(true))
}
}
return pathList
}
func (manager *TableManager) tables(list ...bgp.RouteFamily) []*Table {
l := make([]*Table, 0, len(manager.Tables))
if len(list) == 0 {
for _, v := range manager.Tables {
l = append(l, v)
}
return l
}
for _, f := range list {
if t, ok := manager.Tables[f]; ok {
l = append(l, t)
}
}
return l
}
func (manager *TableManager) getDestinationCount(rfList []bgp.RouteFamily) int {
count := 0
for _, t := range manager.tables(rfList...) {
count += len(t.GetDestinations())
}
return count
}
func (manager *TableManager) GetBestPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
if SelectionOptions.DisableBestPathSelection {
// Note: If best path selection disabled, there is no best path.
return nil
}
paths := make([]*Path, 0, manager.getDestinationCount(rfList))
for _, t := range manager.tables(rfList...) {
paths = append(paths, t.Bests(id, as)...)
}
return paths
}
func (manager *TableManager) GetBestMultiPathList(id string, rfList []bgp.RouteFamily) [][]*Path {
if !UseMultiplePaths.Enabled || SelectionOptions.DisableBestPathSelection {
// Note: If multi path not enabled or best path selection disabled,
// there is no best multi path.
return nil
}
paths := make([][]*Path, 0, manager.getDestinationCount(rfList))
for _, t := range manager.tables(rfList...) {
paths = append(paths, t.MultiBests(id)...)
}
return paths
}
func (manager *TableManager) GetPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
paths := make([]*Path, 0, manager.getDestinationCount(rfList))
for _, t := range manager.tables(rfList...) {
paths = append(paths, t.GetKnownPathList(id, as)...)
}
return paths
}
func (manager *TableManager) GetPathListWithNexthop(id string, rfList []bgp.RouteFamily, nexthop net.IP) []*Path {
paths := make([]*Path, 0, manager.getDestinationCount(rfList))
for _, rf := range rfList {
if t, ok := manager.Tables[rf]; ok {
for _, path := range t.GetKnownPathList(id, 0) {
if path.GetNexthop().Equal(nexthop) {
paths = append(paths, path)
}
}
}
}
return paths
}
func (manager *TableManager) GetPathListWithSource(id string, rfList []bgp.RouteFamily, source *PeerInfo) []*Path {
paths := make([]*Path, 0, manager.getDestinationCount(rfList))
for _, rf := range rfList {
if t, ok := manager.Tables[rf]; ok {
for _, path := range t.GetKnownPathList(id, 0) {
if path.GetSource().Equal(source) {
paths = append(paths, path)
}
}
}
}
return paths
}
func (manager *TableManager) GetDestination(path *Path) *Destination {
if path == nil {
return nil
}
family := path.GetRouteFamily()
t, ok := manager.Tables[family]
if !ok {
return nil
}
return t.GetDestination(path.GetNlri())
}
func (manager *TableManager) TableInfo(id string, as uint32, family bgp.RouteFamily) (*TableInfo, error) {
t, ok := manager.Tables[family]
if !ok {
return nil, fmt.Errorf("address family %s is not configured", family)
}
return t.Info(id, as), nil
}

53
vendor/github.com/osrg/gobgp/internal/pkg/table/vrf.go generated vendored Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package table
import (
"github.com/osrg/gobgp/pkg/packet/bgp"
)
type Vrf struct {
Name string
Id uint32
Rd bgp.RouteDistinguisherInterface
ImportRt []bgp.ExtendedCommunityInterface
ExportRt []bgp.ExtendedCommunityInterface
}
func (v *Vrf) Clone() *Vrf {
f := func(rt []bgp.ExtendedCommunityInterface) []bgp.ExtendedCommunityInterface {
l := make([]bgp.ExtendedCommunityInterface, 0, len(rt))
return append(l, rt...)
}
return &Vrf{
Name: v.Name,
Id: v.Id,
Rd: v.Rd,
ImportRt: f(v.ImportRt),
ExportRt: f(v.ExportRt),
}
}
func isLastTargetUser(vrfs map[string]*Vrf, target bgp.ExtendedCommunityInterface) bool {
for _, vrf := range vrfs {
for _, rt := range vrf.ImportRt {
if target.String() == rt.String() {
return false
}
}
}
return true
}

View File

@@ -0,0 +1,17 @@
// Code generated by "stringer -type=AFI"; DO NOT EDIT.
package zebra
import "strconv"
const _AFI_name = "AFI_IPAFI_IP6AFI_ETHERAFI_MAX"
var _AFI_index = [...]uint8{0, 6, 13, 22, 29}
func (i AFI) String() string {
i -= 1
if i >= AFI(len(_AFI_index)-1) {
return "AFI(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _AFI_name[_AFI_index[i]:_AFI_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=API_TYPE"; DO NOT EDIT.
package zebra
import "strconv"
const _API_TYPE_name = "FRR_ZAPI5_INTERFACE_ADDFRR_ZAPI5_INTERFACE_DELETEFRR_ZAPI5_INTERFACE_ADDRESS_ADDFRR_ZAPI5_INTERFACE_ADDRESS_DELETEFRR_ZAPI5_INTERFACE_UPFRR_ZAPI5_INTERFACE_DOWNFRR_ZAPI5_INTERFACE_SET_MASTERFRR_ZAPI5_ROUTE_ADDFRR_ZAPI5_ROUTE_DELETEFRR_ZAPI5_ROUTE_NOTIFY_OWNERFRR_ZAPI5_IPV4_ROUTE_ADDFRR_ZAPI5_IPV4_ROUTE_DELETEFRR_ZAPI5_IPV6_ROUTE_ADDFRR_ZAPI5_IPV6_ROUTE_DELETEFRR_ZAPI5_REDISTRIBUTE_ADDFRR_ZAPI5_REDISTRIBUTE_DELETEFRR_ZAPI5_REDISTRIBUTE_DEFAULT_ADDFRR_ZAPI5_REDISTRIBUTE_DEFAULT_DELETEFRR_ZAPI5_ROUTER_ID_ADDFRR_ZAPI5_ROUTER_ID_DELETEFRR_ZAPI5_ROUTER_ID_UPDATEFRR_ZAPI5_HELLOFRR_ZAPI5_CAPABILITIESFRR_ZAPI5_NEXTHOP_REGISTERFRR_ZAPI5_NEXTHOP_UNREGISTERFRR_ZAPI5_NEXTHOP_UPDATEFRR_ZAPI5_INTERFACE_NBR_ADDRESS_ADDFRR_ZAPI5_INTERFACE_NBR_ADDRESS_DELETEFRR_ZAPI5_INTERFACE_BFD_DEST_UPDATEFRR_ZAPI5_IMPORT_ROUTE_REGISTERFRR_ZAPI5_IMPORT_ROUTE_UNREGISTERFRR_ZAPI5_IMPORT_CHECK_UPDATEFRR_ZAPI5_IPV4_ROUTE_IPV6_NEXTHOP_ADDFRR_ZAPI5_BFD_DEST_REGISTERFRR_ZAPI5_BFD_DEST_DEREGISTERFRR_ZAPI5_BFD_DEST_UPDATEFRR_ZAPI5_BFD_DEST_REPLAYFRR_ZAPI5_REDISTRIBUTE_ROUTE_ADDFRR_ZAPI5_REDISTRIBUTE_ROUTE_DELFRR_ZAPI5_VRF_UNREGISTERFRR_ZAPI5_VRF_ADDFRR_ZAPI5_VRF_DELETEFRR_ZAPI5_VRF_LABELFRR_ZAPI5_INTERFACE_VRF_UPDATEFRR_ZAPI5_BFD_CLIENT_REGISTERFRR_ZAPI5_INTERFACE_ENABLE_RADVFRR_ZAPI5_INTERFACE_DISABLE_RADVFRR_ZAPI5_IPV4_NEXTHOP_LOOKUP_MRIBFRR_ZAPI5_INTERFACE_LINK_PARAMSFRR_ZAPI5_MPLS_LABELS_ADDFRR_ZAPI5_MPLS_LABELS_DELETEFRR_ZAPI5_IPMR_ROUTE_STATSFRR_ZAPI5_LABEL_MANAGER_CONNECTFRR_ZAPI5_GET_LABEL_CHUNKFRR_ZAPI5_RELEASE_LABEL_CHUNKFRR_ZAPI5_FEC_REGISTERFRR_ZAPI5_FEC_UNREGISTERFRR_ZAPI5_FEC_UPDATEFRR_ZAPI5_ADVERTISE_DEFAULT_GWFRR_ZAPI5_ADVERTISE_SUBNETFRR_ZAPI5_ADVERTISE_ALL_VNIFRR_ZAPI5_VNI_ADDFRR_ZAPI5_VNI_DELFRR_ZAPI5_L3VNI_ADDFRR_ZAPI5_L3VNI_DELFRR_ZAPI5_REMOTE_VTEP_ADDFRR_ZAPI5_REMOTE_VTEP_DELFRR_ZAPI5_MACIP_ADDFRR_ZAPI5_MACIP_DELFRR_ZAPI5_IP_PREFIX_ROUTE_ADDFRR_ZAPI5_IP_PREFIX_ROUTE_DELFRR_ZAPI5_REMOTE_MACIP_ADDFRR_ZAPI5_REMOTE_MACIP_DELFRR_ZAPI5_PW_ADDFRR_ZAPI5_PW_DELETEFRR_ZAPI5_PW_SETFRR_ZAPI5_PW_UNSETFRR_ZAPI5_PW_STATUS_UPDATEFRR_ZAPI5_RULE_ADDFRR_ZAPI5_RULE_DELETEFRR_ZAPI5_RULE_NOTIFY_OWNERFRR_ZAPI5_TABLE_MANAGER_CONNECTFRR_ZAPI5_GET_TABLE_CHUNKFRR_ZAPI5_RELEASE_TABLE_CHUNKFRR_ZAPI5_IPSET_CREATEFRR_ZAPI5_IPSET_DESTROYFRR_ZAPI5_IPSET_ENTRY_ADDFRR_ZAPI5_IPSET_ENTRY_DELETEFRR_ZAPI5_IPSET_NOTIFY_OWNERFRR_ZAPI5_IPSET_ENTRY_NOTIFY_OWNERFRR_ZAPI5_IPTABLE_ADDFRR_ZAPI5_IPTABLE_DELETEFRR_ZAPI5_IPTABLE_NOTIFY_OWNER"
var _API_TYPE_index = [...]uint16{0, 23, 49, 80, 114, 136, 160, 190, 209, 231, 259, 283, 310, 334, 361, 387, 416, 450, 487, 510, 536, 562, 577, 599, 625, 653, 677, 712, 750, 785, 816, 849, 878, 915, 942, 971, 996, 1021, 1053, 1085, 1109, 1126, 1146, 1165, 1195, 1224, 1255, 1287, 1321, 1352, 1377, 1405, 1431, 1462, 1487, 1516, 1538, 1562, 1582, 1612, 1638, 1665, 1682, 1699, 1718, 1737, 1762, 1787, 1806, 1825, 1854, 1883, 1909, 1935, 1951, 1970, 1986, 2004, 2030, 2048, 2069, 2096, 2127, 2152, 2181, 2203, 2226, 2251, 2279, 2307, 2341, 2362, 2386, 2416}
func (i API_TYPE) String() string {
if i >= API_TYPE(len(_API_TYPE_index)-1) {
return "API_TYPE(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _API_TYPE_name[_API_TYPE_index[i]:_API_TYPE_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=LINK_TYPE"; DO NOT EDIT.
package zebra
import "strconv"
const _LINK_TYPE_name = "LINK_TYPE_UNKNOWNLINK_TYPE_ETHERLINK_TYPE_EETHERLINK_TYPE_AX25LINK_TYPE_PRONETLINK_TYPE_IEEE802LINK_TYPE_ARCNETLINK_TYPE_APPLETLKLINK_TYPE_DLCILINK_TYPE_ATMLINK_TYPE_METRICOMLINK_TYPE_IEEE1394LINK_TYPE_EUI64LINK_TYPE_INFINIBANDLINK_TYPE_SLIPLINK_TYPE_CSLIPLINK_TYPE_SLIP6LINK_TYPE_CSLIP6LINK_TYPE_RSRVDLINK_TYPE_ADAPTLINK_TYPE_ROSELINK_TYPE_X25LINK_TYPE_PPPLINK_TYPE_CHDLCLINK_TYPE_LAPBLINK_TYPE_RAWHDLCLINK_TYPE_IPIPLINK_TYPE_IPIP6LINK_TYPE_FRADLINK_TYPE_SKIPLINK_TYPE_LOOPBACKLINK_TYPE_LOCALTLKLINK_TYPE_FDDILINK_TYPE_SITLINK_TYPE_IPDDPLINK_TYPE_IPGRELINK_TYPE_IP6GRELINK_TYPE_PIMREGLINK_TYPE_HIPPILINK_TYPE_ECONETLINK_TYPE_IRDALINK_TYPE_FCPPLINK_TYPE_FCALLINK_TYPE_FCPLLINK_TYPE_FCFABRICLINK_TYPE_IEEE802_TRLINK_TYPE_IEEE80211LINK_TYPE_IEEE80211_RADIOTAPLINK_TYPE_IEEE802154LINK_TYPE_IEEE802154_PHY"
var _LINK_TYPE_index = [...]uint16{0, 17, 32, 48, 62, 78, 95, 111, 129, 143, 156, 174, 192, 207, 227, 241, 256, 271, 287, 302, 317, 331, 344, 357, 372, 386, 403, 417, 432, 446, 460, 478, 496, 510, 523, 538, 553, 569, 585, 600, 616, 630, 644, 658, 672, 690, 710, 729, 757, 777, 801}
func (i LINK_TYPE) String() string {
if i >= LINK_TYPE(len(_LINK_TYPE_index)-1) {
return "LINK_TYPE(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _LINK_TYPE_name[_LINK_TYPE_index[i]:_LINK_TYPE_index[i+1]]
}

View File

@@ -0,0 +1,41 @@
// Code generated by "stringer -type=NEXTHOP_FLAG"; DO NOT EDIT.
package zebra
import "strconv"
const (
_NEXTHOP_FLAG_name_0 = "NEXTHOP_FLAG_ACTIVENEXTHOP_FLAG_FIB"
_NEXTHOP_FLAG_name_1 = "NEXTHOP_FLAG_RECURSIVE"
_NEXTHOP_FLAG_name_2 = "NEXTHOP_FLAG_ONLINK"
_NEXTHOP_FLAG_name_3 = "NEXTHOP_FLAG_MATCHED"
_NEXTHOP_FLAG_name_4 = "NEXTHOP_FLAG_FILTERED"
_NEXTHOP_FLAG_name_5 = "NEXTHOP_FLAG_DUPLICATE"
_NEXTHOP_FLAG_name_6 = "NEXTHOP_FLAG_EVPN_RVTEP"
)
var (
_NEXTHOP_FLAG_index_0 = [...]uint8{0, 19, 35}
)
func (i NEXTHOP_FLAG) String() string {
switch {
case 1 <= i && i <= 2:
i -= 1
return _NEXTHOP_FLAG_name_0[_NEXTHOP_FLAG_index_0[i]:_NEXTHOP_FLAG_index_0[i+1]]
case i == 4:
return _NEXTHOP_FLAG_name_1
case i == 8:
return _NEXTHOP_FLAG_name_2
case i == 16:
return _NEXTHOP_FLAG_name_3
case i == 32:
return _NEXTHOP_FLAG_name_4
case i == 64:
return _NEXTHOP_FLAG_name_5
case i == 128:
return _NEXTHOP_FLAG_name_6
default:
return "NEXTHOP_FLAG(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

View File

@@ -0,0 +1,17 @@
// Code generated by "stringer -type=NEXTHOP_TYPE"; DO NOT EDIT.
package zebra
import "strconv"
const _NEXTHOP_TYPE_name = "FRR_NEXTHOP_TYPE_IFINDEXFRR_NEXTHOP_TYPE_IPV4FRR_NEXTHOP_TYPE_IPV4_IFINDEXFRR_NEXTHOP_TYPE_IPV6FRR_NEXTHOP_TYPE_IPV6_IFINDEXFRR_NEXTHOP_TYPE_BLACKHOLENEXTHOP_TYPE_IPV6_IFINDEXNEXTHOP_TYPE_IPV6_IFNAMENEXTHOP_TYPE_BLACKHOLE"
var _NEXTHOP_TYPE_index = [...]uint8{0, 24, 45, 74, 95, 124, 150, 175, 199, 221}
func (i NEXTHOP_TYPE) String() string {
i -= 1
if i >= NEXTHOP_TYPE(len(_NEXTHOP_TYPE_index)-1) {
return "NEXTHOP_TYPE(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _NEXTHOP_TYPE_name[_NEXTHOP_TYPE_index[i]:_NEXTHOP_TYPE_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=PTM_ENABLE"; DO NOT EDIT.
package zebra
import "strconv"
const _PTM_ENABLE_name = "PTM_ENABLE_OFFPTM_ENABLE_ONPTM_ENABLE_UNSPEC"
var _PTM_ENABLE_index = [...]uint8{0, 14, 27, 44}
func (i PTM_ENABLE) String() string {
if i >= PTM_ENABLE(len(_PTM_ENABLE_index)-1) {
return "PTM_ENABLE(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _PTM_ENABLE_name[_PTM_ENABLE_index[i]:_PTM_ENABLE_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=PTM_STATUS"; DO NOT EDIT.
package zebra
import "strconv"
const _PTM_STATUS_name = "PTM_STATUS_DOWNPTM_STATUS_UPPTM_STATUS_UNKNOWN"
var _PTM_STATUS_index = [...]uint8{0, 15, 28, 46}
func (i PTM_STATUS) String() string {
if i >= PTM_STATUS(len(_PTM_STATUS_index)-1) {
return "PTM_STATUS(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _PTM_STATUS_name[_PTM_STATUS_index[i]:_PTM_STATUS_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=ROUTE_TYPE"; DO NOT EDIT.
package zebra
import "strconv"
const _ROUTE_TYPE_name = "FRR_ZAPI5_ROUTE_SYSTEMFRR_ZAPI5_ROUTE_KERNELFRR_ZAPI5_ROUTE_CONNECTFRR_ZAPI5_ROUTE_STATICFRR_ZAPI5_ROUTE_RIPFRR_ZAPI5_ROUTE_RIPNGFRR_ZAPI5_ROUTE_OSPFFRR_ZAPI5_ROUTE_OSPF6FRR_ZAPI5_ROUTE_ISISFRR_ZAPI5_ROUTE_BGPFRR_ZAPI5_ROUTE_PIMFRR_ZAPI5_ROUTE_EIGRPFRR_ZAPI5_ROUTE_NHRPFRR_ZAPI5_ROUTE_HSLSFRR_ZAPI5_ROUTE_OLSRFRR_ZAPI5_ROUTE_TABLEFRR_ZAPI5_ROUTE_LDPFRR_ZAPI5_ROUTE_VNCFRR_ZAPI5_ROUTE_VNC_DIRECTFRR_ZAPI5_ROUTE_VNC_DIRECT_RHFRR_ZAPI5_ROUTE_BGP_DIRECTFRR_ZAPI5_ROUTE_BGP_DIRECT_EXTFRR_ZAPI5_ROUTE_BABELFRR_ZAPI5_ROUTE_SHARPFRR_ZAPI5_ROUTE_PBRFRR_ZAPI5_ROUTE_ALLFRR_ZAPI5_ROUTE_MAX"
var _ROUTE_TYPE_index = [...]uint16{0, 22, 44, 67, 89, 108, 129, 149, 170, 190, 209, 228, 249, 269, 289, 309, 330, 349, 368, 394, 423, 449, 479, 500, 521, 540, 559, 578}
func (i ROUTE_TYPE) String() string {
if i >= ROUTE_TYPE(len(_ROUTE_TYPE_index)-1) {
return "ROUTE_TYPE(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ROUTE_TYPE_name[_ROUTE_TYPE_index[i]:_ROUTE_TYPE_index[i+1]]
}

View File

@@ -0,0 +1,17 @@
// Code generated by "stringer -type=SAFI"; DO NOT EDIT.
package zebra
import "strconv"
const _SAFI_name = "SAFI_UNICASTSAFI_MULTICASTSAFI_RESERVED_3SAFI_MPLS_VPNSAFI_MAX"
var _SAFI_index = [...]uint8{0, 12, 26, 41, 54, 62}
func (i SAFI) String() string {
i -= 1
if i >= SAFI(len(_SAFI_index)-1) {
return "SAFI(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _SAFI_name[_SAFI_index[i]:_SAFI_index[i+1]]
}

2534
vendor/github.com/osrg/gobgp/internal/pkg/zebra/zapi.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build freebsd netbsd openbsd
package zebra
import (
"strings"
"syscall"
)
func intfflag2string(flag uint64) string {
ss := make([]string, 0, 10)
if flag&syscall.IFF_UP > 0 {
ss = append(ss, "UP")
}
if flag&syscall.IFF_BROADCAST > 0 {
ss = append(ss, "BROADCAST")
}
if flag&syscall.IFF_DEBUG > 0 {
ss = append(ss, "DEBUG")
}
if flag&syscall.IFF_LOOPBACK > 0 {
ss = append(ss, "LOOPBACK")
}
if flag&syscall.IFF_POINTOPOINT > 0 {
ss = append(ss, "POINTOPOINT")
}
if flag&syscall.IFF_RUNNING > 0 {
ss = append(ss, "RUNNING")
}
if flag&syscall.IFF_NOARP > 0 {
ss = append(ss, "NOARP")
}
if flag&syscall.IFF_PROMISC > 0 {
ss = append(ss, "PROMISC")
}
if flag&syscall.IFF_ALLMULTI > 0 {
ss = append(ss, "ALLMULTI")
}
if flag&syscall.IFF_MULTICAST > 0 {
ss = append(ss, "MULTICAST")
}
return strings.Join(ss, " | ")
}

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package zebra
import (
"strings"
"syscall"
)
func intfflag2string(flag uint64) string {
ss := make([]string, 0, 10)
if flag&syscall.IFF_UP > 0 {
ss = append(ss, "UP")
}
if flag&syscall.IFF_BROADCAST > 0 {
ss = append(ss, "BROADCAST")
}
if flag&syscall.IFF_DEBUG > 0 {
ss = append(ss, "DEBUG")
}
if flag&syscall.IFF_LOOPBACK > 0 {
ss = append(ss, "LOOPBACK")
}
if flag&syscall.IFF_POINTOPOINT > 0 {
ss = append(ss, "POINTOPOINT")
}
if flag&syscall.IFF_NOTRAILERS > 0 {
ss = append(ss, "NOTRAILERS")
}
if flag&syscall.IFF_RUNNING > 0 {
ss = append(ss, "RUNNING")
}
if flag&syscall.IFF_NOARP > 0 {
ss = append(ss, "NOARP")
}
if flag&syscall.IFF_PROMISC > 0 {
ss = append(ss, "PROMISC")
}
if flag&syscall.IFF_ALLMULTI > 0 {
ss = append(ss, "ALLMULTI")
}
if flag&syscall.IFF_MULTICAST > 0 {
ss = append(ss, "MULTICAST")
}
return strings.Join(ss, " | ")
}

View File

@@ -0,0 +1,83 @@
// Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package zebra
import (
"strings"
"syscall"
)
func intfflag2string(flag uint64) string {
ss := make([]string, 0, 10)
if flag&syscall.IFF_UP > 0 {
ss = append(ss, "UP")
}
if flag&syscall.IFF_BROADCAST > 0 {
ss = append(ss, "BROADCAST")
}
if flag&syscall.IFF_DEBUG > 0 {
ss = append(ss, "DEBUG")
}
if flag&syscall.IFF_LOOPBACK > 0 {
ss = append(ss, "LOOPBACK")
}
if flag&syscall.IFF_POINTOPOINT > 0 {
ss = append(ss, "POINTOPOINT")
}
if flag&syscall.IFF_NOTRAILERS > 0 {
ss = append(ss, "NOTRAILERS")
}
if flag&syscall.IFF_RUNNING > 0 {
ss = append(ss, "RUNNING")
}
if flag&syscall.IFF_NOARP > 0 {
ss = append(ss, "NOARP")
}
if flag&syscall.IFF_PROMISC > 0 {
ss = append(ss, "PROMISC")
}
if flag&syscall.IFF_ALLMULTI > 0 {
ss = append(ss, "ALLMULTI")
}
if flag&syscall.IFF_MASTER > 0 {
ss = append(ss, "MASTER")
}
if flag&syscall.IFF_SLAVE > 0 {
ss = append(ss, "SLAVE")
}
if flag&syscall.IFF_MULTICAST > 0 {
ss = append(ss, "MULTICAST")
}
if flag&syscall.IFF_PORTSEL > 0 {
ss = append(ss, "PORTSEL")
}
if flag&syscall.IFF_AUTOMEDIA > 0 {
ss = append(ss, "AUTOMEDIA")
}
if flag&syscall.IFF_DYNAMIC > 0 {
ss = append(ss, "DYNAMIC")
}
// if flag&syscall.IFF_LOWER_UP > 0 {
// ss = append(ss, "LOWER_UP")
// }
// if flag&syscall.IFF_DORMANT > 0 {
// ss = append(ss, "DORMANT")
// }
// if flag&syscall.IFF_ECHO > 0 {
// ss = append(ss, "ECHO")
// }
return strings.Join(ss, " | ")
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package zebra
import (
"strings"
"syscall"
)
func intfflag2string(flag uint64) string {
ss := make([]string, 0, 10)
if flag&syscall.IFF_UP > 0 {
ss = append(ss, "UP")
}
if flag&syscall.IFF_BROADCAST > 0 {
ss = append(ss, "BROADCAST")
}
if flag&syscall.IFF_LOOPBACK > 0 {
ss = append(ss, "LOOPBACK")
}
if flag&syscall.IFF_MULTICAST > 0 {
ss = append(ss, "MULTICAST")
}
return strings.Join(ss, " | ")
}

9677
vendor/github.com/osrg/gobgp/pkg/packet/bgp/bgp.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
// generated by stringer -type BGPAttrType bgp.go; DO NOT EDIT
package bgp
import "fmt"
const (
_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"
_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"
)
var (
_BGPAttrType_index_0 = [...]uint8{0, 20, 41, 63, 92, 116, 146, 170, 195, 222, 248}
_BGPAttrType_index_1 = [...]uint8{0, 27, 56, 90, 112, 140}
)
func (i BGPAttrType) String() string {
switch {
case 1 <= i && i <= 10:
i -= 1
return _BGPAttrType_name_0[_BGPAttrType_index_0[i]:_BGPAttrType_index_0[i+1]]
case 14 <= i && i <= 18:
i -= 14
return _BGPAttrType_name_1[_BGPAttrType_index_1[i]:_BGPAttrType_index_1[i+1]]
default:
return fmt.Sprintf("BGPAttrType(%d)", i)
}
}

327
vendor/github.com/osrg/gobgp/pkg/packet/bgp/constant.go generated vendored Normal file
View File

@@ -0,0 +1,327 @@
// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bgp
import (
"fmt"
"strings"
)
const AS_TRANS = 23456
const BGP_PORT = 179
type FSMState int
const (
BGP_FSM_IDLE FSMState = iota
BGP_FSM_CONNECT
BGP_FSM_ACTIVE
BGP_FSM_OPENSENT
BGP_FSM_OPENCONFIRM
BGP_FSM_ESTABLISHED
)
// partially taken from http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
type Protocol int
const (
Unknown Protocol = iota
ICMP = 0x01
IGMP = 0x02
TCP = 0x06
EGP = 0x08
IGP = 0x09
UDP = 0x11
RSVP = 0x2e
GRE = 0x2f
OSPF = 0x59
IPIP = 0x5e
PIM = 0x67
SCTP = 0x84
)
var ProtocolNameMap = map[Protocol]string{
Unknown: "unknown",
ICMP: "icmp",
IGMP: "igmp",
TCP: "tcp",
EGP: "egp",
IGP: "igp",
UDP: "udp",
RSVP: "rsvp",
GRE: "gre",
OSPF: "ospf",
IPIP: "ipip",
PIM: "pim",
SCTP: "sctp",
}
func (p Protocol) String() string {
name, ok := ProtocolNameMap[p]
if !ok {
return fmt.Sprintf("%d", p)
}
return name
}
type TCPFlag int
const (
_ TCPFlag = iota
TCP_FLAG_FIN = 0x01
TCP_FLAG_SYN = 0x02
TCP_FLAG_RST = 0x04
TCP_FLAG_PUSH = 0x08
TCP_FLAG_ACK = 0x10
TCP_FLAG_URGENT = 0x20
TCP_FLAG_ECE = 0x40
TCP_FLAG_CWR = 0x80
)
var TCPFlagNameMap = map[TCPFlag]string{
TCP_FLAG_FIN: "F",
TCP_FLAG_SYN: "S",
TCP_FLAG_RST: "R",
TCP_FLAG_PUSH: "P",
TCP_FLAG_ACK: "A",
TCP_FLAG_URGENT: "U",
TCP_FLAG_CWR: "C",
TCP_FLAG_ECE: "E",
}
// Prepares a sorted list of flags because map iterations does not happen
// in a consistent order in Golang.
var TCPSortedFlags = []TCPFlag{
TCP_FLAG_FIN,
TCP_FLAG_SYN,
TCP_FLAG_RST,
TCP_FLAG_PUSH,
TCP_FLAG_ACK,
TCP_FLAG_URGENT,
TCP_FLAG_ECE,
TCP_FLAG_CWR,
}
func (f TCPFlag) String() string {
flags := make([]string, 0, len(TCPSortedFlags))
for _, v := range TCPSortedFlags {
if f&v > 0 {
flags = append(flags, TCPFlagNameMap[v])
}
}
return strings.Join(flags, "")
}
type BitmaskFlagOp uint8
const (
BITMASK_FLAG_OP_OR BitmaskFlagOp = iota
BITMASK_FLAG_OP_MATCH = 0x01
BITMASK_FLAG_OP_NOT = 0x02
BITMASK_FLAG_OP_NOT_MATCH = 0x03
BITMASK_FLAG_OP_AND = 0x40
BITMASK_FLAG_OP_END = 0x80
)
var BitmaskFlagOpNameMap = map[BitmaskFlagOp]string{
BITMASK_FLAG_OP_OR: " ",
BITMASK_FLAG_OP_AND: "&",
BITMASK_FLAG_OP_END: "E",
BITMASK_FLAG_OP_NOT: "!",
BITMASK_FLAG_OP_MATCH: "=",
}
// Note: Meaning of "" is different from that of the numeric operator because
// RFC5575 says if the Match bit in the bitmask operand is set, it should be
// "strictly" matching against the given value.
var BitmaskFlagOpValueMap = map[string]BitmaskFlagOp{
" ": BITMASK_FLAG_OP_OR,
"": BITMASK_FLAG_OP_OR,
"==": BITMASK_FLAG_OP_MATCH,
"=": BITMASK_FLAG_OP_MATCH,
"!": BITMASK_FLAG_OP_NOT,
"!=": BITMASK_FLAG_OP_NOT_MATCH,
"=!": BITMASK_FLAG_OP_NOT_MATCH, // For the backward compatibility
"&": BITMASK_FLAG_OP_AND,
"E": BITMASK_FLAG_OP_END,
}
func (f BitmaskFlagOp) String() string {
ops := make([]string, 0)
if f&BITMASK_FLAG_OP_AND > 0 {
ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND])
} else {
ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR])
}
if f&BITMASK_FLAG_OP_NOT > 0 {
ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT])
}
if f&BITMASK_FLAG_OP_MATCH > 0 {
ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH])
}
return strings.Join(ops, "")
}
type FragmentFlag int
const (
FRAG_FLAG_NOT FragmentFlag = iota
FRAG_FLAG_DONT = 0x01
FRAG_FLAG_IS = 0x02
FRAG_FLAG_FIRST = 0x04
FRAG_FLAG_LAST = 0x08
)
var FragmentFlagNameMap = map[FragmentFlag]string{
FRAG_FLAG_NOT: "not-a-fragment",
FRAG_FLAG_DONT: "dont-fragment",
FRAG_FLAG_IS: "is-fragment",
FRAG_FLAG_FIRST: "first-fragment",
FRAG_FLAG_LAST: "last-fragment",
}
// Prepares a sorted list of flags because map iterations does not happen
// in a consistent order in Golang.
var FragmentSortedFlags = []FragmentFlag{
FRAG_FLAG_NOT,
FRAG_FLAG_DONT,
FRAG_FLAG_IS,
FRAG_FLAG_FIRST,
FRAG_FLAG_LAST,
}
func (f FragmentFlag) String() string {
flags := make([]string, 0, len(FragmentSortedFlags))
for _, v := range FragmentSortedFlags {
if f&v > 0 {
flags = append(flags, FragmentFlagNameMap[v])
}
}
// Note: If multiple bits are set, joins them with "+".
return strings.Join(flags, "+")
}
type DECNumOp uint8
const (
DEC_NUM_OP_TRUE DECNumOp = iota // true always with END bit set
DEC_NUM_OP_EQ = 0x01
DEC_NUM_OP_GT = 0x02
DEC_NUM_OP_GT_EQ = 0x03
DEC_NUM_OP_LT = 0x04
DEC_NUM_OP_LT_EQ = 0x05
DEC_NUM_OP_NOT_EQ = 0x06
DEC_NUM_OP_FALSE = 0x07 // false always with END bit set
DEC_NUM_OP_OR = 0x00
DEC_NUM_OP_AND = 0x40
DEC_NUM_OP_END = 0x80
)
var DECNumOpNameMap = map[DECNumOp]string{
DEC_NUM_OP_TRUE: "true",
DEC_NUM_OP_EQ: "==",
DEC_NUM_OP_GT: ">",
DEC_NUM_OP_GT_EQ: ">=",
DEC_NUM_OP_LT: "<",
DEC_NUM_OP_LT_EQ: "<=",
DEC_NUM_OP_NOT_EQ: "!=",
DEC_NUM_OP_FALSE: "false",
//DEC_NUM_OP_OR: " ", // duplicate with DEC_NUM_OP_TRUE
DEC_NUM_OP_AND: "&",
DEC_NUM_OP_END: "E",
}
var DECNumOpValueMap = map[string]DECNumOp{
"true": DEC_NUM_OP_TRUE,
"": DEC_NUM_OP_EQ,
"==": DEC_NUM_OP_EQ,
"=": DEC_NUM_OP_EQ,
">": DEC_NUM_OP_GT,
">=": DEC_NUM_OP_GT_EQ,
"<": DEC_NUM_OP_LT,
"<=": DEC_NUM_OP_LT_EQ,
"!=": DEC_NUM_OP_NOT_EQ,
"=!": DEC_NUM_OP_NOT_EQ,
"!": DEC_NUM_OP_NOT_EQ,
"false": DEC_NUM_OP_FALSE,
" ": DEC_NUM_OP_OR,
"&": DEC_NUM_OP_AND,
"E": DEC_NUM_OP_END,
}
func (f DECNumOp) String() string {
ops := make([]string, 0)
logicFlag := DECNumOp(f & 0xc0) // higher 2 bits
if logicFlag&DEC_NUM_OP_AND > 0 {
ops = append(ops, DECNumOpNameMap[DEC_NUM_OP_AND])
} else {
ops = append(ops, " ") // DEC_NUM_OP_OR
}
// Omits DEC_NUM_OP_END
cmpFlag := DECNumOp(f & 0x7) // lower 3 bits
for v, s := range DECNumOpNameMap {
if cmpFlag == v {
ops = append(ops, s)
break
}
}
return strings.Join(ops, "")
}
// Potentially taken from https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
type EthernetType int
const (
IPv4 EthernetType = 0x0800
ARP EthernetType = 0x0806
RARP EthernetType = 0x8035
VMTP EthernetType = 0x805B
APPLE_TALK EthernetType = 0x809B
AARP EthernetType = 0x80F3
IPX EthernetType = 0x8137
SNMP EthernetType = 0x814C
NET_BIOS EthernetType = 0x8191
XTP EthernetType = 0x817D
IPv6 EthernetType = 0x86DD
PPPoE_DISCOVERY EthernetType = 0x8863
PPPoE_SESSION EthernetType = 0x8864
LOOPBACK EthernetType = 0x9000
)
var EthernetTypeNameMap = map[EthernetType]string{
IPv4: "ipv4",
ARP: "arp",
RARP: "rarp",
VMTP: "vmtp",
APPLE_TALK: "apple-talk",
AARP: "aarp",
IPX: "ipx",
SNMP: "snmp",
NET_BIOS: "net-bios",
XTP: "xtp",
IPv6: "ipv6",
PPPoE_DISCOVERY: "pppoe-discovery",
PPPoE_SESSION: "pppoe-session",
LOOPBACK: "loopback",
}
func (t EthernetType) String() string {
if name, ok := EthernetTypeNameMap[t]; ok {
return name
}
return fmt.Sprintf("%d", t)
}

View File

@@ -0,0 +1,16 @@
// generated by stringer -type=ESIType bgp.go validate.go; DO NOT EDIT
package bgp
import "fmt"
const _ESIType_name = "ESI_ARBITRARYESI_LACPESI_MSTPESI_MACESI_ROUTERIDESI_AS"
var _ESIType_index = [...]uint8{0, 13, 21, 29, 36, 48, 54}
func (i ESIType) String() string {
if i+1 >= ESIType(len(_ESIType_index)) {
return fmt.Sprintf("ESIType(%d)", i)
}
return _ESIType_name[_ESIType_index[i]:_ESIType_index[i+1]]
}

View File

@@ -0,0 +1,16 @@
// generated by stringer -type=FSMState -output=fsmstate_string.go bgp.go validate.go mrt.go rtr.go constant.go bmp.go esitype_string.go bgpattrtype_string.go; DO NOT EDIT
package bgp
import "fmt"
const _FSMState_name = "BGP_FSM_IDLEBGP_FSM_CONNECTBGP_FSM_ACTIVEBGP_FSM_OPENSENTBGP_FSM_OPENCONFIRMBGP_FSM_ESTABLISHED"
var _FSMState_index = [...]uint8{0, 12, 27, 41, 57, 76, 95}
func (i FSMState) String() string {
if i < 0 || i >= FSMState(len(_FSMState_index)-1) {
return fmt.Sprintf("FSMState(%d)", i)
}
return _FSMState_name[_FSMState_index[i]:_FSMState_index[i+1]]
}

126
vendor/github.com/osrg/gobgp/pkg/packet/bgp/helper.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bgp
func NewTestBGPOpenMessage() *BGPMessage {
p1 := NewOptionParameterCapability(
[]ParameterCapabilityInterface{NewCapRouteRefresh()})
p2 := NewOptionParameterCapability(
[]ParameterCapabilityInterface{NewCapMultiProtocol(RF_IPv4_UC)})
g := &CapGracefulRestartTuple{4, 2, 3}
p3 := NewOptionParameterCapability(
[]ParameterCapabilityInterface{NewCapGracefulRestart(false, true, 100,
[]*CapGracefulRestartTuple{g})})
p4 := NewOptionParameterCapability(
[]ParameterCapabilityInterface{NewCapFourOctetASNumber(100000)})
p5 := NewOptionParameterCapability(
[]ParameterCapabilityInterface{NewCapAddPath([]*CapAddPathTuple{NewCapAddPathTuple(RF_IPv4_UC, BGP_ADD_PATH_BOTH)})})
return NewBGPOpenMessage(11033, 303, "100.4.10.3",
[]OptionParameterInterface{p1, p2, p3, p4, p5})
}
func NewTestBGPUpdateMessage() *BGPMessage {
w1 := NewIPAddrPrefix(23, "121.1.3.2")
w2 := NewIPAddrPrefix(17, "100.33.3.0")
w := []*IPAddrPrefix{w1, w2}
aspath1 := []AsPathParamInterface{
NewAsPathParam(2, []uint16{1000}),
NewAsPathParam(1, []uint16{1001, 1002}),
NewAsPathParam(2, []uint16{1003, 1004}),
}
aspath2 := []AsPathParamInterface{
NewAs4PathParam(2, []uint32{1000000}),
NewAs4PathParam(1, []uint32{1000001, 1002}),
NewAs4PathParam(2, []uint32{1003, 100004}),
}
aspath3 := []*As4PathParam{
NewAs4PathParam(2, []uint32{1000000}),
NewAs4PathParam(1, []uint32{1000001, 1002}),
NewAs4PathParam(2, []uint32{1003, 100004}),
}
isTransitive := true
ecommunities := []ExtendedCommunityInterface{
NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 10003, 3<<20, isTransitive),
NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 1<<20, 300, isTransitive),
NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, "192.2.1.2", 3000, isTransitive),
NewOpaqueExtended(false, []byte{1, 2, 3, 4, 5, 6, 7}),
NewValidationExtended(VALIDATION_STATE_INVALID),
NewUnknownExtended(99, []byte{0, 1, 2, 3, 4, 5, 6, 7}),
NewESILabelExtended(1000, true),
NewESImportRouteTarget("11:22:33:44:55:66"),
NewMacMobilityExtended(123, false),
}
prefixes1 := []AddrPrefixInterface{
NewLabeledVPNIPAddrPrefix(24, "192.0.9.0", *NewMPLSLabelStack(1, 2, 3),
NewRouteDistinguisherTwoOctetAS(256, 10000)),
NewLabeledVPNIPAddrPrefix(24, "192.10.8.0", *NewMPLSLabelStack(5, 6, 7, 8),
NewRouteDistinguisherIPAddressAS("10.0.1.1", 10001)),
}
prefixes2 := []AddrPrefixInterface{NewIPv6AddrPrefix(128,
"fe80:1234:1234:5667:8967:af12:8912:1023")}
prefixes3 := []AddrPrefixInterface{NewLabeledVPNIPv6AddrPrefix(128,
"fe80:1234:1234:5667:8967:af12:1203:33a1", *NewMPLSLabelStack(5, 6),
NewRouteDistinguisherFourOctetAS(5, 6))}
prefixes4 := []AddrPrefixInterface{NewLabeledIPAddrPrefix(25, "192.168.0.0",
*NewMPLSLabelStack(5, 6, 7))}
prefixes5 := []AddrPrefixInterface{
NewEVPNEthernetAutoDiscoveryRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2),
NewEVPNMacIPAdvertisementRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 3, "01:23:45:67:89:ab", "192.2.1.2", []uint32{3, 4}),
NewEVPNMulticastEthernetTagRoute(NewRouteDistinguisherFourOctetAS(5, 6), 3, "192.2.1.2"),
NewEVPNEthernetSegmentRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, "192.2.1.1"),
NewEVPNIPPrefixRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 5, 24, "192.2.1.0", "192.3.1.1", 5),
}
p := []PathAttributeInterface{
NewPathAttributeOrigin(3),
NewPathAttributeAsPath(aspath1),
NewPathAttributeAsPath(aspath2),
NewPathAttributeNextHop("129.1.1.2"),
NewPathAttributeMultiExitDisc(1 << 20),
NewPathAttributeLocalPref(1 << 22),
NewPathAttributeAtomicAggregate(),
NewPathAttributeAggregator(uint16(30002), "129.0.2.99"),
NewPathAttributeAggregator(uint32(30002), "129.0.2.99"),
NewPathAttributeAggregator(uint32(300020), "129.0.2.99"),
NewPathAttributeCommunities([]uint32{1, 3}),
NewPathAttributeOriginatorId("10.10.0.1"),
NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}),
NewPathAttributeExtendedCommunities(ecommunities),
NewPathAttributeAs4Path(aspath3),
NewPathAttributeAs4Aggregator(10000, "112.22.2.1"),
NewPathAttributeMpReachNLRI("112.22.2.0", prefixes1),
NewPathAttributeMpReachNLRI("1023::", prefixes2),
NewPathAttributeMpReachNLRI("fe80::", prefixes3),
NewPathAttributeMpReachNLRI("129.1.1.1", prefixes4),
NewPathAttributeMpReachNLRI("129.1.1.1", prefixes5),
NewPathAttributeMpUnreachNLRI(prefixes1),
//NewPathAttributeMpReachNLRI("112.22.2.0", []AddrPrefixInterface{}),
//NewPathAttributeMpUnreachNLRI([]AddrPrefixInterface{}),
NewPathAttributeUnknown(BGP_ATTR_FLAG_TRANSITIVE, 100, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}),
}
n := []*IPAddrPrefix{NewIPAddrPrefix(24, "13.2.3.1")}
return NewBGPUpdateMessage(w, p, n)
}

337
vendor/github.com/osrg/gobgp/pkg/packet/bgp/validate.go generated vendored Normal file
View File

@@ -0,0 +1,337 @@
package bgp
import (
"encoding/binary"
"fmt"
"math"
"net"
"strconv"
)
// Validator for BGPUpdate
func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) {
var strongestError error
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE)
if len(m.NLRI) > 0 || len(m.WithdrawnRoutes) > 0 {
if _, ok := rfs[RF_IPv4_UC]; !ok {
return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", RF_IPv4_UC))
}
}
seen := make(map[BGPAttrType]PathAttributeInterface)
newAttrs := make([]PathAttributeInterface, 0, len(seen))
// check path attribute
for _, a := range m.PathAttributes {
// check duplication
if _, ok := seen[a.GetType()]; !ok {
seen[a.GetType()] = a
newAttrs = append(newAttrs, a)
//check specific path attribute
ok, err := ValidateAttribute(a, rfs, isEBGP, isConfed)
if !ok {
if err.(*MessageError).ErrorHandling == ERROR_HANDLING_SESSION_RESET {
return false, err
} else if err.(*MessageError).Stronger(strongestError) {
strongestError = err
}
}
} else if a.GetType() == BGP_ATTR_TYPE_MP_REACH_NLRI || a.GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI {
eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
return false, NewMessageError(eCode, eSubCodeAttrList, nil, eMsg)
} else {
eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
e := NewMessageErrorWithErrorHandling(eCode, eSubCodeAttrList, nil, ERROR_HANDLING_ATTRIBUTE_DISCARD, nil, eMsg)
if e.(*MessageError).Stronger(strongestError) {
strongestError = e
}
}
}
m.PathAttributes = newAttrs
if _, ok := seen[BGP_ATTR_TYPE_MP_REACH_NLRI]; ok || len(m.NLRI) > 0 {
// check the existence of well-known mandatory attributes
exist := func(attrs []BGPAttrType) (bool, BGPAttrType) {
for _, attr := range attrs {
_, ok := seen[attr]
if !ok {
return false, attr
}
}
return true, 0
}
mandatory := []BGPAttrType{BGP_ATTR_TYPE_ORIGIN, BGP_ATTR_TYPE_AS_PATH}
if len(m.NLRI) > 0 {
mandatory = append(mandatory, BGP_ATTR_TYPE_NEXT_HOP)
}
if ok, t := exist(mandatory); !ok {
eMsg := "well-known mandatory attributes are not present. type : " + strconv.Itoa(int(t))
data := []byte{byte(t)}
e := NewMessageErrorWithErrorHandling(eCode, eSubCodeMissing, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, eMsg)
if e.(*MessageError).Stronger(strongestError) {
strongestError = e
}
}
}
return strongestError == nil, strongestError
}
func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) {
var strongestError error
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE)
eSubCodeBadNextHop := uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE)
eSubCodeUnknown := uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE)
eSubCodeMalformedAspath := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
checkPrefix := func(l []AddrPrefixInterface) error {
for _, prefix := range l {
rf := AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI())
if _, ok := rfs[rf]; !ok {
return NewMessageError(0, 0, nil, fmt.Sprintf("Address-family %s not available for this session", rf))
}
switch rf {
case RF_FS_IPv4_UC, RF_FS_IPv6_UC, RF_FS_IPv4_VPN, RF_FS_IPv6_VPN, RF_FS_L2_VPN:
t := BGPFlowSpecType(0)
value := make([]FlowSpecComponentInterface, 0)
switch rf {
case RF_FS_IPv4_UC:
value = prefix.(*FlowSpecIPv4Unicast).Value
case RF_FS_IPv6_UC:
value = prefix.(*FlowSpecIPv6Unicast).Value
case RF_FS_IPv4_VPN:
value = prefix.(*FlowSpecIPv4VPN).Value
case RF_FS_IPv6_VPN:
value = prefix.(*FlowSpecIPv6VPN).Value
case RF_FS_L2_VPN:
value = prefix.(*FlowSpecL2VPN).Value
}
for _, v := range value {
if v.Type() <= t {
return NewMessageError(0, 0, nil, fmt.Sprintf("%s nlri violate strict type ordering", rf))
}
t = v.Type()
}
}
}
return nil
}
switch p := a.(type) {
case *PathAttributeMpUnreachNLRI:
rf := AfiSafiToRouteFamily(p.AFI, p.SAFI)
if _, ok := rfs[rf]; !ok {
return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf))
}
if err := checkPrefix(p.Value); err != nil {
return false, err
}
case *PathAttributeMpReachNLRI:
rf := AfiSafiToRouteFamily(p.AFI, p.SAFI)
if _, ok := rfs[rf]; !ok {
return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf))
}
if err := checkPrefix(p.Value); err != nil {
return false, err
}
case *PathAttributeOrigin:
v := uint8(p.Value)
if v != BGP_ORIGIN_ATTR_TYPE_IGP &&
v != BGP_ORIGIN_ATTR_TYPE_EGP &&
v != BGP_ORIGIN_ATTR_TYPE_INCOMPLETE {
data, _ := a.Serialize()
eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v))
e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadOrigin, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
if e.(*MessageError).Stronger(strongestError) {
strongestError = e
}
}
case *PathAttributeNextHop:
isZero := func(ip net.IP) bool {
res := ip[0] & 0xff
return res == 0x00
}
isClassDorE := func(ip net.IP) bool {
res := ip[0] & 0xe0
return res == 0xe0
}
//check IP address represents host address
if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) {
eMsg := "invalid nexthop address"
data, _ := a.Serialize()
e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadNextHop, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
if e.(*MessageError).Stronger(strongestError) {
strongestError = e
}
}
case *PathAttributeAsPath:
if isEBGP {
if isConfed {
if segType := p.Value[0].GetType(); segType != BGP_ASPATH_ATTR_TYPE_CONFED_SEQ {
return false, NewMessageError(eCode, eSubCodeMalformedAspath, nil, fmt.Sprintf("segment type is not confederation seq (%d)", segType))
}
} else {
for _, param := range p.Value {
segType := param.GetType()
switch segType {
case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
err := NewMessageErrorWithErrorHandling(
eCode, eSubCodeMalformedAspath, nil, getErrorHandlingFromPathAttribute(p.GetType()), nil, fmt.Sprintf("segment type confederation(%d) found", segType))
if err.(*MessageError).Stronger(strongestError) {
strongestError = err
}
}
}
}
}
case *PathAttributeLargeCommunities:
uniq := make([]*LargeCommunity, 0, len(p.Values))
for _, x := range p.Values {
found := false
for _, y := range uniq {
if x.String() == y.String() {
found = true
break
}
}
if !found {
uniq = append(uniq, x)
}
}
p.Values = uniq
case *PathAttributeUnknown:
if p.GetFlags()&BGP_ATTR_FLAG_OPTIONAL == 0 {
eMsg := fmt.Sprintf("unrecognized well-known attribute %s", p.GetType())
data, _ := a.Serialize()
return false, NewMessageError(eCode, eSubCodeUnknown, data, eMsg)
}
}
return strongestError == nil, strongestError
}
// validator for PathAttribute
func validatePathAttributeFlags(t BGPAttrType, flags BGPAttrFlag) string {
/*
* RFC 4271 P.17 For well-known attributes, the Transitive bit MUST be set to 1.
*/
if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 {
eMsg := fmt.Sprintf("well-known attribute %s must have transitive flag 1", t)
return eMsg
}
/*
* RFC 4271 P.17 For well-known attributes and for optional non-transitive attributes,
* the Partial bit MUST be set to 0.
*/
if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 {
eMsg := fmt.Sprintf("well-known attribute %s must have partial bit 0", t)
return eMsg
}
if flags&BGP_ATTR_FLAG_OPTIONAL != 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 {
eMsg := fmt.Sprintf("optional non-transitive attribute %s must have partial bit 0", t)
return eMsg
}
// check flags are correct
if f, ok := PathAttrFlags[t]; ok {
if f != flags & ^BGP_ATTR_FLAG_EXTENDED_LENGTH & ^BGP_ATTR_FLAG_PARTIAL {
eMsg := fmt.Sprintf("flags are invalid. attribute type: %s, expect: %s, actual: %s", t, f, flags)
return eMsg
}
}
return ""
}
func validateAsPathValueBytes(data []byte) (bool, error) {
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
if len(data)%2 != 0 {
return false, NewMessageError(eCode, eSubCode, nil, "AS PATH length is not odd")
}
tryParse := func(data []byte, use4byte bool) (bool, error) {
for len(data) > 0 {
if len(data) < 2 {
return false, NewMessageError(eCode, eSubCode, nil, "AS PATH header is short")
}
segType := data[0]
if segType == 0 || segType > 4 {
return false, NewMessageError(eCode, eSubCode, nil, "unknown AS_PATH seg type")
}
asNum := data[1]
data = data[2:]
if asNum == 0 || int(asNum) > math.MaxUint8 {
return false, NewMessageError(eCode, eSubCode, nil, "AS PATH the number of AS is incorrect")
}
segLength := int(asNum)
if use4byte {
segLength *= 4
} else {
segLength *= 2
}
if int(segLength) > len(data) {
return false, NewMessageError(eCode, eSubCode, nil, "seg length is short")
}
data = data[segLength:]
}
return true, nil
}
_, err := tryParse(data, true)
if err == nil {
return true, nil
}
_, err = tryParse(data, false)
if err == nil {
return false, nil
}
return false, NewMessageError(eCode, eSubCode, nil, "can't parse AS_PATH")
}
func ValidateBGPMessage(m *BGPMessage) error {
if m.Header.Len > BGP_MAX_MESSAGE_LENGTH {
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, m.Header.Len)
return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, buf, "too long length")
}
return nil
}
func ValidateOpenMsg(m *BGPOpen, expectedAS uint32) (uint32, error) {
if m.Version != 4 {
return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER, nil, fmt.Sprintf("unsupported version %d", m.Version))
}
as := uint32(m.MyAS)
for _, p := range m.OptParams {
paramCap, y := p.(*OptionParameterCapability)
if !y {
continue
}
for _, c := range paramCap.Capability {
if c.Code() == BGP_CAP_FOUR_OCTET_AS_NUMBER {
cap := c.(*CapFourOctetASNumber)
as = cap.CapValue
}
}
}
if expectedAS != 0 && as != expectedAS {
return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_BAD_PEER_AS, nil, fmt.Sprintf("as number mismatch expected %d, received %d", expectedAS, as))
}
if m.HoldTime < 3 && m.HoldTime != 0 {
return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME, nil, fmt.Sprintf("unacceptable hold time %d", m.HoldTime))
}
return as, nil
}

1072
vendor/github.com/osrg/gobgp/pkg/packet/bmp/bmp.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1006
vendor/github.com/osrg/gobgp/pkg/packet/mrt/mrt.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

392
vendor/github.com/osrg/gobgp/pkg/packet/rtr/rtr.go generated vendored Normal file
View File

@@ -0,0 +1,392 @@
// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rtr
import (
"encoding/binary"
"fmt"
"net"
)
const (
RPKI_DEFAULT_PORT = 323
)
const (
RTR_SERIAL_NOTIFY = iota
RTR_SERIAL_QUERY
RTR_RESET_QUERY
RTR_CACHE_RESPONSE
RTR_IPV4_PREFIX
_
RTR_IPV6_PREFIX
RTR_END_OF_DATA
RTR_CACHE_RESET
_
RTR_ERROR_REPORT
)
const (
RTR_SERIAL_NOTIFY_LEN = 12
RTR_SERIAL_QUERY_LEN = 12
RTR_RESET_QUERY_LEN = 8
RTR_CACHE_RESPONSE_LEN = 8
RTR_IPV4_PREFIX_LEN = 20
RTR_IPV6_PREFIX_LEN = 32
RTR_END_OF_DATA_LEN = 12
RTR_CACHE_RESET_LEN = 8
RTR_MIN_LEN = 8
RTR_ERROR_REPORT_ERR_PDU_LEN = 4
RTR_ERROR_REPORT_ERR_TEXT_LEN = 4
)
const (
WITHDRAWAL uint8 = iota
ANNOUNCEMENT
)
const (
CORRUPT_DATA uint16 = iota
INTERNAL_ERROR
NO_DATA_AVAILABLE
INVALID_REQUEST
UNSUPPORTED_PROTOCOL_VERSION
UNSUPPORTED_PDU_TYPE
WITHDRAWAL_OF_UNKNOWN_RECORD
DUPLICATE_ANNOUNCEMENT_RECORD
)
type RTRMessage interface {
DecodeFromBytes([]byte) error
Serialize() ([]byte, error)
}
type RTRCommon struct {
Version uint8
Type uint8
SessionID uint16
Len uint32
SerialNumber uint32
}
func (m *RTRCommon) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.SessionID = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
m.SerialNumber = binary.BigEndian.Uint32(data[8:12])
return nil
}
func (m *RTRCommon) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.SessionID)
binary.BigEndian.PutUint32(data[4:8], m.Len)
binary.BigEndian.PutUint32(data[8:12], m.SerialNumber)
return data, nil
}
type RTRSerialNotify struct {
RTRCommon
}
func NewRTRSerialNotify(id uint16, sn uint32) *RTRSerialNotify {
return &RTRSerialNotify{
RTRCommon{
Type: RTR_SERIAL_NOTIFY,
SessionID: id,
Len: RTR_SERIAL_NOTIFY_LEN,
SerialNumber: sn,
},
}
}
type RTRSerialQuery struct {
RTRCommon
}
func NewRTRSerialQuery(id uint16, sn uint32) *RTRSerialQuery {
return &RTRSerialQuery{
RTRCommon{
Type: RTR_SERIAL_QUERY,
SessionID: id,
Len: RTR_SERIAL_QUERY_LEN,
SerialNumber: sn,
},
}
}
type RTRReset struct {
Version uint8
Type uint8
Len uint32
}
func (m *RTRReset) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.Len = binary.BigEndian.Uint32(data[4:8])
return nil
}
func (m *RTRReset) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint32(data[4:8], m.Len)
return data, nil
}
type RTRResetQuery struct {
RTRReset
}
func NewRTRResetQuery() *RTRResetQuery {
return &RTRResetQuery{
RTRReset{
Type: RTR_RESET_QUERY,
Len: RTR_RESET_QUERY_LEN,
},
}
}
type RTRCacheResponse struct {
Version uint8
Type uint8
SessionID uint16
Len uint32
}
func (m *RTRCacheResponse) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.SessionID = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
return nil
}
func (m *RTRCacheResponse) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.SessionID)
binary.BigEndian.PutUint32(data[4:8], m.Len)
return data, nil
}
func NewRTRCacheResponse(id uint16) *RTRCacheResponse {
return &RTRCacheResponse{
Type: RTR_CACHE_RESPONSE,
SessionID: id,
Len: RTR_CACHE_RESPONSE_LEN,
}
}
type RTRIPPrefix struct {
Version uint8
Type uint8
Len uint32
Flags uint8
PrefixLen uint8
MaxLen uint8
Prefix net.IP
AS uint32
}
func (m *RTRIPPrefix) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.Len = binary.BigEndian.Uint32(data[4:8])
m.Flags = data[8]
m.PrefixLen = data[9]
m.MaxLen = data[10]
if m.Type == RTR_IPV4_PREFIX {
m.Prefix = net.IP(data[12:16]).To4()
m.AS = binary.BigEndian.Uint32(data[16:20])
} else {
m.Prefix = net.IP(data[12:28]).To16()
m.AS = binary.BigEndian.Uint32(data[28:32])
}
return nil
}
func (m *RTRIPPrefix) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint32(data[4:8], m.Len)
data[8] = m.Flags
data[9] = m.PrefixLen
data[10] = m.MaxLen
if m.Type == RTR_IPV4_PREFIX {
copy(data[12:16], m.Prefix.To4())
binary.BigEndian.PutUint32(data[16:20], m.AS)
} else {
copy(data[12:28], m.Prefix.To16())
binary.BigEndian.PutUint32(data[28:32], m.AS)
}
return data, nil
}
func NewRTRIPPrefix(prefix net.IP, prefixLen, maxLen uint8, as uint32, flags uint8) *RTRIPPrefix {
var pduType uint8
var pduLen uint32
if prefix.To4() != nil && prefixLen <= 32 {
pduType = RTR_IPV4_PREFIX
pduLen = RTR_IPV4_PREFIX_LEN
} else {
pduType = RTR_IPV6_PREFIX
pduLen = RTR_IPV6_PREFIX_LEN
}
return &RTRIPPrefix{
Type: pduType,
Len: pduLen,
Flags: flags,
PrefixLen: prefixLen,
MaxLen: maxLen,
Prefix: prefix,
AS: as,
}
}
type RTREndOfData struct {
RTRCommon
}
func NewRTREndOfData(id uint16, sn uint32) *RTREndOfData {
return &RTREndOfData{
RTRCommon{
Type: RTR_END_OF_DATA,
SessionID: id,
Len: RTR_END_OF_DATA_LEN,
SerialNumber: sn,
},
}
}
type RTRCacheReset struct {
RTRReset
}
func NewRTRCacheReset() *RTRCacheReset {
return &RTRCacheReset{
RTRReset{
Type: RTR_CACHE_RESET,
Len: RTR_CACHE_RESET_LEN,
},
}
}
type RTRErrorReport struct {
Version uint8
Type uint8
ErrorCode uint16
Len uint32
PDULen uint32
PDU []byte
TextLen uint32
Text []byte
}
func (m *RTRErrorReport) DecodeFromBytes(data []byte) error {
m.Version = data[0]
m.Type = data[1]
m.ErrorCode = binary.BigEndian.Uint16(data[2:4])
m.Len = binary.BigEndian.Uint32(data[4:8])
m.PDULen = binary.BigEndian.Uint32(data[8:12])
m.PDU = make([]byte, m.PDULen)
copy(m.PDU, data[12:12+m.PDULen])
m.TextLen = binary.BigEndian.Uint32(data[12+m.PDULen : 16+m.PDULen])
m.Text = make([]byte, m.TextLen)
copy(m.Text, data[16+m.PDULen:])
return nil
}
func (m *RTRErrorReport) Serialize() ([]byte, error) {
data := make([]byte, m.Len)
data[0] = m.Version
data[1] = m.Type
binary.BigEndian.PutUint16(data[2:4], m.ErrorCode)
binary.BigEndian.PutUint32(data[4:8], m.Len)
binary.BigEndian.PutUint32(data[8:12], m.PDULen)
copy(data[12:], m.PDU)
binary.BigEndian.PutUint32(data[12+m.PDULen:16+m.PDULen], m.TextLen)
copy(data[16+m.PDULen:], m.Text)
return data, nil
}
func NewRTRErrorReport(errCode uint16, errPDU []byte, errMsg []byte) *RTRErrorReport {
pdu := &RTRErrorReport{Type: RTR_ERROR_REPORT, ErrorCode: errCode}
if errPDU != nil {
if errPDU[1] == RTR_ERROR_REPORT {
return nil
}
pdu.PDULen = uint32(len(errPDU))
pdu.PDU = errPDU
}
if errMsg != nil {
pdu.Text = errMsg
pdu.TextLen = uint32(len(errMsg))
}
pdu.Len = uint32(RTR_MIN_LEN) + uint32(RTR_ERROR_REPORT_ERR_PDU_LEN) + pdu.PDULen + uint32(RTR_ERROR_REPORT_ERR_TEXT_LEN) + pdu.TextLen
return pdu
}
func SplitRTR(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 || len(data) < RTR_MIN_LEN {
return 0, nil, nil
}
totalLen := binary.BigEndian.Uint32(data[4:8])
if totalLen < RTR_MIN_LEN {
return 0, nil, fmt.Errorf("Invalid length: %d", totalLen)
}
if uint32(len(data)) < totalLen {
return 0, nil, nil
}
return int(totalLen), data[0:totalLen], nil
}
func ParseRTR(data []byte) (RTRMessage, error) {
var msg RTRMessage
switch data[1] {
case RTR_SERIAL_NOTIFY:
msg = &RTRSerialNotify{}
case RTR_SERIAL_QUERY:
msg = &RTRSerialQuery{}
case RTR_RESET_QUERY:
msg = &RTRResetQuery{}
case RTR_CACHE_RESPONSE:
msg = &RTRCacheResponse{}
case RTR_IPV4_PREFIX:
msg = &RTRIPPrefix{}
case RTR_IPV6_PREFIX:
msg = &RTRIPPrefix{}
case RTR_END_OF_DATA:
msg = &RTREndOfData{}
case RTR_CACHE_RESET:
msg = &RTRCacheReset{}
case RTR_ERROR_REPORT:
msg = &RTRErrorReport{}
default:
return nil, fmt.Errorf("unknown RTR message type %d:", data[1])
}
err := msg.DecodeFromBytes(data)
return msg, err
}

358
vendor/github.com/osrg/gobgp/pkg/server/bmp.go generated vendored Normal file
View File

@@ -0,0 +1,358 @@
// Copyright (C) 2015-2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
"net"
"strconv"
"time"
"github.com/osrg/gobgp/internal/pkg/config"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/pkg/packet/bgp"
"github.com/osrg/gobgp/pkg/packet/bmp"
log "github.com/sirupsen/logrus"
)
type ribout map[string][]*table.Path
func newribout() ribout {
return make(map[string][]*table.Path)
}
// return true if we need to send the path to the BMP server
func (r ribout) update(p *table.Path) bool {
key := p.GetNlri().String() // TODO expose (*Path).getPrefix()
l := r[key]
if p.IsWithdraw {
if len(l) == 0 {
return false
}
n := make([]*table.Path, 0, len(l))
for _, q := range l {
if p.GetSource() == q.GetSource() {
continue
}
n = append(n, q)
}
if len(n) == 0 {
delete(r, key)
} else {
r[key] = n
}
return true
}
if len(l) == 0 {
r[key] = []*table.Path{p}
return true
}
doAppend := true
for idx, q := range l {
if p.GetSource() == q.GetSource() {
// if we have sent the same path, don't send it again
if p.Equal(q) {
return false
}
l[idx] = p
doAppend = false
}
}
if doAppend {
r[key] = append(r[key], p)
}
return true
}
func (b *bmpClient) tryConnect() *net.TCPConn {
interval := 1
for {
log.WithFields(log.Fields{"Topic": "bmp"}).Debugf("Connecting BMP server:%s", b.host)
conn, err := net.Dial("tcp", b.host)
if err != nil {
select {
case <-b.dead:
return nil
default:
}
time.Sleep(time.Duration(interval) * time.Second)
if interval < 30 {
interval *= 2
}
} else {
log.WithFields(log.Fields{"Topic": "bmp"}).Infof("BMP server is connected:%s", b.host)
return conn.(*net.TCPConn)
}
}
}
func (b *bmpClient) Stop() {
close(b.dead)
}
func (b *bmpClient) loop() {
for {
conn := b.tryConnect()
if conn == nil {
break
}
if func() bool {
ops := []WatchOption{WatchPeerState(true)}
if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_BOTH {
log.WithFields(
log.Fields{"Topic": "bmp"},
).Warn("both option for route-monitoring-policy is obsoleted")
}
if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL {
ops = append(ops, WatchUpdate(true))
}
if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL {
ops = append(ops, WatchPostUpdate(true))
}
if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_LOCAL_RIB || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL {
ops = append(ops, WatchBestPath(true))
}
if b.c.RouteMirroringEnabled {
ops = append(ops, WatchMessage(false))
}
w := b.s.Watch(ops...)
defer w.Stop()
var tickerCh <-chan time.Time
if b.c.StatisticsTimeout == 0 {
log.WithFields(log.Fields{"Topic": "bmp"}).Debug("statistics reports disabled")
} else {
t := time.NewTicker(time.Duration(b.c.StatisticsTimeout) * time.Second)
defer t.Stop()
tickerCh = t.C
}
write := func(msg *bmp.BMPMessage) error {
buf, _ := msg.Serialize()
_, err := conn.Write(buf)
if err != nil {
log.Warnf("failed to write to bmp server %s", b.host)
}
return err
}
if err := write(bmp.NewBMPInitiation([]bmp.BMPInfoTLVInterface{})); err != nil {
return false
}
for {
select {
case ev := <-w.Event():
switch msg := ev.(type) {
case *WatchEventUpdate:
info := &table.PeerInfo{
Address: msg.PeerAddress,
AS: msg.PeerAS,
ID: msg.PeerID,
}
if msg.Payload == nil {
var pathList []*table.Path
if msg.Init {
pathList = msg.PathList
} else {
for _, p := range msg.PathList {
if b.ribout.update(p) {
pathList = append(pathList, p)
}
}
}
for _, path := range pathList {
for _, u := range table.CreateUpdateMsgFromPaths([]*table.Path{path}) {
payload, _ := u.Serialize()
if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, true, info, msg.Timestamp.Unix(), payload)); err != nil {
return false
}
}
}
} else {
if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, msg.FourBytesAs, info, msg.Timestamp.Unix(), msg.Payload)); err != nil {
return false
}
}
case *WatchEventBestPath:
info := &table.PeerInfo{
Address: net.ParseIP("0.0.0.0").To4(),
AS: b.s.bgpConfig.Global.Config.As,
ID: net.ParseIP(b.s.bgpConfig.Global.Config.RouterId).To4(),
}
for _, p := range msg.PathList {
u := table.CreateUpdateMsgFromPaths([]*table.Path{p})[0]
if payload, err := u.Serialize(); err != nil {
return false
} else if err = write(bmpPeerRoute(bmp.BMP_PEER_TYPE_LOCAL_RIB, false, 0, true, info, p.GetTimestamp().Unix(), payload)); err != nil {
return false
}
}
case *WatchEventPeerState:
if msg.State == bgp.BGP_FSM_ESTABLISHED {
if err := write(bmpPeerUp(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil {
return false
}
} else {
if err := write(bmpPeerDown(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil {
return false
}
}
case *WatchEventMessage:
info := &table.PeerInfo{
Address: msg.PeerAddress,
AS: msg.PeerAS,
ID: msg.PeerID,
}
if err := write(bmpPeerRouteMirroring(bmp.BMP_PEER_TYPE_GLOBAL, 0, info, msg.Timestamp.Unix(), msg.Message)); err != nil {
return false
}
}
case <-tickerCh:
neighborList := b.s.getNeighbor("", true)
for _, n := range neighborList {
if n.State.SessionState != config.SESSION_STATE_ESTABLISHED {
continue
}
if err := write(bmpPeerStats(bmp.BMP_PEER_TYPE_GLOBAL, 0, 0, n)); err != nil {
return false
}
}
case <-b.dead:
term := bmp.NewBMPTermination([]bmp.BMPTermTLVInterface{
bmp.NewBMPTermTLV16(bmp.BMP_TERM_TLV_TYPE_REASON, bmp.BMP_TERM_REASON_PERMANENTLY_ADMIN),
})
if err := write(term); err != nil {
return false
}
conn.Close()
return true
}
}
}() {
return
}
}
}
type bmpClient struct {
s *BgpServer
dead chan struct{}
host string
c *config.BmpServerConfig
ribout ribout
}
func bmpPeerUp(ev *WatchEventPeerState, t uint8, policy bool, pd uint64) *bmp.BMPMessage {
var flags uint8 = 0
if policy {
flags |= bmp.BMP_PEER_FLAG_POST_POLICY
}
ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix()))
return bmp.NewBMPPeerUpNotification(*ph, ev.LocalAddress.String(), ev.LocalPort, ev.PeerPort, ev.SentOpen, ev.RecvOpen)
}
func bmpPeerDown(ev *WatchEventPeerState, t uint8, policy bool, pd uint64) *bmp.BMPMessage {
var flags uint8 = 0
if policy {
flags |= bmp.BMP_PEER_FLAG_POST_POLICY
}
ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix()))
return bmp.NewBMPPeerDownNotification(*ph, uint8(ev.StateReason.PeerDownReason), ev.StateReason.BGPNotification, ev.StateReason.Data)
}
func bmpPeerRoute(t uint8, policy bool, pd uint64, fourBytesAs bool, peeri *table.PeerInfo, timestamp int64, payload []byte) *bmp.BMPMessage {
var flags uint8 = 0
if policy {
flags |= bmp.BMP_PEER_FLAG_POST_POLICY
}
if !fourBytesAs {
flags |= bmp.BMP_PEER_FLAG_TWO_AS
}
ph := bmp.NewBMPPeerHeader(t, flags, pd, peeri.Address.String(), peeri.AS, peeri.ID.String(), float64(timestamp))
m := bmp.NewBMPRouteMonitoring(*ph, nil)
body := m.Body.(*bmp.BMPRouteMonitoring)
body.BGPUpdatePayload = payload
return m
}
func bmpPeerStats(peerType uint8, peerDist uint64, timestamp int64, neighConf *config.Neighbor) *bmp.BMPMessage {
var peerFlags uint8 = 0
ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, neighConf.State.NeighborAddress, neighConf.State.PeerAs, neighConf.State.RemoteRouterId, float64(timestamp))
return bmp.NewBMPStatisticsReport(
*ph,
[]bmp.BMPStatsTLVInterface{
bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_ADJ_RIB_IN, uint64(neighConf.State.AdjTable.Accepted)),
bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_LOC_RIB, uint64(neighConf.State.AdjTable.Advertised+neighConf.State.AdjTable.Filtered)),
bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_UPDATE, neighConf.State.Messages.Received.WithdrawUpdate),
bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_PREFIX, neighConf.State.Messages.Received.WithdrawPrefix),
},
)
}
func bmpPeerRouteMirroring(peerType uint8, peerDist uint64, peerInfo *table.PeerInfo, timestamp int64, msg *bgp.BGPMessage) *bmp.BMPMessage {
var peerFlags uint8 = 0
ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, peerInfo.Address.String(), peerInfo.AS, peerInfo.ID.String(), float64(timestamp))
return bmp.NewBMPRouteMirroring(
*ph,
[]bmp.BMPRouteMirrTLVInterface{
// RFC7854: BGP Message TLV MUST occur last in the list of TLVs
bmp.NewBMPRouteMirrTLVBGPMsg(bmp.BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, msg),
},
)
}
func (b *bmpClientManager) addServer(c *config.BmpServerConfig) error {
host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port)))
if _, y := b.clientMap[host]; y {
return fmt.Errorf("bmp client %s is already configured", host)
}
b.clientMap[host] = &bmpClient{
s: b.s,
dead: make(chan struct{}),
host: host,
c: c,
ribout: newribout(),
}
go b.clientMap[host].loop()
return nil
}
func (b *bmpClientManager) deleteServer(c *config.BmpServerConfig) error {
host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port)))
if c, y := b.clientMap[host]; !y {
return fmt.Errorf("bmp client %s isn't found", host)
} else {
c.Stop()
delete(b.clientMap, host)
}
return nil
}
type bmpClientManager struct {
s *BgpServer
clientMap map[string]*bmpClient
}
func newBmpClientManager(s *BgpServer) *bmpClientManager {
return &bmpClientManager{
s: s,
clientMap: make(map[string]*bmpClient),
}
}

222
vendor/github.com/osrg/gobgp/pkg/server/collector.go generated vendored Normal file
View File

@@ -0,0 +1,222 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
"time"
"github.com/influxdata/influxdb/client/v2"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/pkg/packet/bgp"
log "github.com/sirupsen/logrus"
)
type Collector struct {
s *BgpServer
url string
dbName string
interval uint64
client client.Client
}
const (
MEATUREMENT_UPDATE = "update"
MEATUREMENT_PEER = "peer"
MEATUREMENT_TABLE = "table"
)
func (c *Collector) writePoints(points []*client.Point) error {
bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
Database: c.dbName,
Precision: "ms",
})
bp.AddPoints(points)
return c.client.Write(bp)
}
func (c *Collector) writePeer(msg *WatchEventPeerState) error {
var state string
switch msg.State {
case bgp.BGP_FSM_ESTABLISHED:
state = "Established"
case bgp.BGP_FSM_IDLE:
state = "Idle"
default:
return fmt.Errorf("unexpected fsm state %v", msg.State)
}
tags := map[string]string{
"PeerAddress": msg.PeerAddress.String(),
"PeerAS": fmt.Sprintf("%v", msg.PeerAS),
"State": state,
}
fields := map[string]interface{}{
"PeerID": msg.PeerID.String(),
}
pt, err := client.NewPoint(MEATUREMENT_PEER, tags, fields, msg.Timestamp)
if err != nil {
return err
}
return c.writePoints([]*client.Point{pt})
}
func path2data(path *table.Path) (map[string]interface{}, map[string]string) {
fields := map[string]interface{}{
"RouterID": path.GetSource().ID,
}
if asPath := path.GetAsPath(); asPath != nil {
fields["ASPath"] = asPath.String()
}
if origin, err := path.GetOrigin(); err == nil {
typ := "-"
switch origin {
case bgp.BGP_ORIGIN_ATTR_TYPE_IGP:
typ = "i"
case bgp.BGP_ORIGIN_ATTR_TYPE_EGP:
typ = "e"
case bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE:
typ = "?"
}
fields["Origin"] = typ
}
if med, err := path.GetMed(); err == nil {
fields["Med"] = med
}
tags := map[string]string{
"PeerAddress": path.GetSource().Address.String(),
"PeerAS": fmt.Sprintf("%v", path.GetSource().AS),
"Timestamp": path.GetTimestamp().String(),
}
if nexthop := path.GetNexthop(); len(nexthop) > 0 {
fields["NextHop"] = nexthop.String()
}
if originAS := path.GetSourceAs(); originAS != 0 {
fields["OriginAS"] = fmt.Sprintf("%v", originAS)
}
if err := bgp.FlatUpdate(tags, path.GetNlri().Flat()); err != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("NLRI FlatUpdate failed")
}
for _, p := range path.GetPathAttrs() {
if err := bgp.FlatUpdate(tags, p.Flat()); err != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("PathAttr FlatUpdate failed")
}
}
return fields, tags
}
func (c *Collector) writeUpdate(msg *WatchEventUpdate) error {
if len(msg.PathList) == 0 {
// EOR
return nil
}
now := time.Now()
points := make([]*client.Point, 0, len(msg.PathList))
for _, path := range msg.PathList {
fields, tags := path2data(path)
tags["Withdraw"] = fmt.Sprintf("%v", path.IsWithdraw)
pt, err := client.NewPoint(MEATUREMENT_UPDATE, tags, fields, now)
if err != nil {
return fmt.Errorf("failed to write update, %v", err)
}
points = append(points, pt)
}
return c.writePoints(points)
}
func (c *Collector) writeTable(msg *WatchEventAdjIn) error {
now := time.Now()
points := make([]*client.Point, 0, len(msg.PathList))
for _, path := range msg.PathList {
fields, tags := path2data(path)
pt, err := client.NewPoint(MEATUREMENT_TABLE, tags, fields, now)
if err != nil {
return fmt.Errorf("failed to write table, %v", err)
}
points = append(points, pt)
}
return c.writePoints(points)
}
func (c *Collector) loop() {
w := c.s.Watch(WatchPeerState(true), WatchUpdate(false))
defer w.Stop()
ticker := func() *time.Ticker {
if c.interval == 0 {
return &time.Ticker{}
}
return time.NewTicker(time.Second * time.Duration(c.interval))
}()
for {
select {
case <-ticker.C:
w.Generate(WATCH_EVENT_TYPE_PRE_UPDATE)
case ev := <-w.Event():
switch msg := ev.(type) {
case *WatchEventUpdate:
if err := c.writeUpdate(msg); err != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("Failed to write update event message")
}
case *WatchEventPeerState:
if err := c.writePeer(msg); err != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("Failed to write state changed event message")
}
case *WatchEventAdjIn:
if err := c.writeTable(msg); err != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("Failed to write Adj-In event message")
}
}
}
}
}
func NewCollector(s *BgpServer, url, dbName string, interval uint64) (*Collector, error) {
c, err := client.NewHTTPClient(client.HTTPConfig{
Addr: url,
})
if err != nil {
return nil, err
}
_, _, err = c.Ping(0)
if err != nil {
log.Error("can not connect to InfluxDB")
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Error("Failed to connect to InfluxDB")
return nil, err
}
q := client.NewQuery("CREATE DATABASE "+dbName, "", "")
if response, err := c.Query(q); err != nil || response.Error() != nil {
log.WithFields(log.Fields{"Type": "collector", "Error": err}).Errorf("Failed to create database:%s", dbName)
return nil, err
}
collector := &Collector{
s: s,
url: url,
dbName: dbName,
interval: interval,
client: c,
}
go collector.loop()
return collector, nil
}

1935
vendor/github.com/osrg/gobgp/pkg/server/fsm.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

2401
vendor/github.com/osrg/gobgp/pkg/server/grpc_server.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

409
vendor/github.com/osrg/gobgp/pkg/server/mrt.go generated vendored Normal file
View File

@@ -0,0 +1,409 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"bytes"
"fmt"
"os"
"time"
"github.com/osrg/gobgp/internal/pkg/config"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/pkg/packet/bgp"
"github.com/osrg/gobgp/pkg/packet/mrt"
log "github.com/sirupsen/logrus"
)
const (
MIN_ROTATION_INTERVAL = 60
MIN_DUMP_INTERVAL = 60
)
type mrtWriter struct {
dead chan struct{}
s *BgpServer
c *config.MrtConfig
file *os.File
rotationInterval uint64
dumpInterval uint64
}
func (m *mrtWriter) Stop() {
close(m.dead)
}
func (m *mrtWriter) loop() error {
ops := []WatchOption{}
switch m.c.DumpType {
case config.MRT_TYPE_UPDATES:
ops = append(ops, WatchUpdate(false))
case config.MRT_TYPE_TABLE:
if len(m.c.TableName) > 0 {
ops = append(ops, WatchTableName(m.c.TableName))
}
}
w := m.s.Watch(ops...)
rotator := func() *time.Ticker {
if m.rotationInterval == 0 {
return &time.Ticker{}
}
return time.NewTicker(time.Second * time.Duration(m.rotationInterval))
}()
dump := func() *time.Ticker {
if m.dumpInterval == 0 {
return &time.Ticker{}
}
return time.NewTicker(time.Second * time.Duration(m.dumpInterval))
}()
defer func() {
if m.file != nil {
m.file.Close()
}
if m.rotationInterval != 0 {
rotator.Stop()
}
if m.dumpInterval != 0 {
dump.Stop()
}
w.Stop()
}()
for {
serialize := func(ev WatchEvent) []*mrt.MRTMessage {
msg := make([]*mrt.MRTMessage, 0, 1)
switch e := ev.(type) {
case *WatchEventUpdate:
if e.Init {
return nil
}
mp := mrt.NewBGP4MPMessage(e.PeerAS, e.LocalAS, 0, e.PeerAddress.String(), e.LocalAddress.String(), e.FourBytesAs, nil)
mp.BGPMessagePayload = e.Payload
isAddPath := e.Neighbor.IsAddPathReceiveEnabled(e.PathList[0].GetRouteFamily())
subtype := mrt.MESSAGE
switch {
case isAddPath && e.FourBytesAs:
subtype = mrt.MESSAGE_AS4_ADDPATH
case isAddPath:
subtype = mrt.MESSAGE_ADDPATH
case e.FourBytesAs:
subtype = mrt.MESSAGE_AS4
}
if bm, err := mrt.NewMRTMessage(uint32(e.Timestamp.Unix()), mrt.BGP4MP, subtype, mp); err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Data": e,
"Error": err,
}).Warnf("Failed to create MRT BGP4MP message (subtype %d)", subtype)
} else {
msg = append(msg, bm)
}
case *WatchEventTable:
t := uint32(time.Now().Unix())
peers := make([]*mrt.Peer, 1, len(e.Neighbor)+1)
// Adding dummy Peer record for locally generated routes
peers[0] = mrt.NewPeer("0.0.0.0", "0.0.0.0", 0, true)
neighborMap := make(map[string]*config.Neighbor)
for _, pconf := range e.Neighbor {
peers = append(peers, mrt.NewPeer(pconf.State.RemoteRouterId, pconf.State.NeighborAddress, pconf.Config.PeerAs, true))
neighborMap[pconf.State.NeighborAddress] = pconf
}
if bm, err := mrt.NewMRTMessage(t, mrt.TABLE_DUMPv2, mrt.PEER_INDEX_TABLE, mrt.NewPeerIndexTable(e.RouterId, "", peers)); err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Data": e,
"Error": err,
}).Warnf("Failed to create MRT TABLE_DUMPv2 message (subtype %d)", mrt.PEER_INDEX_TABLE)
break
} else {
msg = append(msg, bm)
}
idx := func(p *table.Path) uint16 {
for i, pconf := range e.Neighbor {
if p.GetSource().Address.String() == pconf.State.NeighborAddress {
return uint16(i)
}
}
return uint16(len(e.Neighbor))
}
subtype := func(p *table.Path, isAddPath bool) mrt.MRTSubTypeTableDumpv2 {
t := mrt.RIB_GENERIC
switch p.GetRouteFamily() {
case bgp.RF_IPv4_UC:
t = mrt.RIB_IPV4_UNICAST
case bgp.RF_IPv4_MC:
t = mrt.RIB_IPV4_MULTICAST
case bgp.RF_IPv6_UC:
t = mrt.RIB_IPV6_UNICAST
case bgp.RF_IPv6_MC:
t = mrt.RIB_IPV6_MULTICAST
}
if isAddPath {
// Shift non-additional-path version to *_ADDPATH
t += 6
}
return t
}
seq := uint32(0)
appendTableDumpMsg := func(path *table.Path, entries []*mrt.RibEntry, isAddPath bool) {
st := subtype(path, isAddPath)
if bm, err := mrt.NewMRTMessage(t, mrt.TABLE_DUMPv2, st, mrt.NewRib(seq, path.GetNlri(), entries)); err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Data": e,
"Error": err,
}).Warnf("Failed to create MRT TABLE_DUMPv2 message (subtype %d)", st)
} else {
msg = append(msg, bm)
seq++
}
}
for _, pathList := range e.PathList {
entries := make([]*mrt.RibEntry, 0, len(pathList))
entriesAddPath := make([]*mrt.RibEntry, 0, len(pathList))
for _, path := range pathList {
isAddPath := false
if path.IsLocal() {
isAddPath = true
} else if neighbor, ok := neighborMap[path.GetSource().Address.String()]; ok {
isAddPath = neighbor.IsAddPathReceiveEnabled(path.GetRouteFamily())
}
if !isAddPath {
entries = append(entries, mrt.NewRibEntry(idx(path), uint32(path.GetTimestamp().Unix()), 0, path.GetPathAttrs(), false))
} else {
entriesAddPath = append(entriesAddPath, mrt.NewRibEntry(idx(path), uint32(path.GetTimestamp().Unix()), path.GetNlri().PathIdentifier(), path.GetPathAttrs(), true))
}
}
if len(entries) > 0 {
appendTableDumpMsg(pathList[0], entries, false)
}
if len(entriesAddPath) > 0 {
appendTableDumpMsg(pathList[0], entriesAddPath, true)
}
}
}
return msg
}
drain := func(ev WatchEvent) {
events := make([]WatchEvent, 0, 1+len(w.Event()))
if ev != nil {
events = append(events, ev)
}
for len(w.Event()) > 0 {
events = append(events, <-w.Event())
}
w := func(buf []byte) {
if _, err := m.file.Write(buf); err == nil {
m.file.Sync()
} else {
log.WithFields(log.Fields{
"Topic": "mrt",
"Error": err,
}).Warn("Can't write to destination MRT file")
}
}
var b bytes.Buffer
for _, e := range events {
for _, m := range serialize(e) {
if buf, err := m.Serialize(); err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Data": e,
"Error": err,
}).Warn("Failed to serialize event")
} else {
b.Write(buf)
if b.Len() > 1*1000*1000 {
w(b.Bytes())
b.Reset()
}
}
}
}
if b.Len() > 0 {
w(b.Bytes())
}
}
rotate := func() {
m.file.Close()
file, err := mrtFileOpen(m.c.FileName, m.rotationInterval)
if err == nil {
m.file = file
} else {
log.WithFields(log.Fields{
"Topic": "mrt",
"Error": err,
}).Warn("can't rotate MRT file")
}
}
select {
case <-m.dead:
drain(nil)
return nil
case e := <-w.Event():
drain(e)
if m.c.DumpType == config.MRT_TYPE_TABLE && m.rotationInterval != 0 {
rotate()
}
case <-rotator.C:
if m.c.DumpType == config.MRT_TYPE_UPDATES {
rotate()
} else {
w.Generate(WATCH_EVENT_TYPE_TABLE)
}
case <-dump.C:
w.Generate(WATCH_EVENT_TYPE_TABLE)
}
}
}
func mrtFileOpen(filename string, interval uint64) (*os.File, error) {
realname := filename
if interval != 0 {
realname = time.Now().Format(filename)
}
log.WithFields(log.Fields{
"Topic": "mrt",
"Filename": realname,
"Dump Interval": interval,
}).Debug("Setting new MRT destination file")
i := len(realname)
for i > 0 && os.IsPathSeparator(realname[i-1]) {
// skip trailing path separators
i--
}
j := i
for j > 0 && !os.IsPathSeparator(realname[j-1]) {
j--
}
if j > 0 {
if err := os.MkdirAll(realname[0:j-1], 0755); err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Error": err,
}).Warn("can't create MRT destination directory")
return nil, err
}
}
file, err := os.OpenFile(realname, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
if err != nil {
log.WithFields(log.Fields{
"Topic": "mrt",
"Error": err,
}).Warn("can't create MRT destination file")
}
return file, err
}
func newMrtWriter(s *BgpServer, c *config.MrtConfig, rInterval, dInterval uint64) (*mrtWriter, error) {
file, err := mrtFileOpen(c.FileName, rInterval)
if err != nil {
return nil, err
}
m := mrtWriter{
s: s,
c: c,
file: file,
rotationInterval: rInterval,
dumpInterval: dInterval,
}
go m.loop()
return &m, nil
}
type mrtManager struct {
bgpServer *BgpServer
writer map[string]*mrtWriter
}
func (m *mrtManager) enable(c *config.MrtConfig) error {
if _, ok := m.writer[c.FileName]; ok {
return fmt.Errorf("%s already exists", c.FileName)
}
rInterval := c.RotationInterval
dInterval := c.DumpInterval
setRotationMin := func() {
if rInterval < MIN_ROTATION_INTERVAL {
log.WithFields(log.Fields{
"Topic": "MRT",
}).Infof("minimum mrt rotation interval is %d seconds", MIN_ROTATION_INTERVAL)
rInterval = MIN_ROTATION_INTERVAL
}
}
if c.DumpType == config.MRT_TYPE_TABLE {
if rInterval == 0 {
if dInterval < MIN_DUMP_INTERVAL {
log.WithFields(log.Fields{
"Topic": "MRT",
}).Infof("minimum mrt dump interval is %d seconds", MIN_DUMP_INTERVAL)
dInterval = MIN_DUMP_INTERVAL
}
} else if dInterval == 0 {
setRotationMin()
} else {
return fmt.Errorf("can't specify both intervals in the table dump type")
}
} else if c.DumpType == config.MRT_TYPE_UPDATES {
// ignore the dump interval
dInterval = 0
if len(c.TableName) > 0 {
return fmt.Errorf("can't specify the table name with the update dump type")
}
setRotationMin()
}
w, err := newMrtWriter(m.bgpServer, c, rInterval, dInterval)
if err == nil {
m.writer[c.FileName] = w
}
return err
}
func (m *mrtManager) disable(c *config.MrtConfig) error {
w, ok := m.writer[c.FileName]
if !ok {
return fmt.Errorf("%s doesn't exists", c.FileName)
}
w.Stop()
delete(m.writer, c.FileName)
return nil
}
func newMrtManager(s *BgpServer) *mrtManager {
return &mrtManager{
bgpServer: s,
writer: make(map[string]*mrtWriter),
}
}

596
vendor/github.com/osrg/gobgp/pkg/server/peer.go generated vendored Normal file
View File

@@ -0,0 +1,596 @@
// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
"net"
"time"
"github.com/osrg/gobgp/internal/pkg/config"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/pkg/packet/bgp"
"github.com/eapache/channels"
log "github.com/sirupsen/logrus"
)
const (
FLOP_THRESHOLD = time.Second * 30
MIN_CONNECT_RETRY = 10
)
type PeerGroup struct {
Conf *config.PeerGroup
members map[string]config.Neighbor
dynamicNeighbors map[string]*config.DynamicNeighbor
}
func NewPeerGroup(c *config.PeerGroup) *PeerGroup {
return &PeerGroup{
Conf: c,
members: make(map[string]config.Neighbor),
dynamicNeighbors: make(map[string]*config.DynamicNeighbor),
}
}
func (pg *PeerGroup) AddMember(c config.Neighbor) {
pg.members[c.State.NeighborAddress] = c
}
func (pg *PeerGroup) DeleteMember(c config.Neighbor) {
delete(pg.members, c.State.NeighborAddress)
}
func (pg *PeerGroup) AddDynamicNeighbor(c *config.DynamicNeighbor) {
pg.dynamicNeighbors[c.Config.Prefix] = c
}
func newDynamicPeer(g *config.Global, neighborAddress string, pg *config.PeerGroup, loc *table.TableManager, policy *table.RoutingPolicy) *Peer {
conf := config.Neighbor{
Config: config.NeighborConfig{
PeerGroup: pg.Config.PeerGroupName,
},
State: config.NeighborState{
NeighborAddress: neighborAddress,
},
Transport: config.Transport{
Config: config.TransportConfig{
PassiveMode: true,
},
},
}
if err := config.OverwriteNeighborConfigWithPeerGroup(&conf, pg); err != nil {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": neighborAddress,
}).Debugf("Can't overwrite neighbor config: %s", err)
return nil
}
if err := config.SetDefaultNeighborConfigValues(&conf, pg, g); err != nil {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": neighborAddress,
}).Debugf("Can't set default config: %s", err)
return nil
}
peer := NewPeer(g, &conf, loc, policy)
peer.fsm.lock.Lock()
peer.fsm.state = bgp.BGP_FSM_ACTIVE
peer.fsm.lock.Unlock()
return peer
}
type Peer struct {
tableId string
fsm *FSM
adjRibIn *table.AdjRib
outgoing *channels.InfiniteChannel
policy *table.RoutingPolicy
localRib *table.TableManager
prefixLimitWarned map[bgp.RouteFamily]bool
llgrEndChs []chan struct{}
}
func NewPeer(g *config.Global, conf *config.Neighbor, loc *table.TableManager, policy *table.RoutingPolicy) *Peer {
peer := &Peer{
outgoing: channels.NewInfiniteChannel(),
localRib: loc,
policy: policy,
fsm: NewFSM(g, conf, policy),
prefixLimitWarned: make(map[bgp.RouteFamily]bool),
}
if peer.isRouteServerClient() {
peer.tableId = conf.State.NeighborAddress
} else {
peer.tableId = table.GLOBAL_RIB_NAME
}
rfs, _ := config.AfiSafis(conf.AfiSafis).ToRfList()
peer.adjRibIn = table.NewAdjRib(rfs)
return peer
}
func (peer *Peer) AS() uint32 {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.State.PeerAs
}
func (peer *Peer) ID() string {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.State.NeighborAddress
}
func (peer *Peer) TableID() string {
return peer.tableId
}
func (peer *Peer) isIBGPPeer() bool {
return peer.fsm.pConf.State.PeerAs == peer.fsm.gConf.Config.As
}
func (peer *Peer) isRouteServerClient() bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.RouteServer.Config.RouteServerClient
}
func (peer *Peer) isRouteReflectorClient() bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.RouteReflector.Config.RouteReflectorClient
}
func (peer *Peer) isGracefulRestartEnabled() bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.GracefulRestart.State.Enabled
}
func (peer *Peer) getAddPathMode(family bgp.RouteFamily) bgp.BGPAddPathMode {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
if mode, y := peer.fsm.rfMap[family]; y {
return mode
}
return bgp.BGP_ADD_PATH_NONE
}
func (peer *Peer) isAddPathReceiveEnabled(family bgp.RouteFamily) bool {
return (peer.getAddPathMode(family) & bgp.BGP_ADD_PATH_RECEIVE) > 0
}
func (peer *Peer) isAddPathSendEnabled(family bgp.RouteFamily) bool {
return (peer.getAddPathMode(family) & bgp.BGP_ADD_PATH_SEND) > 0
}
func (peer *Peer) isDynamicNeighbor() bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
return peer.fsm.pConf.Config.NeighborAddress == "" && peer.fsm.pConf.Config.NeighborInterface == ""
}
func (peer *Peer) recvedAllEOR() bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
for _, a := range peer.fsm.pConf.AfiSafis {
if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived {
return false
}
}
return true
}
func (peer *Peer) configuredRFlist() []bgp.RouteFamily {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
rfs, _ := config.AfiSafis(peer.fsm.pConf.AfiSafis).ToRfList()
return rfs
}
func (peer *Peer) negotiatedRFList() []bgp.RouteFamily {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
l := make([]bgp.RouteFamily, 0, len(peer.fsm.rfMap))
for family := range peer.fsm.rfMap {
l = append(l, family)
}
return l
}
func (peer *Peer) toGlobalFamilies(families []bgp.RouteFamily) []bgp.RouteFamily {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
if peer.fsm.pConf.Config.Vrf != "" {
fs := make([]bgp.RouteFamily, 0, len(families))
for _, f := range families {
switch f {
case bgp.RF_IPv4_UC:
fs = append(fs, bgp.RF_IPv4_VPN)
case bgp.RF_IPv6_UC:
fs = append(fs, bgp.RF_IPv6_VPN)
default:
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"Family": f,
"VRF": peer.fsm.pConf.Config.Vrf,
}).Warn("invalid family configured for neighbor with vrf")
}
}
families = fs
}
return families
}
func classifyFamilies(all, part []bgp.RouteFamily) ([]bgp.RouteFamily, []bgp.RouteFamily) {
a := []bgp.RouteFamily{}
b := []bgp.RouteFamily{}
for _, f := range all {
p := true
for _, g := range part {
if f == g {
p = false
a = append(a, f)
break
}
}
if p {
b = append(b, f)
}
}
return a, b
}
func (peer *Peer) forwardingPreservedFamilies() ([]bgp.RouteFamily, []bgp.RouteFamily) {
peer.fsm.lock.RLock()
list := []bgp.RouteFamily{}
for _, a := range peer.fsm.pConf.AfiSafis {
if s := a.MpGracefulRestart.State; s.Enabled && s.Received {
list = append(list, a.State.Family)
}
}
peer.fsm.lock.RUnlock()
return classifyFamilies(peer.configuredRFlist(), list)
}
func (peer *Peer) llgrFamilies() ([]bgp.RouteFamily, []bgp.RouteFamily) {
peer.fsm.lock.RLock()
list := []bgp.RouteFamily{}
for _, a := range peer.fsm.pConf.AfiSafis {
if a.LongLivedGracefulRestart.State.Enabled {
list = append(list, a.State.Family)
}
}
peer.fsm.lock.RUnlock()
return classifyFamilies(peer.configuredRFlist(), list)
}
func (peer *Peer) isLLGREnabledFamily(family bgp.RouteFamily) bool {
peer.fsm.lock.RLock()
llgrEnabled := peer.fsm.pConf.GracefulRestart.Config.LongLivedEnabled
peer.fsm.lock.RUnlock()
if !llgrEnabled {
return false
}
fs, _ := peer.llgrFamilies()
for _, f := range fs {
if f == family {
return true
}
}
return false
}
func (peer *Peer) llgrRestartTime(family bgp.RouteFamily) uint32 {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
for _, a := range peer.fsm.pConf.AfiSafis {
if a.State.Family == family {
return a.LongLivedGracefulRestart.State.PeerRestartTime
}
}
return 0
}
func (peer *Peer) llgrRestartTimerExpired(family bgp.RouteFamily) bool {
peer.fsm.lock.RLock()
defer peer.fsm.lock.RUnlock()
all := true
for _, a := range peer.fsm.pConf.AfiSafis {
if a.State.Family == family {
a.LongLivedGracefulRestart.State.PeerRestartTimerExpired = true
}
s := a.LongLivedGracefulRestart.State
if s.Received && !s.PeerRestartTimerExpired {
all = false
}
}
return all
}
func (peer *Peer) markLLGRStale(fs []bgp.RouteFamily) []*table.Path {
paths := peer.adjRibIn.PathList(fs, true)
for i, p := range paths {
doStale := true
for _, c := range p.GetCommunities() {
if c == uint32(bgp.COMMUNITY_NO_LLGR) {
doStale = false
p = p.Clone(true)
break
}
}
if doStale {
p = p.Clone(false)
p.SetCommunities([]uint32{uint32(bgp.COMMUNITY_LLGR_STALE)}, false)
}
paths[i] = p
}
return paths
}
func (peer *Peer) stopPeerRestarting() {
peer.fsm.lock.Lock()
defer peer.fsm.lock.Unlock()
peer.fsm.pConf.GracefulRestart.State.PeerRestarting = false
for _, ch := range peer.llgrEndChs {
close(ch)
}
peer.llgrEndChs = make([]chan struct{}, 0)
}
func (peer *Peer) filterPathFromSourcePeer(path, old *table.Path) *table.Path {
if peer.ID() != path.GetSource().Address.String() {
return path
}
// Note: Multiple paths having the same prefix could exist the withdrawals
// list in the case of Route Server setup with import policies modifying
// paths. In such case, gobgp sends duplicated update messages; withdraw
// messages for the same prefix.
if !peer.isRouteServerClient() {
if peer.isRouteReflectorClient() && path.GetRouteFamily() == bgp.RF_RTC_UC {
// When the peer is a Route Reflector client and the given path
// contains the Route Tartget Membership NLRI, the path should not
// be withdrawn in order to signal the client to distribute routes
// with the specific RT to Route Reflector.
return path
} else if !path.IsWithdraw && old != nil && old.GetSource().Address.String() != peer.ID() {
// Say, peer A and B advertized same prefix P, and best path
// calculation chose a path from B as best. When B withdraws prefix
// P, best path calculation chooses the path from A as best. For
// peers other than A, this path should be advertised (as implicit
// withdrawal). However for A, we should advertise the withdrawal
// path. Thing is same when peer A and we advertized prefix P (as
// local route), then, we withdraws the prefix.
return old.Clone(true)
}
}
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"Data": path,
}).Debug("From me, ignore.")
return nil
}
func (peer *Peer) doPrefixLimit(k bgp.RouteFamily, c *config.PrefixLimitConfig) *bgp.BGPMessage {
if maxPrefixes := int(c.MaxPrefixes); maxPrefixes > 0 {
count := peer.adjRibIn.Count([]bgp.RouteFamily{k})
pct := int(c.ShutdownThresholdPct)
if pct > 0 && !peer.prefixLimitWarned[k] && count > (maxPrefixes*pct/100) {
peer.prefixLimitWarned[k] = true
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"AddressFamily": k.String(),
}).Warnf("prefix limit %d%% reached", pct)
}
if count > maxPrefixes {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"AddressFamily": k.String(),
}).Warnf("prefix limit reached")
return bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED, nil)
}
}
return nil
}
func (peer *Peer) updatePrefixLimitConfig(c []config.AfiSafi) error {
peer.fsm.lock.RLock()
x := peer.fsm.pConf.AfiSafis
peer.fsm.lock.RUnlock()
y := c
if len(x) != len(y) {
return fmt.Errorf("changing supported afi-safi is not allowed")
}
m := make(map[bgp.RouteFamily]config.PrefixLimitConfig)
for _, e := range x {
m[e.State.Family] = e.PrefixLimit.Config
}
for _, e := range y {
if p, ok := m[e.State.Family]; !ok {
return fmt.Errorf("changing supported afi-safi is not allowed")
} else if !p.Equal(&e.PrefixLimit.Config) {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"AddressFamily": e.Config.AfiSafiName,
"OldMaxPrefixes": p.MaxPrefixes,
"NewMaxPrefixes": e.PrefixLimit.Config.MaxPrefixes,
"OldShutdownThresholdPct": p.ShutdownThresholdPct,
"NewShutdownThresholdPct": e.PrefixLimit.Config.ShutdownThresholdPct,
}).Warnf("update prefix limit configuration")
peer.prefixLimitWarned[e.State.Family] = false
if msg := peer.doPrefixLimit(e.State.Family, &e.PrefixLimit.Config); msg != nil {
sendFsmOutgoingMsg(peer, nil, msg, true)
}
}
}
peer.fsm.lock.Lock()
peer.fsm.pConf.AfiSafis = c
peer.fsm.lock.Unlock()
return nil
}
func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily, *bgp.BGPMessage) {
m := e.MsgData.(*bgp.BGPMessage)
update := m.Body.(*bgp.BGPUpdate)
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.fsm.pConf.State.NeighborAddress,
"nlri": update.NLRI,
"withdrawals": update.WithdrawnRoutes,
"attributes": update.PathAttributes,
}).Debug("received update")
peer.fsm.lock.Lock()
peer.fsm.pConf.Timers.State.UpdateRecvTime = time.Now().Unix()
peer.fsm.lock.Unlock()
if len(e.PathList) > 0 {
paths := make([]*table.Path, 0, len(e.PathList))
eor := []bgp.RouteFamily{}
for _, path := range e.PathList {
if path.IsEOR() {
family := path.GetRouteFamily()
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"AddressFamily": family,
}).Debug("EOR received")
eor = append(eor, family)
continue
}
// RFC4271 9.1.2 Phase 2: Route Selection
//
// If the AS_PATH attribute of a BGP route contains an AS loop, the BGP
// route should be excluded from the Phase 2 decision function.
if aspath := path.GetAsPath(); aspath != nil {
peer.fsm.lock.RLock()
localAS := peer.fsm.peerInfo.LocalAS
allowOwnAS := int(peer.fsm.pConf.AsPathOptions.Config.AllowOwnAs)
peer.fsm.lock.RUnlock()
if hasOwnASLoop(localAS, allowOwnAS, aspath) {
path.SetAsLooped(true)
continue
}
}
// RFC4456 8. Avoiding Routing Information Loops
// A router that recognizes the ORIGINATOR_ID attribute SHOULD
// ignore a route received with its BGP Identifier as the ORIGINATOR_ID.
peer.fsm.lock.RLock()
isIBGPPeer := peer.isIBGPPeer()
routerId := peer.fsm.gConf.Config.RouterId
peer.fsm.lock.RUnlock()
if isIBGPPeer {
if id := path.GetOriginatorID(); routerId == id.String() {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
"OriginatorID": id,
"Data": path,
}).Debug("Originator ID is mine, ignore")
continue
}
}
paths = append(paths, path)
}
peer.adjRibIn.Update(e.PathList)
peer.fsm.lock.RLock()
peerAfiSafis := peer.fsm.pConf.AfiSafis
peer.fsm.lock.RUnlock()
for _, af := range peerAfiSafis {
if msg := peer.doPrefixLimit(af.State.Family, &af.PrefixLimit.Config); msg != nil {
return nil, nil, msg
}
}
return paths, eor, nil
}
return nil, nil, nil
}
func (peer *Peer) startFSMHandler(incoming *channels.InfiniteChannel, stateCh chan *FsmMsg) {
handler := NewFSMHandler(peer.fsm, incoming, stateCh, peer.outgoing)
peer.fsm.lock.Lock()
peer.fsm.h = handler
peer.fsm.lock.Unlock()
}
func (peer *Peer) StaleAll(rfList []bgp.RouteFamily) []*table.Path {
return peer.adjRibIn.StaleAll(rfList)
}
func (peer *Peer) PassConn(conn *net.TCPConn) {
select {
case peer.fsm.connCh <- conn:
default:
conn.Close()
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
}).Warn("accepted conn is closed to avoid be blocked")
}
}
func (peer *Peer) DropAll(rfList []bgp.RouteFamily) {
peer.adjRibIn.Drop(rfList)
}
func (peer *Peer) stopFSM() error {
failed := false
peer.fsm.lock.RLock()
addr := peer.fsm.pConf.State.NeighborAddress
peer.fsm.lock.RUnlock()
t1 := time.AfterFunc(time.Minute*5, func() {
log.WithFields(log.Fields{
"Topic": "Peer",
}).Warnf("Failed to free the fsm.h.t for %s", addr)
failed = true
})
peer.fsm.h.t.Kill(nil)
peer.fsm.h.t.Wait()
t1.Stop()
if !failed {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Debug("freed fsm.h.t")
cleanInfiniteChannel(peer.outgoing)
}
failed = false
t2 := time.AfterFunc(time.Minute*5, func() {
log.WithFields(log.Fields{
"Topic": "Peer",
}).Warnf("Failed to free the fsm.t for %s", addr)
failed = true
})
peer.fsm.t.Kill(nil)
peer.fsm.t.Wait()
t2.Stop()
if !failed {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Debug("freed fsm.t")
return nil
}
return fmt.Errorf("Failed to free FSM for %s", addr)
}

712
vendor/github.com/osrg/gobgp/pkg/server/rpki.go generated vendored Normal file
View File

@@ -0,0 +1,712 @@
// Copyright (C) 2015,2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"encoding/binary"
"fmt"
"io"
"net"
"sort"
"strconv"
"time"
"github.com/osrg/gobgp/internal/pkg/config"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/pkg/packet/bgp"
"github.com/osrg/gobgp/pkg/packet/rtr"
"github.com/armon/go-radix"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
)
const (
CONNECT_RETRY_INTERVAL = 30
)
func before(a, b uint32) bool {
return int32(a-b) < 0
}
type RoaBucket struct {
Prefix *table.IPPrefix
entries []*table.ROA
}
func (r *RoaBucket) GetEntries() []*table.ROA {
return r.entries
}
type roas []*table.ROA
func (r roas) Len() int {
return len(r)
}
func (r roas) Swap(i, j int) {
r[i], r[j] = r[j], r[i]
}
func (r roas) Less(i, j int) bool {
r1 := r[i]
r2 := r[j]
if r1.MaxLen < r2.MaxLen {
return true
} else if r1.MaxLen > r2.MaxLen {
return false
}
if r1.AS < r2.AS {
return true
}
return false
}
type ROAEventType uint8
const (
CONNECTED ROAEventType = iota
DISCONNECTED
RTR
LIFETIMEOUT
)
type ROAEvent struct {
EventType ROAEventType
Src string
Data []byte
conn *net.TCPConn
}
type roaManager struct {
AS uint32
Roas map[bgp.RouteFamily]*radix.Tree
eventCh chan *ROAEvent
clientMap map[string]*roaClient
}
func NewROAManager(as uint32) (*roaManager, error) {
m := &roaManager{
AS: as,
Roas: make(map[bgp.RouteFamily]*radix.Tree),
}
m.Roas[bgp.RF_IPv4_UC] = radix.New()
m.Roas[bgp.RF_IPv6_UC] = radix.New()
m.eventCh = make(chan *ROAEvent)
m.clientMap = make(map[string]*roaClient)
return m, nil
}
func (c *roaManager) enabled() bool {
return len(c.clientMap) != 0
}
func (m *roaManager) SetAS(as uint32) error {
if m.AS != 0 {
return fmt.Errorf("AS was already configured")
}
m.AS = as
return nil
}
func (m *roaManager) AddServer(host string, lifetime int64) error {
address, port, err := net.SplitHostPort(host)
if err != nil {
return err
}
if lifetime == 0 {
lifetime = 3600
}
if _, ok := m.clientMap[host]; ok {
return fmt.Errorf("ROA server exists %s", host)
}
m.clientMap[host] = NewRoaClient(address, port, m.eventCh, lifetime)
return nil
}
func (m *roaManager) DeleteServer(host string) error {
client, ok := m.clientMap[host]
if !ok {
return fmt.Errorf("ROA server doesn't exists %s", host)
}
client.stop()
m.deleteAllROA(host)
delete(m.clientMap, host)
return nil
}
func (m *roaManager) deleteAllROA(network string) {
for _, tree := range m.Roas {
deleteKeys := make([]string, 0, tree.Len())
tree.Walk(func(s string, v interface{}) bool {
b, _ := v.(*RoaBucket)
newEntries := make([]*table.ROA, 0, len(b.entries))
for _, r := range b.entries {
if r.Src != network {
newEntries = append(newEntries, r)
}
}
if len(newEntries) > 0 {
b.entries = newEntries
} else {
deleteKeys = append(deleteKeys, s)
}
return false
})
for _, key := range deleteKeys {
tree.Delete(key)
}
}
}
func (m *roaManager) Enable(address string) error {
for network, client := range m.clientMap {
add, _, _ := net.SplitHostPort(network)
if add == address {
client.enable(client.serialNumber)
return nil
}
}
return fmt.Errorf("ROA server not found %s", address)
}
func (m *roaManager) Disable(address string) error {
for network, client := range m.clientMap {
add, _, _ := net.SplitHostPort(network)
if add == address {
client.reset()
m.deleteAllROA(add)
return nil
}
}
return fmt.Errorf("ROA server not found %s", address)
}
func (m *roaManager) Reset(address string) error {
return m.Disable(address)
}
func (m *roaManager) SoftReset(address string) error {
for network, client := range m.clientMap {
add, _, _ := net.SplitHostPort(network)
if add == address {
client.softReset()
m.deleteAllROA(network)
return nil
}
}
return fmt.Errorf("ROA server not found %s", address)
}
func (c *roaManager) ReceiveROA() chan *ROAEvent {
return c.eventCh
}
func (c *roaClient) lifetimeout() {
c.eventCh <- &ROAEvent{
EventType: LIFETIMEOUT,
Src: c.host,
}
}
func (m *roaManager) HandleROAEvent(ev *ROAEvent) {
client, y := m.clientMap[ev.Src]
if !y {
if ev.EventType == CONNECTED {
ev.conn.Close()
}
log.WithFields(log.Fields{"Topic": "rpki"}).Errorf("Can't find %s ROA server configuration", ev.Src)
return
}
switch ev.EventType {
case DISCONNECTED:
log.WithFields(log.Fields{"Topic": "rpki"}).Infof("ROA server %s is disconnected", ev.Src)
client.state.Downtime = time.Now().Unix()
// clear state
client.endOfData = false
client.pendingROAs = make([]*table.ROA, 0)
client.state.RpkiMessages = config.RpkiMessages{}
client.conn = nil
go client.tryConnect()
client.timer = time.AfterFunc(time.Duration(client.lifetime)*time.Second, client.lifetimeout)
client.oldSessionID = client.sessionID
case CONNECTED:
log.WithFields(log.Fields{"Topic": "rpki"}).Infof("ROA server %s is connected", ev.Src)
client.conn = ev.conn
client.state.Uptime = time.Now().Unix()
go client.established()
case RTR:
m.handleRTRMsg(client, &client.state, ev.Data)
case LIFETIMEOUT:
// a) already reconnected but hasn't received
// EndOfData -> needs to delete stale ROAs
// b) not reconnected -> needs to delete stale ROAs
//
// c) already reconnected and received EndOfData so
// all stale ROAs were deleted -> timer was cancelled
// so should not be here.
if client.oldSessionID != client.sessionID {
log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Reconnected to %s. Ignore timeout", client.host)
} else {
log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Deleting all ROAs due to timeout with:%s", client.host)
m.deleteAllROA(client.host)
}
}
}
func (m *roaManager) roa2tree(roa *table.ROA) (*radix.Tree, string) {
tree := m.Roas[bgp.RF_IPv4_UC]
if roa.Family == bgp.AFI_IP6 {
tree = m.Roas[bgp.RF_IPv6_UC]
}
return tree, table.IpToRadixkey(roa.Prefix.Prefix, roa.Prefix.Length)
}
func (m *roaManager) deleteROA(roa *table.ROA) {
tree, key := m.roa2tree(roa)
b, _ := tree.Get(key)
if b != nil {
bucket := b.(*RoaBucket)
newEntries := make([]*table.ROA, 0, len(bucket.entries))
for _, r := range bucket.entries {
if !r.Equal(roa) {
newEntries = append(newEntries, r)
}
}
if len(newEntries) != len(bucket.entries) {
bucket.entries = newEntries
if len(newEntries) == 0 {
tree.Delete(key)
}
return
}
}
log.WithFields(log.Fields{
"Topic": "rpki",
"Prefix": roa.Prefix.Prefix.String(),
"Prefix Length": roa.Prefix.Length,
"AS": roa.AS,
"Max Length": roa.MaxLen,
}).Info("Can't withdraw a ROA")
}
func (m *roaManager) DeleteROA(roa *table.ROA) {
m.deleteROA(roa)
}
func (m *roaManager) addROA(roa *table.ROA) {
tree, key := m.roa2tree(roa)
b, _ := tree.Get(key)
var bucket *RoaBucket
if b == nil {
bucket = &RoaBucket{
Prefix: roa.Prefix,
entries: make([]*table.ROA, 0),
}
tree.Insert(key, bucket)
} else {
bucket = b.(*RoaBucket)
for _, r := range bucket.entries {
if r.Equal(roa) {
// we already have the same one
return
}
}
}
bucket.entries = append(bucket.entries, roa)
}
func (m *roaManager) AddROA(roa *table.ROA) {
m.addROA(roa)
}
func (c *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerState, buf []byte) {
received := &state.RpkiMessages.RpkiReceived
m, err := rtr.ParseRTR(buf)
if err == nil {
switch msg := m.(type) {
case *rtr.RTRSerialNotify:
if before(client.serialNumber, msg.RTRCommon.SerialNumber) {
client.enable(client.serialNumber)
} else if client.serialNumber == msg.RTRCommon.SerialNumber {
// nothing
} else {
// should not happen. try to get the whole ROAs.
client.softReset()
}
received.SerialNotify++
case *rtr.RTRSerialQuery:
case *rtr.RTRResetQuery:
case *rtr.RTRCacheResponse:
received.CacheResponse++
client.endOfData = false
case *rtr.RTRIPPrefix:
family := bgp.AFI_IP
if msg.Type == rtr.RTR_IPV4_PREFIX {
received.Ipv4Prefix++
} else {
family = bgp.AFI_IP6
received.Ipv6Prefix++
}
roa := table.NewROA(family, msg.Prefix, msg.PrefixLen, msg.MaxLen, msg.AS, client.host)
if (msg.Flags & 1) == 1 {
if client.endOfData {
c.addROA(roa)
} else {
client.pendingROAs = append(client.pendingROAs, roa)
}
} else {
c.deleteROA(roa)
}
case *rtr.RTREndOfData:
received.EndOfData++
if client.sessionID != msg.RTRCommon.SessionID {
// remove all ROAs related with the
// previous session
c.deleteAllROA(client.host)
}
client.sessionID = msg.RTRCommon.SessionID
client.serialNumber = msg.RTRCommon.SerialNumber
client.endOfData = true
if client.timer != nil {
client.timer.Stop()
client.timer = nil
}
for _, roa := range client.pendingROAs {
c.addROA(roa)
}
client.pendingROAs = make([]*table.ROA, 0)
case *rtr.RTRCacheReset:
client.softReset()
received.CacheReset++
case *rtr.RTRErrorReport:
received.Error++
}
} else {
log.WithFields(log.Fields{
"Topic": "rpki",
"Host": client.host,
"Error": err,
}).Info("Failed to parse an RTR message")
}
}
func (c *roaManager) GetServers() []*config.RpkiServer {
f := func(tree *radix.Tree) (map[string]uint32, map[string]uint32) {
records := make(map[string]uint32)
prefixes := make(map[string]uint32)
tree.Walk(func(s string, v interface{}) bool {
b, _ := v.(*RoaBucket)
tmpRecords := make(map[string]uint32)
for _, roa := range b.entries {
tmpRecords[roa.Src]++
}
for src, r := range tmpRecords {
if r > 0 {
records[src] += r
prefixes[src]++
}
}
return false
})
return records, prefixes
}
recordsV4, prefixesV4 := f(c.Roas[bgp.RF_IPv4_UC])
recordsV6, prefixesV6 := f(c.Roas[bgp.RF_IPv6_UC])
l := make([]*config.RpkiServer, 0, len(c.clientMap))
for _, client := range c.clientMap {
state := &client.state
if client.conn == nil {
state.Up = false
} else {
state.Up = true
}
f := func(m map[string]uint32, key string) uint32 {
if r, ok := m[key]; ok {
return r
}
return 0
}
state.RecordsV4 = f(recordsV4, client.host)
state.RecordsV6 = f(recordsV6, client.host)
state.PrefixesV4 = f(prefixesV4, client.host)
state.PrefixesV6 = f(prefixesV6, client.host)
state.SerialNumber = client.serialNumber
addr, port, _ := net.SplitHostPort(client.host)
l = append(l, &config.RpkiServer{
Config: config.RpkiServerConfig{
Address: addr,
// Note: RpkiServerConfig.Port is uint32 type, but the TCP/UDP
// port is 16-bit length.
Port: func() uint32 { p, _ := strconv.ParseUint(port, 10, 16); return uint32(p) }(),
},
State: client.state,
})
}
return l
}
func (c *roaManager) GetRoa(family bgp.RouteFamily) ([]*table.ROA, error) {
if len(c.clientMap) == 0 {
return []*table.ROA{}, fmt.Errorf("RPKI server isn't configured.")
}
var rfList []bgp.RouteFamily
switch family {
case bgp.RF_IPv4_UC:
rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC}
case bgp.RF_IPv6_UC:
rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC}
default:
rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC}
}
l := make([]*table.ROA, 0)
for _, rf := range rfList {
if tree, ok := c.Roas[rf]; ok {
tree.Walk(func(s string, v interface{}) bool {
b, _ := v.(*RoaBucket)
var roaList roas
for _, r := range b.entries {
roaList = append(roaList, r)
}
sort.Sort(roaList)
for _, roa := range roaList {
l = append(l, roa)
}
return false
})
}
}
return l, nil
}
func ValidatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) *table.Validation {
var as uint32
validation := &table.Validation{
Status: config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND,
Reason: table.RPKI_VALIDATION_REASON_TYPE_NONE,
Matched: make([]*table.ROA, 0),
UnmatchedLength: make([]*table.ROA, 0),
UnmatchedAs: make([]*table.ROA, 0),
}
if asPath == nil || len(asPath.Value) == 0 {
as = ownAs
} else {
param := asPath.Value[len(asPath.Value)-1]
switch param.GetType() {
case bgp.BGP_ASPATH_ATTR_TYPE_SEQ:
asList := param.GetAS()
if len(asList) == 0 {
as = ownAs
} else {
as = asList[len(asList)-1]
}
case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
as = ownAs
default:
return validation
}
}
_, n, _ := net.ParseCIDR(cidr)
ones, _ := n.Mask.Size()
prefixLen := uint8(ones)
key := table.IpToRadixkey(n.IP, prefixLen)
_, b, _ := tree.LongestPrefix(key)
if b == nil {
return validation
}
var bucket *RoaBucket
fn := radix.WalkFn(func(k string, v interface{}) bool {
bucket, _ = v.(*RoaBucket)
for _, r := range bucket.entries {
if prefixLen <= r.MaxLen {
if r.AS != 0 && r.AS == as {
validation.Matched = append(validation.Matched, r)
} else {
validation.UnmatchedAs = append(validation.UnmatchedAs, r)
}
} else {
validation.UnmatchedLength = append(validation.UnmatchedLength, r)
}
}
return false
})
tree.WalkPath(key, fn)
if len(validation.Matched) != 0 {
validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_VALID
validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE
} else if len(validation.UnmatchedAs) != 0 {
validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID
validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_AS
} else if len(validation.UnmatchedLength) != 0 {
validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID
validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_LENGTH
} else {
validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND
validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE
}
return validation
}
func (c *roaManager) validate(path *table.Path) *table.Validation {
if len(c.clientMap) == 0 || path.IsWithdraw || path.IsEOR() {
// RPKI isn't enabled or invalid path
return nil
}
if tree, ok := c.Roas[path.GetRouteFamily()]; ok {
return ValidatePath(c.AS, tree, path.GetNlri().String(), path.GetAsPath())
}
return nil
}
type roaClient struct {
host string
conn *net.TCPConn
state config.RpkiServerState
eventCh chan *ROAEvent
sessionID uint16
oldSessionID uint16
serialNumber uint32
timer *time.Timer
lifetime int64
endOfData bool
pendingROAs []*table.ROA
cancelfnc context.CancelFunc
ctx context.Context
}
func NewRoaClient(address, port string, ch chan *ROAEvent, lifetime int64) *roaClient {
ctx, cancel := context.WithCancel(context.Background())
c := &roaClient{
host: net.JoinHostPort(address, port),
eventCh: ch,
lifetime: lifetime,
pendingROAs: make([]*table.ROA, 0),
ctx: ctx,
cancelfnc: cancel,
}
go c.tryConnect()
return c
}
func (c *roaClient) enable(serial uint32) error {
if c.conn != nil {
r := rtr.NewRTRSerialQuery(c.sessionID, serial)
data, _ := r.Serialize()
_, err := c.conn.Write(data)
if err != nil {
return err
}
c.state.RpkiMessages.RpkiSent.SerialQuery++
}
return nil
}
func (c *roaClient) softReset() error {
if c.conn != nil {
r := rtr.NewRTRResetQuery()
data, _ := r.Serialize()
_, err := c.conn.Write(data)
if err != nil {
return err
}
c.state.RpkiMessages.RpkiSent.ResetQuery++
c.endOfData = false
c.pendingROAs = make([]*table.ROA, 0)
}
return nil
}
func (c *roaClient) reset() {
if c.conn != nil {
c.conn.Close()
}
}
func (c *roaClient) stop() {
c.cancelfnc()
c.reset()
}
func (c *roaClient) tryConnect() {
for {
select {
case <-c.ctx.Done():
return
default:
}
if conn, err := net.Dial("tcp", c.host); err != nil {
// better to use context with timeout
time.Sleep(CONNECT_RETRY_INTERVAL * time.Second)
} else {
c.eventCh <- &ROAEvent{
EventType: CONNECTED,
Src: c.host,
conn: conn.(*net.TCPConn),
}
return
}
}
}
func (c *roaClient) established() (err error) {
defer func() {
c.conn.Close()
c.eventCh <- &ROAEvent{
EventType: DISCONNECTED,
Src: c.host,
}
}()
if err := c.softReset(); err != nil {
return err
}
for {
header := make([]byte, rtr.RTR_MIN_LEN)
if _, err = io.ReadFull(c.conn, header); err != nil {
return err
}
totalLen := binary.BigEndian.Uint32(header[4:8])
if totalLen < rtr.RTR_MIN_LEN {
return fmt.Errorf("too short header length %v", totalLen)
}
body := make([]byte, totalLen-rtr.RTR_MIN_LEN)
if _, err = io.ReadFull(c.conn, body); err != nil {
return
}
c.eventCh <- &ROAEvent{
EventType: RTR,
Src: c.host,
Data: append(header, body...),
}
}
}

3731
vendor/github.com/osrg/gobgp/pkg/server/server.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

90
vendor/github.com/osrg/gobgp/pkg/server/sockopt.go generated vendored Normal file
View File

@@ -0,0 +1,90 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !linux,!openbsd
package server
import (
"fmt"
"net"
log "github.com/sirupsen/logrus"
)
func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return setTcpMD5SigSockopt(l, address, key)
}
func SetListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
return setListenTcpTTLSockopt(l, ttl)
}
func SetTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
return setTcpTTLSockopt(conn, ttl)
}
func SetTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setTcpMinTTLSockopt(conn, ttl)
}
type TCPDialer struct {
net.Dialer
// MD5 authentication password.
AuthPassword string
// The TTL value to set outgoing connection.
Ttl uint8
// The minimum TTL value for incoming packets.
TtlMin uint8
}
func (d *TCPDialer) DialTCP(addr string, port int) (*net.TCPConn, error) {
if d.AuthPassword != "" {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting md5 for active connection is not supported")
}
if d.Ttl != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting ttl for active connection is not supported")
}
if d.TtlMin != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting min ttl for active connection is not supported")
}
raddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(addr, fmt.Sprintf("%d", port)))
if err != nil {
return nil, fmt.Errorf("invalid remote address: %s", err)
}
laddr, err := net.ResolveTCPAddr("tcp", d.LocalAddr.String())
if err != nil {
return nil, fmt.Errorf("invalid local address: %s", err)
}
dialer := net.Dialer{LocalAddr: laddr, Timeout: d.Timeout}
conn, err := dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}

69
vendor/github.com/osrg/gobgp/pkg/server/sockopt_bsd.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build dragonfly freebsd netbsd
package server
import (
"net"
"syscall"
)
const (
TCP_MD5SIG = 0x10 // TCP MD5 Signature (RFC2385)
IPV6_MINHOPCOUNT = 73 // Generalized TTL Security Mechanism (RFC5082)
)
func setTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
sc, err := l.SyscallConn()
if err != nil {
return err
}
// always enable and assumes that the configuration is done by setkey()
return setsockOptInt(sc, syscall.IPPROTO_TCP, TCP_MD5SIG, 1)
}
func setListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
family := extractFamilyFromTCPListener(l)
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
level := syscall.IPPROTO_IP
name := syscall.IP_MINTTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = IPV6_MINHOPCOUNT
}
return setsockOptInt(sc, level, name, ttl)
}

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2016-2017 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build darwin
package server
import (
"fmt"
"net"
"strings"
"syscall"
)
func setTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return fmt.Errorf("setting md5 is not supported")
}
func setListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
family := extractFamilyFromTCPListener(l)
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := syscall.AF_INET
if strings.Contains(conn.RemoteAddr().String(), "[") {
family = syscall.AF_INET6
}
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return fmt.Errorf("setting min ttl is not supported")
}

View File

@@ -0,0 +1,289 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
package server
import (
"fmt"
"net"
"os"
"syscall"
"unsafe"
)
const (
TCP_MD5SIG = 14 // TCP MD5 Signature (RFC2385)
IPV6_MINHOPCOUNT = 73 // Generalized TTL Security Mechanism (RFC5082)
)
type tcpmd5sig struct {
ss_family uint16
ss [126]byte
// padding the struct
_ uint16
keylen uint16
// padding the struct
_ uint32
key [80]byte
}
func buildTcpMD5Sig(address string, key string) (tcpmd5sig, error) {
t := tcpmd5sig{}
addr := net.ParseIP(address)
if addr.To4() != nil {
t.ss_family = syscall.AF_INET
copy(t.ss[2:], addr.To4())
} else {
t.ss_family = syscall.AF_INET6
copy(t.ss[6:], addr.To16())
}
t.keylen = uint16(len(key))
copy(t.key[0:], []byte(key))
return t, nil
}
func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
t, err := buildTcpMD5Sig(address, key)
if err != nil {
return err
}
b := *(*[unsafe.Sizeof(t)]byte)(unsafe.Pointer(&t))
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockOptString(sc, syscall.IPPROTO_TCP, TCP_MD5SIG, string(b[:]))
}
func SetListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
family := extractFamilyFromTCPListener(l)
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func SetTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func SetTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
level := syscall.IPPROTO_IP
name := syscall.IP_MINTTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = IPV6_MINHOPCOUNT
}
return setsockOptInt(sc, level, name, ttl)
}
func setsockoptTcpMD5Sig(fd int, address string, key string) error {
t, err := buildTcpMD5Sig(address, key)
if err != nil {
return err
}
b := *(*[unsafe.Sizeof(t)]byte)(unsafe.Pointer(&t))
return os.NewSyscallError("setsockopt", syscall.SetsockoptString(fd, syscall.IPPROTO_TCP, TCP_MD5SIG, string(b[:])))
}
func setsockoptIpTtl2(fd int, family int, value int) error {
level := syscall.IPPROTO_IP
name := syscall.IP_TTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = syscall.IPV6_UNICAST_HOPS
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, value))
}
func setsockoptIpMinTtl(fd int, family int, value int) error {
level := syscall.IPPROTO_IP
name := syscall.IP_MINTTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = IPV6_MINHOPCOUNT
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, value))
}
type TCPDialer struct {
net.Dialer
// MD5 authentication password.
AuthPassword string
// The TTL value to set outgoing connection.
Ttl uint8
// The minimum TTL value for incoming packets.
TtlMin uint8
}
func (d *TCPDialer) DialTCP(addr string, port int) (*net.TCPConn, error) {
var family int
var ra, la syscall.Sockaddr
raddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(addr, fmt.Sprintf("%d", port)))
if err != nil {
return nil, fmt.Errorf("invalid remote address: %s", err)
}
laddr, err := net.ResolveTCPAddr("tcp", d.LocalAddr.String())
if err != nil {
return nil, fmt.Errorf("invalid local address: %s", err)
}
if raddr.IP.To4() != nil {
family = syscall.AF_INET
rsockaddr := &syscall.SockaddrInet4{Port: port}
copy(rsockaddr.Addr[:], raddr.IP.To4())
ra = rsockaddr
lsockaddr := &syscall.SockaddrInet4{}
copy(lsockaddr.Addr[:], laddr.IP.To4())
la = lsockaddr
} else {
family = syscall.AF_INET6
rsockaddr := &syscall.SockaddrInet6{Port: port}
copy(rsockaddr.Addr[:], raddr.IP.To16())
ra = rsockaddr
var zone uint32
if laddr.Zone != "" {
if intf, err := net.InterfaceByName(laddr.Zone); err != nil {
return nil, err
} else {
zone = uint32(intf.Index)
}
}
lsockaddr := &syscall.SockaddrInet6{ZoneId: zone}
copy(lsockaddr.Addr[:], laddr.IP.To16())
la = lsockaddr
}
sockType := syscall.SOCK_STREAM | syscall.SOCK_CLOEXEC | syscall.SOCK_NONBLOCK
proto := 0
fd, err := syscall.Socket(family, sockType, proto)
if err != nil {
return nil, err
}
fi := os.NewFile(uintptr(fd), "")
defer fi.Close()
// A new socket was created so we must close it before this
// function returns either on failure or success. On success,
// net.FileConn() in newTCPConn() increases the refcount of
// the socket so this fi.Close() doesn't destroy the socket.
// The caller must call Close() with the file later.
// Note that the above os.NewFile() doesn't play with the
// refcount.
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1); err != nil {
return nil, os.NewSyscallError("setsockopt", err)
}
if err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); err != nil {
return nil, os.NewSyscallError("setsockopt", err)
}
if d.AuthPassword != "" {
if err = setsockoptTcpMD5Sig(fd, addr, d.AuthPassword); err != nil {
return nil, err
}
}
if d.Ttl != 0 {
if err = setsockoptIpTtl2(fd, family, int(d.Ttl)); err != nil {
return nil, err
}
}
if d.TtlMin != 0 {
if err = setsockoptIpMinTtl(fd, family, int(d.Ttl)); err != nil {
return nil, err
}
}
if err = syscall.Bind(fd, la); err != nil {
return nil, os.NewSyscallError("bind", err)
}
newTCPConn := func(fi *os.File) (*net.TCPConn, error) {
if conn, err := net.FileConn(fi); err != nil {
return nil, err
} else {
return conn.(*net.TCPConn), err
}
}
err = syscall.Connect(fd, ra)
switch err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
// do timeout handling
case nil, syscall.EISCONN:
return newTCPConn(fi)
default:
return nil, os.NewSyscallError("connect", err)
}
epfd, e := syscall.EpollCreate1(syscall.EPOLL_CLOEXEC)
if e != nil {
return nil, e
}
defer syscall.Close(epfd)
var event syscall.EpollEvent
events := make([]syscall.EpollEvent, 1)
event.Events = syscall.EPOLLIN | syscall.EPOLLOUT | syscall.EPOLLPRI
event.Fd = int32(fd)
if e = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); e != nil {
return nil, e
}
for {
nevents, e := syscall.EpollWait(epfd, events, int(d.Timeout/1000000) /*msec*/)
if e != nil {
return nil, e
}
if nevents == 0 {
return nil, fmt.Errorf("timeout")
} else if nevents == 1 && events[0].Fd == int32(fd) {
nerr, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR)
if err != nil {
return nil, os.NewSyscallError("getsockopt", err)
}
switch err := syscall.Errno(nerr); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case syscall.Errno(0), syscall.EISCONN:
return newTCPConn(fi)
default:
return nil, os.NewSyscallError("getsockopt", err)
}
} else {
return nil, fmt.Errorf("unexpected epoll behavior")
}
}
}

View File

@@ -0,0 +1,454 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build openbsd
package server
import (
"encoding/binary"
"fmt"
"net"
"os"
"syscall"
"unsafe"
log "github.com/sirupsen/logrus"
)
const (
PF_KEY_V2 = 2
SADB_X_SATYPE_TCPSIGNATURE = 8
SADB_EXT_SA = 1
SADB_EXT_ADDRESS_SRC = 5
SADB_EXT_ADDRESS_DST = 6
SADB_EXT_KEY_AUTH = 8
SADB_EXT_SPIRANGE = 16
SADB_GETSPI = 1
SADB_UPDATE = 2
SADB_DELETE = 4
SADB_X_EALG_AES = 12
SADB_SASTATE_MATURE = 1
)
type sadbMsg struct {
sadbMsgVersion uint8
sadbMsgType uint8
sadbMsgErrno uint8
sadbMsgSatype uint8
sadbMsgLen uint16
sadbMsgReserved uint16
sadbMsgSeq uint32
sadbMsgPid uint32
}
func (s *sadbMsg) DecodeFromBytes(data []byte) error {
if len(data) < SADB_MSG_SIZE {
fmt.Errorf("too short for sadbMsg %d", len(data))
}
s.sadbMsgVersion = data[0]
s.sadbMsgType = data[1]
s.sadbMsgErrno = data[2]
s.sadbMsgSatype = data[3]
s.sadbMsgLen = binary.LittleEndian.Uint16(data[4:6])
s.sadbMsgSeq = binary.LittleEndian.Uint32(data[8:12])
s.sadbMsgPid = binary.LittleEndian.Uint32(data[12:16])
return nil
}
type sadbSpirange struct {
sadbSpirangeLen uint16
sadbSpirangeExttype uint16
sadbSpirangeMin uint32
sadbSpirangeMax uint32
sadbSpirangeReserved uint32
}
type sadbAddress struct {
sadbAddressLen uint16
sadbAddressExttype uint16
sadbAddressReserved uint32
}
type sadbExt struct {
sadbExtLen uint16
sadbExtType uint16
}
type sadbSa struct {
sadbSaLen uint16
sadbSaExttype uint16
sadbSaSpi uint32
sadbSaReplay uint8
sadbSaState uint8
sadbSaAuth uint8
sadbSaEncrypt uint8
sadbSaFlags uint32
}
type sadbKey struct {
sadbKeyLen uint16
sadbKeyExttype uint16
sadbKeyBits uint16
sadbKeyReserved uint16
}
const (
SADB_MSG_SIZE = int(unsafe.Sizeof(sadbMsg{}))
SADB_SPIRANGE_SIZE = int(unsafe.Sizeof(sadbSpirange{}))
SADB_ADDRESS_SIZE = int(unsafe.Sizeof(sadbAddress{}))
SADB_SA_SIZE = int(unsafe.Sizeof(sadbSa{}))
SADB_KEY_SIZE = int(unsafe.Sizeof(sadbKey{}))
)
type sockaddrIn struct {
ssLen uint8
ssFamily uint8
ssPort uint16
ssAddr uint32
pad [8]byte
}
func newSockaddrIn(addr string) sockaddrIn {
if len(addr) == 0 {
return sockaddrIn{
ssLen: 16,
}
}
v := net.ParseIP(addr).To4()
return sockaddrIn{
ssAddr: uint32(v[3])<<24 | uint32(v[2])<<16 | uint32(v[1])<<8 | uint32(v[0]),
ssLen: 16,
ssFamily: syscall.AF_INET,
}
}
func roundUp(v int) int {
if v%8 != 0 {
v += 8 - v%8
}
return v
}
func b(p unsafe.Pointer, length int) []byte {
buf := make([]byte, length)
for i := 0; i < length; i++ {
buf[i] = *(*byte)(p)
p = unsafe.Pointer(uintptr(p) + 1)
}
return buf
}
var seq uint32
var fd int
var spiInMap map[string]uint32 = map[string]uint32{}
var spiOutMap map[string]uint32 = map[string]uint32{}
func pfkeyReply() (spi uint32, err error) {
buf := make([]byte, SADB_MSG_SIZE)
if count, _, _, _, _ := syscall.Recvmsg(fd, buf, nil, syscall.MSG_PEEK); count != len(buf) {
return spi, fmt.Errorf("incomplete sadb msg %d %d", len(buf), count)
}
h := sadbMsg{}
h.DecodeFromBytes(buf)
if h.sadbMsgErrno != 0 {
return spi, fmt.Errorf("sadb msg reply error %d", h.sadbMsgErrno)
}
if h.sadbMsgSeq != seq {
return spi, fmt.Errorf("sadb msg sequence doesn't match %d %d", h.sadbMsgSeq, seq)
}
if h.sadbMsgPid != uint32(os.Getpid()) {
return spi, fmt.Errorf("sadb msg pid doesn't match %d %d", h.sadbMsgPid, os.Getpid())
}
buf = make([]byte, int(8*h.sadbMsgLen))
if count, _, _, _, _ := syscall.Recvmsg(fd, buf, nil, 0); count != len(buf) {
return spi, fmt.Errorf("incomplete sadb msg body %d %d", len(buf), count)
}
buf = buf[SADB_MSG_SIZE:]
for len(buf) >= 4 {
l := binary.LittleEndian.Uint16(buf[0:2]) * 8
t := binary.LittleEndian.Uint16(buf[2:4])
if t == SADB_EXT_SA {
return binary.LittleEndian.Uint32(buf[4:8]), nil
}
if len(buf) <= int(l) {
break
}
buf = buf[l:]
}
return spi, err
}
func sendSadbMsg(msg *sadbMsg, body []byte) (err error) {
if fd == 0 {
fd, err = syscall.Socket(syscall.AF_KEY, syscall.SOCK_RAW, PF_KEY_V2)
if err != nil {
return err
}
}
seq++
msg.sadbMsgSeq = seq
msg.sadbMsgLen = uint16((len(body) + SADB_MSG_SIZE) / 8)
buf := append(b(unsafe.Pointer(msg), SADB_MSG_SIZE), body...)
r, err := syscall.Write(fd, buf)
if r != len(buf) {
return fmt.Errorf("short write %d %d", r, len(buf))
}
return err
}
func rfkeyRequest(msgType uint8, src, dst string, spi uint32, key string) error {
h := sadbMsg{
sadbMsgVersion: PF_KEY_V2,
sadbMsgType: msgType,
sadbMsgSatype: SADB_X_SATYPE_TCPSIGNATURE,
sadbMsgPid: uint32(os.Getpid()),
}
ssrc := newSockaddrIn(src)
sa_src := sadbAddress{
sadbAddressExttype: SADB_EXT_ADDRESS_SRC,
sadbAddressLen: uint16(SADB_ADDRESS_SIZE+roundUp(int(ssrc.ssLen))) / 8,
}
sdst := newSockaddrIn(dst)
sa_dst := sadbAddress{
sadbAddressExttype: SADB_EXT_ADDRESS_DST,
sadbAddressLen: uint16(SADB_ADDRESS_SIZE+roundUp(int(sdst.ssLen))) / 8,
}
buf := make([]byte, 0)
switch msgType {
case SADB_UPDATE, SADB_DELETE:
sa := sadbSa{
sadbSaLen: uint16(SADB_SA_SIZE / 8),
sadbSaExttype: SADB_EXT_SA,
sadbSaSpi: spi,
sadbSaState: SADB_SASTATE_MATURE,
sadbSaEncrypt: SADB_X_EALG_AES,
}
buf = append(buf, b(unsafe.Pointer(&sa), SADB_SA_SIZE)...)
case SADB_GETSPI:
spirange := sadbSpirange{
sadbSpirangeLen: uint16(SADB_SPIRANGE_SIZE) / 8,
sadbSpirangeExttype: SADB_EXT_SPIRANGE,
sadbSpirangeMin: 0x100,
sadbSpirangeMax: 0xffffffff,
}
buf = append(buf, b(unsafe.Pointer(&spirange), SADB_SPIRANGE_SIZE)...)
}
buf = append(buf, b(unsafe.Pointer(&sa_dst), SADB_ADDRESS_SIZE)...)
buf = append(buf, b(unsafe.Pointer(&sdst), roundUp(int(sdst.ssLen)))...)
buf = append(buf, b(unsafe.Pointer(&sa_src), SADB_ADDRESS_SIZE)...)
buf = append(buf, b(unsafe.Pointer(&ssrc), roundUp(int(ssrc.ssLen)))...)
switch msgType {
case SADB_UPDATE:
keylen := roundUp(len(key))
sa_akey := sadbKey{
sadbKeyLen: uint16((SADB_KEY_SIZE + keylen) / 8),
sadbKeyExttype: SADB_EXT_KEY_AUTH,
sadbKeyBits: uint16(len(key) * 8),
}
k := []byte(key)
if pad := keylen - len(k); pad != 0 {
k = append(k, make([]byte, pad)...)
}
buf = append(buf, b(unsafe.Pointer(&sa_akey), SADB_KEY_SIZE)...)
buf = append(buf, k...)
}
return sendSadbMsg(&h, buf)
}
func saAdd(address, key string) error {
f := func(src, dst string) error {
if err := rfkeyRequest(SADB_GETSPI, src, dst, 0, ""); err != nil {
return err
}
spi, err := pfkeyReply()
if err != nil {
return err
}
if src == "" {
spiOutMap[address] = spi
} else {
spiInMap[address] = spi
}
if err := rfkeyRequest(SADB_UPDATE, src, dst, spi, key); err != nil {
return err
}
_, err = pfkeyReply()
return err
}
if err := f(address, ""); err != nil {
return err
}
return f("", address)
}
func saDelete(address string) error {
if spi, y := spiInMap[address]; y {
if err := rfkeyRequest(SADB_DELETE, address, "", spi, ""); err != nil {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": address,
}).Info("failed to delete md5 for incoming")
} else {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": address,
}).Info("can't find spi for md5 for incoming")
}
}
if spi, y := spiOutMap[address]; y {
if err := rfkeyRequest(SADB_DELETE, "", address, spi, ""); err != nil {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": address,
}).Info("failed to delete md5 for outgoing")
} else {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": address,
}).Info("can't find spi for md5 for outgoing")
}
}
return nil
}
const (
TCP_MD5SIG = 0x4 // TCP MD5 Signature (RFC2385)
IPV6_MINHOPCOUNT = 73 // Generalized TTL Security Mechanism (RFC5082)
)
func setsockoptTcpMD5Sig(sc syscall.RawConn, address string, key string) error {
if err := setsockOptInt(sc, syscall.IPPROTO_TCP, TCP_MD5SIG, 1); err != nil {
return err
}
if len(key) > 0 {
return saAdd(address, key)
}
return saDelete(address)
}
func SetTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockoptTcpMD5Sig(sc, address, key)
}
func SetListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
family := extractFamilyFromTCPListener(l)
sc, err := l.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func SetTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptIpTtl(sc, family, ttl)
}
func SetTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
level := syscall.IPPROTO_IP
name := syscall.IP_MINTTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = IPV6_MINHOPCOUNT
}
return setsockOptInt(sc, level, name, ttl)
}
type TCPDialer struct {
net.Dialer
// MD5 authentication password.
AuthPassword string
// The TTL value to set outgoing connection.
Ttl uint8
// The minimum TTL value for incoming packets.
TtlMin uint8
}
func (d *TCPDialer) DialTCP(addr string, port int) (*net.TCPConn, error) {
if d.AuthPassword != "" {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting md5 for active connection is not supported")
}
if d.Ttl != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting ttl for active connection is not supported")
}
if d.TtlMin != 0 {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": addr,
}).Warn("setting min ttl for active connection is not supported")
}
raddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(addr, fmt.Sprintf("%d", port)))
if err != nil {
return nil, fmt.Errorf("invalid remote address: %s", err)
}
laddr, err := net.ResolveTCPAddr("tcp", d.LocalAddr.String())
if err != nil {
return nil, fmt.Errorf("invalid local address: %s", err)
}
dialer := net.Dialer{LocalAddr: laddr, Timeout: d.Timeout}
conn, err := dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !linux,!dragonfly,!freebsd,!netbsd,!openbsd,!darwin
package server
import (
"fmt"
"net"
)
func setTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return fmt.Errorf("setting md5 is not supported")
}
func setListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
return fmt.Errorf("setting ttl is not supported")
}
func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
return fmt.Errorf("setting ttl is not supported")
}
func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return fmt.Errorf("setting min ttl is not supported")
}

116
vendor/github.com/osrg/gobgp/pkg/server/util.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"net"
"strings"
"syscall"
"github.com/eapache/channels"
"github.com/osrg/gobgp/pkg/packet/bgp"
)
func cleanInfiniteChannel(ch *channels.InfiniteChannel) {
ch.Close()
// drain all remaining items
for range ch.Out() {
}
}
// Returns the binary formatted Administrative Shutdown Communication from the
// given string value.
func newAdministrativeCommunication(communication string) (data []byte) {
if communication == "" {
return nil
}
com := []byte(communication)
if len(com) > bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX {
data = []byte{bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX}
data = append(data, com[:bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX]...)
} else {
data = []byte{byte(len(com))}
data = append(data, com...)
}
return data
}
// Parses the given NOTIFICATION message data as a binary value and returns
// the Administrative Shutdown Communication in string and the rest binary.
func decodeAdministrativeCommunication(data []byte) (string, []byte) {
if len(data) == 0 {
return "", data
}
communicationLen := int(data[0])
if communicationLen > bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX {
communicationLen = bgp.BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX
}
if communicationLen > len(data)+1 {
communicationLen = len(data) + 1
}
return string(data[1 : communicationLen+1]), data[communicationLen+1:]
}
func extractFamilyFromTCPListener(l *net.TCPListener) int {
family := syscall.AF_INET
if strings.Contains(l.Addr().String(), "[") {
family = syscall.AF_INET6
}
return family
}
func extractFamilyFromTCPConn(conn *net.TCPConn) int {
family := syscall.AF_INET
if strings.Contains(conn.RemoteAddr().String(), "[") {
family = syscall.AF_INET6
}
return family
}
func setsockOptString(sc syscall.RawConn, level int, opt int, str string) error {
var opterr error
fn := func(s uintptr) {
opterr = syscall.SetsockoptString(int(s), level, opt, str)
}
err := sc.Control(fn)
if opterr == nil {
return err
}
return opterr
}
func setsockOptInt(sc syscall.RawConn, level, name, value int) error {
var opterr error
fn := func(s uintptr) {
opterr = syscall.SetsockoptInt(int(s), level, name, value)
}
err := sc.Control(fn)
if opterr == nil {
return err
}
return opterr
}
func setsockoptIpTtl(sc syscall.RawConn, family int, value int) error {
level := syscall.IPPROTO_IP
name := syscall.IP_TTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = syscall.IPV6_UNICAST_HOPS
}
return setsockOptInt(sc, level, name, value)
}

456
vendor/github.com/osrg/gobgp/pkg/server/zclient.go generated vendored Normal file
View File

@@ -0,0 +1,456 @@
// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
"math"
"net"
"strconv"
"strings"
"syscall"
"time"
"github.com/osrg/gobgp/internal/pkg/table"
"github.com/osrg/gobgp/internal/pkg/zebra"
"github.com/osrg/gobgp/pkg/packet/bgp"
log "github.com/sirupsen/logrus"
)
// nexthopStateCache stores a map of nexthop IP to metric value. Especially,
// the metric value of math.MaxUint32 means the nexthop is unreachable.
type nexthopStateCache map[string]uint32
func (m nexthopStateCache) applyToPathList(paths []*table.Path) []*table.Path {
updated := make([]*table.Path, 0, len(paths))
for _, path := range paths {
if path == nil || path.IsWithdraw {
continue
}
metric, ok := m[path.GetNexthop().String()]
if !ok {
continue
}
isNexthopInvalid := metric == math.MaxUint32
med, err := path.GetMed()
if err == nil && med == metric && path.IsNexthopInvalid == isNexthopInvalid {
// If the nexthop state of the given path is already up to date,
// skips this path.
continue
}
newPath := path.Clone(false)
if isNexthopInvalid {
newPath.IsNexthopInvalid = true
} else {
newPath.IsNexthopInvalid = false
newPath.SetMed(int64(metric), true)
}
updated = append(updated, newPath)
}
return updated
}
func (m nexthopStateCache) updateByNexthopUpdate(body *zebra.NexthopUpdateBody) (updated bool) {
if len(body.Nexthops) == 0 {
// If NEXTHOP_UPDATE message does not contain any nexthop, the given
// nexthop is unreachable.
if _, ok := m[body.Prefix.Prefix.String()]; !ok {
// Zebra will send an empty NEXTHOP_UPDATE message as the fist
// response for the NEXTHOP_REGISTER message. Here ignores it.
return false
}
m[body.Prefix.Prefix.String()] = math.MaxUint32 // means unreachable
} else {
m[body.Prefix.Prefix.String()] = body.Metric
}
return true
}
func (m nexthopStateCache) filterPathToRegister(paths []*table.Path) []*table.Path {
filteredPaths := make([]*table.Path, 0, len(paths))
for _, path := range paths {
// Here filters out:
// - Nil path
// - Withdrawn path
// - External path (advertised from Zebra) in order avoid sending back
// - Unspecified nexthop address
// - Already registered nexthop
if path == nil || path.IsWithdraw || path.IsFromExternal() {
continue
} else if nexthop := path.GetNexthop(); nexthop.IsUnspecified() {
continue
} else if _, ok := m[nexthop.String()]; ok {
continue
}
filteredPaths = append(filteredPaths, path)
}
return filteredPaths
}
func filterOutExternalPath(paths []*table.Path) []*table.Path {
filteredPaths := make([]*table.Path, 0, len(paths))
for _, path := range paths {
// Here filters out:
// - Nil path
// - External path (advertised from Zebra) in order avoid sending back
// - Unreachable path because invalidated by Zebra
if path == nil || path.IsFromExternal() || path.IsNexthopInvalid {
continue
}
filteredPaths = append(filteredPaths, path)
}
return filteredPaths
}
func newIPRouteBody(dst []*table.Path) (body *zebra.IPRouteBody, isWithdraw bool) {
paths := filterOutExternalPath(dst)
if len(paths) == 0 {
return nil, false
}
path := paths[0]
l := strings.SplitN(path.GetNlri().String(), "/", 2)
var prefix net.IP
//nexthops := make([]net.IP, 0, len(paths))
var nexthop zebra.Nexthop
nexthops := make([]zebra.Nexthop, 0, len(paths))
switch path.GetRouteFamily() {
case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN:
if path.GetRouteFamily() == bgp.RF_IPv4_UC {
prefix = path.GetNlri().(*bgp.IPAddrPrefix).IPAddrPrefixDefault.Prefix.To4()
} else {
prefix = path.GetNlri().(*bgp.LabeledVPNIPAddrPrefix).IPAddrPrefixDefault.Prefix.To4()
}
for _, p := range paths {
nexthop.Gate = p.GetNexthop().To4()
nexthops = append(nexthops, nexthop)
}
case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN:
if path.GetRouteFamily() == bgp.RF_IPv6_UC {
prefix = path.GetNlri().(*bgp.IPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16()
} else {
prefix = path.GetNlri().(*bgp.LabeledVPNIPv6AddrPrefix).IPAddrPrefixDefault.Prefix.To16()
}
for _, p := range paths {
nexthop.Gate = p.GetNexthop().To16()
nexthops = append(nexthops, nexthop)
}
default:
return nil, false
}
msgFlags := zebra.MESSAGE_NEXTHOP
plen, _ := strconv.ParseUint(l[1], 10, 8)
med, err := path.GetMed()
if err == nil {
msgFlags |= zebra.MESSAGE_METRIC
}
var flags zebra.FLAG
info := path.GetSource()
if info.AS == info.LocalAS {
flags = zebra.FLAG_IBGP | zebra.FLAG_INTERNAL
} else if info.MultihopTtl > 0 {
flags = zebra.FLAG_INTERNAL
}
return &zebra.IPRouteBody{
Type: zebra.ROUTE_BGP,
Flags: flags,
SAFI: zebra.SAFI_UNICAST,
Message: msgFlags,
Prefix: zebra.Prefix{
Prefix: prefix,
PrefixLen: uint8(plen),
},
Nexthops: nexthops,
Metric: med,
}, path.IsWithdraw
}
func newNexthopRegisterBody(paths []*table.Path, nexthopCache nexthopStateCache) *zebra.NexthopRegisterBody {
paths = nexthopCache.filterPathToRegister(paths)
if len(paths) == 0 {
return nil
}
path := paths[0]
family := path.GetRouteFamily()
nexthops := make([]*zebra.RegisteredNexthop, 0, len(paths))
for _, p := range paths {
nexthop := p.GetNexthop()
var nh *zebra.RegisteredNexthop
switch family {
case bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN:
nh = &zebra.RegisteredNexthop{
Family: syscall.AF_INET,
Prefix: nexthop.To4(),
}
case bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN:
nh = &zebra.RegisteredNexthop{
Family: syscall.AF_INET6,
Prefix: nexthop.To16(),
}
default:
continue
}
nexthops = append(nexthops, nh)
}
// If no nexthop needs to be registered or unregistered, skips to send
// message.
if len(nexthops) == 0 {
return nil
}
return &zebra.NexthopRegisterBody{
Nexthops: nexthops,
}
}
func newNexthopUnregisterBody(family uint16, prefix net.IP) *zebra.NexthopRegisterBody {
return &zebra.NexthopRegisterBody{
Nexthops: []*zebra.RegisteredNexthop{{
Family: family,
Prefix: prefix,
}},
}
}
func newPathFromIPRouteMessage(m *zebra.Message, version uint8) *table.Path {
header := m.Header
body := m.Body.(*zebra.IPRouteBody)
family := body.RouteFamily(version)
isWithdraw := body.IsWithdraw(version)
var nlri bgp.AddrPrefixInterface
pattr := make([]bgp.PathAttributeInterface, 0)
origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)
pattr = append(pattr, origin)
log.WithFields(log.Fields{
"Topic": "Zebra",
"RouteType": body.Type.String(),
"Flag": body.Flags.String(),
"Message": body.Message,
"Family": body.Prefix.Family,
"Prefix": body.Prefix.Prefix,
"PrefixLength": body.Prefix.PrefixLen,
"Nexthop": body.Nexthops,
"Metric": body.Metric,
"Distance": body.Distance,
"Mtu": body.Mtu,
"api": header.Command.String(),
}).Debugf("create path from ip route message.")
switch family {
case bgp.RF_IPv4_UC:
nlri = bgp.NewIPAddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String())
if len(body.Nexthops) > 0 {
pattr = append(pattr, bgp.NewPathAttributeNextHop(body.Nexthops[0].Gate.String()))
}
case bgp.RF_IPv6_UC:
nlri = bgp.NewIPv6AddrPrefix(body.Prefix.PrefixLen, body.Prefix.Prefix.String())
nexthop := ""
if len(body.Nexthops) > 0 {
nexthop = body.Nexthops[0].Gate.String()
}
pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
default:
log.WithFields(log.Fields{
"Topic": "Zebra",
}).Errorf("unsupport address family: %s", family)
return nil
}
med := bgp.NewPathAttributeMultiExitDisc(body.Metric)
pattr = append(pattr, med)
path := table.NewPath(nil, nlri, isWithdraw, pattr, time.Now(), false)
path.SetIsFromExternal(true)
return path
}
type zebraClient struct {
client *zebra.Client
server *BgpServer
nexthopCache nexthopStateCache
dead chan struct{}
}
func (z *zebraClient) getPathListWithNexthopUpdate(body *zebra.NexthopUpdateBody) []*table.Path {
rib := &table.TableManager{
Tables: make(map[bgp.RouteFamily]*table.Table),
}
var rfList []bgp.RouteFamily
switch body.Prefix.Family {
case syscall.AF_INET:
rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv4_VPN}
case syscall.AF_INET6:
rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC, bgp.RF_IPv6_VPN}
}
for _, rf := range rfList {
tbl, _, err := z.server.getRib("", rf, nil)
if err != nil {
log.WithFields(log.Fields{
"Topic": "Zebra",
"Family": rf.String(),
"Error": err,
}).Error("failed to get global rib")
continue
}
rib.Tables[rf] = tbl
}
return rib.GetPathListWithNexthop(table.GLOBAL_RIB_NAME, rfList, body.Prefix.Prefix)
}
func (z *zebraClient) updatePathByNexthopCache(paths []*table.Path) {
paths = z.nexthopCache.applyToPathList(paths)
if len(paths) > 0 {
if err := z.server.updatePath("", paths); err != nil {
log.WithFields(log.Fields{
"Topic": "Zebra",
"PathList": paths,
}).Error("failed to update nexthop reachability")
}
}
}
func (z *zebraClient) loop() {
w := z.server.Watch([]WatchOption{
WatchBestPath(true),
WatchPostUpdate(true),
}...)
defer w.Stop()
for {
select {
case <-z.dead:
return
case msg := <-z.client.Receive():
switch body := msg.Body.(type) {
case *zebra.IPRouteBody:
if path := newPathFromIPRouteMessage(msg, z.client.Version); path != nil {
if err := z.server.addPathList("", []*table.Path{path}); err != nil {
log.WithFields(log.Fields{
"Topic": "Zebra",
"Path": path,
"Error": err,
}).Error("failed to add path from zebra")
}
}
case *zebra.NexthopUpdateBody:
if updated := z.nexthopCache.updateByNexthopUpdate(body); !updated {
continue
}
paths := z.getPathListWithNexthopUpdate(body)
if len(paths) == 0 {
// If there is no path bound for the given nexthop, send
// NEXTHOP_UNREGISTER message.
z.client.SendNexthopRegister(msg.Header.VrfId, newNexthopUnregisterBody(uint16(body.Prefix.Family), body.Prefix.Prefix), true)
delete(z.nexthopCache, body.Prefix.Prefix.String())
}
z.updatePathByNexthopCache(paths)
}
case ev := <-w.Event():
switch msg := ev.(type) {
case *WatchEventBestPath:
if table.UseMultiplePaths.Enabled {
for _, paths := range msg.MultiPathList {
z.updatePathByNexthopCache(paths)
if body, isWithdraw := newIPRouteBody(paths); body != nil {
z.client.SendIPRoute(0, body, isWithdraw)
}
if body := newNexthopRegisterBody(paths, z.nexthopCache); body != nil {
z.client.SendNexthopRegister(0, body, false)
}
}
} else {
z.updatePathByNexthopCache(msg.PathList)
for _, path := range msg.PathList {
vrfs := []uint32{0}
if msg.Vrf != nil {
if v, ok := msg.Vrf[path.GetNlri().String()]; ok {
vrfs = append(vrfs, v)
}
}
for _, i := range vrfs {
if body, isWithdraw := newIPRouteBody([]*table.Path{path}); body != nil {
z.client.SendIPRoute(i, body, isWithdraw)
}
if body := newNexthopRegisterBody([]*table.Path{path}, z.nexthopCache); body != nil {
z.client.SendNexthopRegister(i, body, false)
}
}
}
}
case *WatchEventUpdate:
if body := newNexthopRegisterBody(msg.PathList, z.nexthopCache); body != nil {
vrfID := uint32(0)
for _, vrf := range z.server.listVrf() {
if vrf.Name == msg.Neighbor.Config.Vrf {
vrfID = uint32(vrf.Id)
}
}
z.client.SendNexthopRegister(vrfID, body, false)
}
}
}
}
}
func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nhtEnable bool, nhtDelay uint8) (*zebraClient, error) {
l := strings.SplitN(url, ":", 2)
if len(l) != 2 {
return nil, fmt.Errorf("unsupported url: %s", url)
}
var cli *zebra.Client
var err error
for _, ver := range []uint8{version, 2, 3, 4, 5} {
cli, err = zebra.NewClient(l[0], l[1], zebra.ROUTE_BGP, ver)
if err == nil {
break
}
// Retry with another Zebra message version
log.WithFields(log.Fields{
"Topic": "Zebra",
}).Warnf("cannot connect to Zebra with message version %d. going to retry another version...", ver)
}
if cli == nil {
return nil, err
}
// Note: HELLO/ROUTER_ID_ADD messages are automatically sent to negotiate
// the Zebra message version in zebra.NewClient().
// cli.SendHello()
// cli.SendRouterIDAdd()
cli.SendInterfaceAdd()
for _, typ := range protos {
t, err := zebra.RouteTypeFromString(typ, version)
if err != nil {
return nil, err
}
cli.SendRedistribute(t, zebra.VRF_DEFAULT)
}
w := &zebraClient{
client: cli,
server: s,
nexthopCache: make(nexthopStateCache),
dead: make(chan struct{}),
}
go w.loop()
return w, nil
}