Add app source, add vendoring and module support
This commit is contained in:
186
vendor/github.com/osrg/gobgp/internal/pkg/table/adj.go
generated
vendored
Normal file
186
vendor/github.com/osrg/gobgp/internal/pkg/table/adj.go
generated
vendored
Normal 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
|
||||
}
|
||||
1041
vendor/github.com/osrg/gobgp/internal/pkg/table/destination.go
generated
vendored
Normal file
1041
vendor/github.com/osrg/gobgp/internal/pkg/table/destination.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
502
vendor/github.com/osrg/gobgp/internal/pkg/table/message.go
generated
vendored
Normal file
502
vendor/github.com/osrg/gobgp/internal/pkg/table/message.go
generated
vendored
Normal 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
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
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
60
vendor/github.com/osrg/gobgp/internal/pkg/table/roa.go
generated
vendored
Normal 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
|
||||
}
|
||||
451
vendor/github.com/osrg/gobgp/internal/pkg/table/table.go
generated
vendored
Normal file
451
vendor/github.com/osrg/gobgp/internal/pkg/table/table.go
generated
vendored
Normal 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,
|
||||
}
|
||||
}
|
||||
370
vendor/github.com/osrg/gobgp/internal/pkg/table/table_manager.go
generated
vendored
Normal file
370
vendor/github.com/osrg/gobgp/internal/pkg/table/table_manager.go
generated
vendored
Normal 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
53
vendor/github.com/osrg/gobgp/internal/pkg/table/vrf.go
generated
vendored
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user