mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
policy: support community action
This commit is contained in:
+175
-86
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user