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

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
}