policy: support community action

This commit is contained in:
Hiroshi Yokoi
2015-05-21 16:46:24 +09:00
parent 34e43ed4fb
commit dffb57e43d
3 changed files with 560 additions and 110 deletions
+175 -86
View File
@@ -23,8 +23,8 @@ import (
"github.com/osrg/gobgp/packet"
"github.com/osrg/gobgp/table"
"net"
"regexp"
"reflect"
"regexp"
"strconv"
"strings"
)
@@ -102,19 +102,22 @@ func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
conditions = append(conditions, cc)
}
action := &RoutingActions{
AcceptRoute: false,
}
// routeing action
ra := NewRoutingAction(statement.Actions)
if statement.Actions.AcceptRoute {
action.AcceptRoute = true
// modification action
mda := make([]Action, 0)
com := NewCommunityAction(statement.Actions.BgpActions.SetCommunity)
if com != nil {
mda = append(mda, com)
}
s := &Statement{
Name: statement.Name,
Conditions: conditions,
Actions: action,
MatchSetOptions: statement.Conditions.MatchSetOptions,
Name: statement.Name,
Conditions: conditions,
routingAction: ra,
modificationActions: mda,
MatchSetOptions: statement.Conditions.MatchSetOptions,
}
st = append(st, s)
@@ -124,10 +127,11 @@ func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
}
type Statement struct {
Name string
Conditions []Condition
Actions Actions
MatchSetOptions config.MatchSetOptionsType
Name string
Conditions []Condition
routingAction *RoutingAction
modificationActions []Action
MatchSetOptions config.MatchSetOptionsType
}
// evaluate each condition in the statement according to MatchSetOptions
@@ -489,75 +493,24 @@ type CommunityElement struct {
// CommunityCondition supports uint and string like 65000:100
// and also supports regular expressions that are available in golang.
// if GoBGP can't parse the regular expression, it return nil and an error message is logged.
func NewCommunityCondition(communitySetName string, defAsPathSetList []config.CommunitySet) *CommunityCondition {
// check format
regUint, _ := regexp.Compile("^([0-9]+)$")
regString, _ := regexp.Compile("([0-9]+):([0-9]+)")
regWellKnown, _ := regexp.Compile("^(" +
COMMUNITY_INTERNET + "|" +
COMMUNITY_NO_EXPORT + "|" +
COMMUNITY_NO_ADVERTISE + "|" +
COMMUNITY_NO_EXPORT_SUBCONFED + ")$")
func NewCommunityCondition(communitySetName string, defCommunitySetList []config.CommunitySet) *CommunityCondition {
communityList := make([]*CommunityElement, 0)
for _, asPathSet := range defAsPathSetList {
if asPathSet.CommunitySetName == communitySetName {
for _, as := range asPathSet.CommunityMembers {
for _, communitySet := range defCommunitySetList {
if communitySet.CommunitySetName == communitySetName {
for _, c := range communitySet.CommunityMembers {
e := &CommunityElement{
isRegExp: false,
isRegExp: false,
communityStr: c,
}
if regUint.MatchString(as) {
// specified by Uint
community, err := strconv.ParseUint(as, 10, 32)
if err != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Condition",
}).Error("failed to parse the community value.")
return nil
}
e.community = uint32(community)
e.communityStr = as
} else if regString.MatchString(as) {
// specified by string containing ":"
group := regString.FindStringSubmatch(as)
asn, errAsn := strconv.ParseUint(group[1], 10, 16)
val, errVal := strconv.ParseUint(group[2], 10, 16)
if errAsn != nil || errVal != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Condition",
}).Error("failed to parser as number or community value.")
return nil
}
e.community = uint32(asn<<16 | val)
e.communityStr = as
} else if regWellKnown.MatchString(as) {
// specified by well known community name
e.communityStr = as
switch as {
case COMMUNITY_INTERNET:
e.community = COMMUNITY_INTERNET_VAL
case COMMUNITY_NO_EXPORT:
e.community = COMMUNITY_NO_EXPORT_VAL
case COMMUNITY_NO_ADVERTISE:
e.community = COMMUNITY_NO_ADVERTISE_VAL
case COMMUNITY_NO_EXPORT_SUBCONFED:
e.community = COMMUNITY_NO_EXPORT_SUBCONFED_VAL
}
if matched, v := getCommunityValue(c); matched {
e.community = v
} else {
// specified by regular expression
e.isRegExp = true
e.communityStr = as
reg, err := regexp.Compile(as)
reg, err := regexp.Compile(c)
if err != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
@@ -579,6 +532,63 @@ func NewCommunityCondition(communitySetName string, defAsPathSetList []config.Co
return nil
}
// getCommunityValue returns uint32 community value converted from the string.
// if the string doesn't match a number or string like "65000:1000" or well known
// community name, it returns false and 0, otherwise returns true and its uint32 value.
func getCommunityValue(comStr string) (bool, uint32) {
// community regexp
regUint, _ := regexp.Compile("^([0-9]+)$")
regString, _ := regexp.Compile("([0-9]+):([0-9]+)")
regWellKnown, _ := regexp.Compile("^(" +
COMMUNITY_INTERNET + "|" +
COMMUNITY_NO_EXPORT + "|" +
COMMUNITY_NO_ADVERTISE + "|" +
COMMUNITY_NO_EXPORT_SUBCONFED + ")$")
if regUint.MatchString(comStr) {
// specified by Uint
community, err := strconv.ParseUint(comStr, 10, 32)
if err != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Condition",
}).Error("failed to parse the community value.")
}
return true, uint32(community)
} else if regString.MatchString(comStr) {
// specified by string containing ":"
group := regString.FindStringSubmatch(comStr)
asn, errAsn := strconv.ParseUint(group[1], 10, 16)
val, errVal := strconv.ParseUint(group[2], 10, 16)
if errAsn != nil || errVal != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Condition",
}).Error("failed to parser as number or community value.")
}
community := uint32(asn<<16 | val)
return true, community
} else if regWellKnown.MatchString(comStr) {
// specified by well known community name
var community uint32
switch comStr {
case COMMUNITY_INTERNET:
community = COMMUNITY_INTERNET_VAL
case COMMUNITY_NO_EXPORT:
community = COMMUNITY_NO_EXPORT_VAL
case COMMUNITY_NO_ADVERTISE:
community = COMMUNITY_NO_ADVERTISE_VAL
case COMMUNITY_NO_EXPORT_SUBCONFED:
community = COMMUNITY_NO_EXPORT_SUBCONFED_VAL
}
return true, community
}
return false, 0
}
// compare community in the message's attribute with
// the one in the condition.
func (c *CommunityCondition) evaluate(path table.Path) bool {
@@ -626,23 +636,30 @@ func (c *CommunityCondition) evaluate(path table.Path) bool {
return false
}
type Actions interface {
type Action interface {
apply(table.Path) table.Path
}
type DefaultActions struct {
type DefaultAction struct {
}
func (a *DefaultActions) apply(path table.Path) table.Path {
func (a *DefaultAction) apply(path table.Path) table.Path {
return path
}
type RoutingActions struct {
DefaultActions
type RoutingAction struct {
DefaultAction
AcceptRoute bool
}
func (r *RoutingActions) apply(path table.Path) table.Path {
func NewRoutingAction(action config.Actions) *RoutingAction {
r := &RoutingAction{
AcceptRoute: action.AcceptRoute,
}
return r
}
func (r *RoutingAction) apply(path table.Path) table.Path {
if r.AcceptRoute {
return path
} else {
@@ -650,10 +667,76 @@ func (r *RoutingActions) apply(path table.Path) table.Path {
}
}
type ModificationActions struct {
DefaultActions
AttrType bgp.BGPAttrType
Value string
type ActionType int
type CommunityAction struct {
DefaultAction
Values []uint32
action ActionType
}
const (
COMMUNITY_ACTION_ADD string = "ADD"
COMMUNITY_ACTION_REPLACE = "REPLACE"
COMMUNITY_ACTION_REMOVE = "REMOVE"
COMMUNITY_ACTION_NULL = "NULL"
)
// NewCommunityAction creates CommunityAction object.
// If it cannot parse community string, then return nil.
// Similarly, if option string is invalid, return nil.
func NewCommunityAction(action config.SetCommunity) *CommunityAction {
m := &CommunityAction{}
values := make([]uint32, len(action.Communities))
for i, com := range action.Communities {
matched, value := getCommunityValue(com)
if matched {
values[i] = value
} else {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Action",
}).Error("community string invalid.")
return nil
}
}
m.Values = values
switch action.Options {
case COMMUNITY_ACTION_ADD:
m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD
case COMMUNITY_ACTION_REMOVE:
m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE
case COMMUNITY_ACTION_REPLACE:
m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE
case COMMUNITY_ACTION_NULL:
m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_NULL
default:
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Action",
}).Error("action string should be ADD or REMOVE or REPLACE or NULL.")
return nil
}
return m
}
func (a *CommunityAction) apply(path table.Path) table.Path {
list := a.Values
switch a.action {
case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD:
path.SetCommunities(list, false)
case config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE:
path.RemoveCommunities(list)
case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE:
path.SetCommunities(list, true)
case config.BGP_SET_COMMUNITY_OPTION_TYPE_NULL:
path.ClearCommunities()
}
return path
}
type Prefix struct {
@@ -724,8 +807,13 @@ func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) {
var p table.Path
if result {
p = statement.Actions.apply(path)
//Routing action
p = statement.routingAction.apply(path)
if p != nil {
// apply all modification actions
for _, action := range statement.modificationActions {
p = action.apply(p)
}
return true, ROUTE_TYPE_ACCEPT, p
} else {
return true, ROUTE_TYPE_REJECT, nil
@@ -851,7 +939,8 @@ func (p *Policy) ToApiStruct() *api.PolicyDefinition {
AcceptRoute: false,
RejectRoute: true,
}
if st.Actions.(*RoutingActions).AcceptRoute {
if st.routingAction.AcceptRoute {
resAction.AcceptRoute = true
resAction.RejectRoute = false
}
+300 -22
View File
@@ -926,13 +926,6 @@ func TestConditionConditionEvaluate(t *testing.T) {
log.SetLevel(log.DebugLevel)
strToCom := func(s string) uint32 {
elem := strings.Split(s, ":")
asn, _ := strconv.ParseUint(elem[0], 10, 16)
val, _ := strconv.ParseUint(elem[1], 10, 16)
return uint32(asn<<16 | val)
}
// setup
// create path
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
@@ -945,10 +938,10 @@ func TestConditionConditionEvaluate(t *testing.T) {
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
communities := bgp.NewPathAttributeCommunities([]uint32{
strToCom("65001:100"),
strToCom("65001:200"),
strToCom("65001:300"),
strToCom("65001:400"),
stringToCommunityValue("65001:100"),
stringToCommunityValue("65001:200"),
stringToCommunityValue("65001:300"),
stringToCommunityValue("65001:400"),
0x00000000,
0xFFFFFF01,
0xFFFFFF02,
@@ -1029,13 +1022,6 @@ func TestConditionConditionEvaluateWithOtherCondition(t *testing.T) {
log.SetLevel(log.DebugLevel)
strToCom := func(s string) uint32 {
elem := strings.Split(s, ":")
asn, _ := strconv.ParseUint(elem[0], 10, 16)
val, _ := strconv.ParseUint(elem[1], 10, 16)
return uint32(asn<<16 | val)
}
// setup
// create path
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
@@ -1048,10 +1034,10 @@ func TestConditionConditionEvaluateWithOtherCondition(t *testing.T) {
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
communities := bgp.NewPathAttributeCommunities([]uint32{
strToCom("65001:100"),
strToCom("65001:200"),
strToCom("65001:300"),
strToCom("65001:400"),
stringToCommunityValue("65001:100"),
stringToCommunityValue("65001:200"),
stringToCommunityValue("65001:300"),
stringToCommunityValue("65001:400"),
0x00000000,
0xFFFFFF01,
0xFFFFFF02,
@@ -1162,4 +1148,296 @@ func TestConditionConditionEvaluateWithOtherCondition(t *testing.T) {
assert.Equal(t, ROUTE_TYPE_NONE, pType)
assert.Equal(t, nil, newPath)
}
func TestPolicyMatchAndAddCommunities(t *testing.T) {
// create path
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
origin := bgp.NewPathAttributeOrigin(0)
aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
aspath := bgp.NewPathAttributeAsPath(aspathParam)
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")}
withdrawnRoutes := []bgp.WithdrawnRoute{}
updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
path := table.ProcessMessage(updateMsg, peer)[0]
// create policy
ps := config.PrefixSet{
PrefixSetName: "ps1",
PrefixList: []config.Prefix{
config.Prefix{
Address: net.ParseIP("10.10.0.0"),
Masklength: 16,
MasklengthRange: "21..24",
}},
}
ns := config.NeighborSet{
NeighborSetName: "ns1",
NeighborInfoList: []config.NeighborInfo{
config.NeighborInfo{
Address: net.ParseIP("10.0.0.1"),
}},
}
ds := config.DefinedSets{
PrefixSetList: []config.PrefixSet{ps},
NeighborSetList: []config.NeighborSet{ns},
}
community := "65000:100"
s := config.Statement{
Name: "statement1",
Conditions: config.Conditions{
MatchPrefixSet: "ps1",
MatchNeighborSet: "ns1",
MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL,
},
Actions: config.Actions{
AcceptRoute: true,
BgpActions: config.BgpActions{
SetCommunity: config.SetCommunity{
Communities: []string{community},
Options: "ADD",
},
},
},
}
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
df := pl.DefinedSets
p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
assert.NotEqual(t, nil, newPath)
assert.Equal(t, []uint32{stringToCommunityValue(community)}, path.GetCommunities())
}
func TestPolicyMatchAndReplaceCommunities(t *testing.T) {
// create path
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
origin := bgp.NewPathAttributeOrigin(0)
aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
aspath := bgp.NewPathAttributeAsPath(aspathParam)
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
communities := bgp.NewPathAttributeCommunities([]uint32{
stringToCommunityValue("65001:200"),
})
pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")}
withdrawnRoutes := []bgp.WithdrawnRoute{}
updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
path := table.ProcessMessage(updateMsg, peer)[0]
// create policy
ps := config.PrefixSet{
PrefixSetName: "ps1",
PrefixList: []config.Prefix{
config.Prefix{
Address: net.ParseIP("10.10.0.0"),
Masklength: 16,
MasklengthRange: "21..24",
}},
}
ns := config.NeighborSet{
NeighborSetName: "ns1",
NeighborInfoList: []config.NeighborInfo{
config.NeighborInfo{
Address: net.ParseIP("10.0.0.1"),
}},
}
ds := config.DefinedSets{
PrefixSetList: []config.PrefixSet{ps},
NeighborSetList: []config.NeighborSet{ns},
}
community := "65000:100"
s := config.Statement{
Name: "statement1",
Conditions: config.Conditions{
MatchPrefixSet: "ps1",
MatchNeighborSet: "ns1",
MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL,
},
Actions: config.Actions{
AcceptRoute: true,
BgpActions: config.BgpActions{
SetCommunity: config.SetCommunity{
Communities: []string{community},
Options: "REPLACE",
},
},
},
}
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
df := pl.DefinedSets
p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
assert.NotEqual(t, nil, newPath)
assert.Equal(t, []uint32{stringToCommunityValue(community)}, path.GetCommunities())
}
func TestPolicyMatchAndRemoveCommunities(t *testing.T) {
// create path
community1 := "65000:100"
community2 := "65000:200"
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
origin := bgp.NewPathAttributeOrigin(0)
aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
aspath := bgp.NewPathAttributeAsPath(aspathParam)
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
communities := bgp.NewPathAttributeCommunities([]uint32{
stringToCommunityValue(community1),
stringToCommunityValue(community2),
})
pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")}
withdrawnRoutes := []bgp.WithdrawnRoute{}
updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
path := table.ProcessMessage(updateMsg, peer)[0]
// create policy
ps := config.PrefixSet{
PrefixSetName: "ps1",
PrefixList: []config.Prefix{
config.Prefix{
Address: net.ParseIP("10.10.0.0"),
Masklength: 16,
MasklengthRange: "21..24",
}},
}
ns := config.NeighborSet{
NeighborSetName: "ns1",
NeighborInfoList: []config.NeighborInfo{
config.NeighborInfo{
Address: net.ParseIP("10.0.0.1"),
}},
}
ds := config.DefinedSets{
PrefixSetList: []config.PrefixSet{ps},
NeighborSetList: []config.NeighborSet{ns},
}
s := config.Statement{
Name: "statement1",
Conditions: config.Conditions{
MatchPrefixSet: "ps1",
MatchNeighborSet: "ns1",
MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL,
},
Actions: config.Actions{
AcceptRoute: true,
BgpActions: config.BgpActions{
SetCommunity: config.SetCommunity{
Communities: []string{community1},
Options: "REMOVE",
},
},
},
}
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
df := pl.DefinedSets
p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
assert.NotEqual(t, nil, newPath)
assert.Equal(t, []uint32{stringToCommunityValue(community2)}, path.GetCommunities())
}
func TestPolicyMatchAndClearCommunities(t *testing.T) {
// create path
community1 := "65000:100"
community2 := "65000:200"
peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
origin := bgp.NewPathAttributeOrigin(0)
aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
aspath := bgp.NewPathAttributeAsPath(aspathParam)
nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
med := bgp.NewPathAttributeMultiExitDisc(0)
communities := bgp.NewPathAttributeCommunities([]uint32{
stringToCommunityValue(community1),
stringToCommunityValue(community2),
})
pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")}
withdrawnRoutes := []bgp.WithdrawnRoute{}
updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
path := table.ProcessMessage(updateMsg, peer)[0]
// create policy
ps := config.PrefixSet{
PrefixSetName: "ps1",
PrefixList: []config.Prefix{
config.Prefix{
Address: net.ParseIP("10.10.0.0"),
Masklength: 16,
MasklengthRange: "21..24",
}},
}
ns := config.NeighborSet{
NeighborSetName: "ns1",
NeighborInfoList: []config.NeighborInfo{
config.NeighborInfo{
Address: net.ParseIP("10.0.0.1"),
}},
}
ds := config.DefinedSets{
PrefixSetList: []config.PrefixSet{ps},
NeighborSetList: []config.NeighborSet{ns},
}
s := config.Statement{
Name: "statement1",
Conditions: config.Conditions{
MatchPrefixSet: "ps1",
MatchNeighborSet: "ns1",
MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL,
},
Actions: config.Actions{
AcceptRoute: true,
BgpActions: config.BgpActions{
SetCommunity: config.SetCommunity{
Communities: []string{community1},
Options: "NULL",
},
},
},
}
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
df := pl.DefinedSets
p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
assert.NotEqual(t, nil, newPath)
assert.Equal(t, []uint32{}, path.GetCommunities())
}
func stringToCommunityValue(comStr string) uint32 {
elem := strings.Split(comStr, ":")
asn, _ := strconv.ParseUint(elem[0], 10, 16)
val, _ := strconv.ParseUint(elem[1], 10, 16)
return uint32(asn<<16 | val)
}
+85 -2
View File
@@ -37,6 +37,9 @@ type Path interface {
GetAsList() []uint32
GetAsSeqList() []uint32
GetCommunities() []uint32
SetCommunities([]uint32, bool)
RemoveCommunities([]uint32) int
ClearCommunities()
setSource(source *PeerInfo)
GetSource() *PeerInfo
GetSourceAs() uint32
@@ -380,11 +383,11 @@ func (pd *PathDefault) getAsListofSpecificType(getAsSeq, getAsSet bool) []uint32
aspath := attr.(*bgp.PathAttributeAsPath)
for _, paramIf := range aspath.Value {
segment := paramIf.(*bgp.As4PathParam)
if getAsSeq && segment.Type == bgp.BGP_ASPATH_ATTR_TYPE_SEQ{
if getAsSeq && segment.Type == bgp.BGP_ASPATH_ATTR_TYPE_SEQ {
asList = append(asList, segment.AS...)
continue
}
if getAsSet && segment.Type == bgp.BGP_ASPATH_ATTR_TYPE_SET{
if getAsSet && segment.Type == bgp.BGP_ASPATH_ATTR_TYPE_SET {
asList = append(asList, segment.AS...)
}
}
@@ -401,6 +404,86 @@ func (pd *PathDefault) GetCommunities() []uint32 {
return communityList
}
// SetCommunities adds or replaces communities with new ones.
// If the length of communites is 0, it does nothing.
func (pd *PathDefault) SetCommunities(communities []uint32, doReplace bool) {
if len(communities) == 0 {
// do nothing
return
}
newList := make([]uint32, 0)
idx, attr := pd.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
if attr != nil {
c := attr.(*bgp.PathAttributeCommunities)
if doReplace {
newList = append(newList, communities...)
} else {
newList = append(newList, c.Value...)
newList = append(newList, communities...)
}
newCommunities := bgp.NewPathAttributeCommunities(newList)
pd.pathAttrs[idx] = newCommunities
} else {
newList = append(newList, communities...)
newCommunities := bgp.NewPathAttributeCommunities(newList)
pd.pathAttrs = append(pd.pathAttrs, newCommunities)
}
}
// RemoveCommunities removes specific communities.
// If the length of communites is 0, it does nothing.
// If all communities are removed, it removes Communities path attribute itself.
func (pd *PathDefault) RemoveCommunities(communities []uint32) int {
if len(communities) == 0 {
// do nothing
return 0
}
find := func(val uint32) bool {
for _, com := range communities {
if com == val {
return true
}
}
return false
}
count := 0
idx, attr := pd.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
if attr != nil {
newList := make([]uint32, 0)
c := attr.(*bgp.PathAttributeCommunities)
for _, value := range c.Value {
if find(value) {
count += 1
} else {
newList = append(newList, value)
}
}
if len(newList) != 0 {
newCommunities := bgp.NewPathAttributeCommunities(newList)
pd.pathAttrs[idx] = newCommunities
} else {
pd.pathAttrs = append(pd.pathAttrs[:idx], pd.pathAttrs[idx+1:]...)
}
}
return count
}
// ClearCommunities removes Communities path attribute.
func (pd *PathDefault) ClearCommunities() {
idx, _ := pd.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
if idx >= 0 {
pd.pathAttrs = append(pd.pathAttrs[:idx], pd.pathAttrs[idx+1:]...)
}
}
// create Path object based on route family
func CreatePath(source *PeerInfo, nlri bgp.AddrPrefixInterface, attrs []bgp.PathAttributeInterface, isWithdraw bool, now time.Time) (Path, error) {