summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--policy/policy.go56
-rw-r--r--policy/policy_test.go88
2 files changed, 135 insertions, 9 deletions
diff --git a/policy/policy.go b/policy/policy.go
index 62a667af..06921eab 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -1009,9 +1009,10 @@ func (r *RoutingAction) apply(path *table.Path) *table.Path {
}
type CommunityAction struct {
- Values []uint32
- ext []byte
- action config.BgpSetCommunityOptionType
+ Values []uint32
+ ext []byte
+ action config.BgpSetCommunityOptionType
+ RegexpValues []*regexp.Regexp
}
const (
@@ -1032,20 +1033,39 @@ func NewCommunityAction(action config.SetCommunity) *CommunityAction {
return nil
}
- values := make([]uint32, len(communities))
- for i, com := range communities {
+ values := make([]uint32, 0, len(communities))
+ regexpValues := make([]*regexp.Regexp, 0, len(communities))
+
+ for _, com := range communities {
matched, value := getCommunityValue(com)
if matched {
- values[i] = value
- } else {
+ values = append(values, value)
+ continue
+ }
+
+ exp, err := regexp.Compile(com)
+ if err != nil {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "Community Action",
- }).Error("community string invalid.")
+ }).Errorf("community string invalid")
return nil
}
+ regexpValues = append(regexpValues, exp)
+ }
+ if len(values) > 0 {
+ m.Values = values
+ }
+ if len(regexpValues) > 0 {
+ if action.Options != COMMUNITY_ACTION_REMOVE {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Community Action",
+ }).Error("regexp values can only be used for remove action")
+ return nil
+ }
+ m.RegexpValues = regexpValues
}
- m.Values = values
switch action.Options {
case COMMUNITY_ACTION_ADD:
@@ -1064,6 +1084,21 @@ func NewCommunityAction(action config.SetCommunity) *CommunityAction {
return m
}
+func RegexpRemoveCommunities(path *table.Path, exps []*regexp.Regexp) {
+ comms := path.GetCommunities()
+ newComms := make([]uint32, 0, len(comms))
+ for _, comm := range comms {
+ c := fmt.Sprintf("%d:%d", comm>>16, comm&0x0000ffff)
+ for _, exp := range exps {
+ if !exp.MatchString(c) {
+ newComms = append(newComms, comm)
+ break
+ }
+ }
+ }
+ path.SetCommunities(newComms, true)
+}
+
func (a *CommunityAction) apply(path *table.Path) *table.Path {
if len(a.ext) > 0 {
return a.extApply(path)
@@ -1074,6 +1109,9 @@ func (a *CommunityAction) apply(path *table.Path) *table.Path {
path.SetCommunities(list, false)
case config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE:
path.RemoveCommunities(list)
+ if len(a.RegexpValues) > 0 {
+ RegexpRemoveCommunities(path, a.RegexpValues)
+ }
case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE:
path.SetCommunities(list, true)
}
diff --git a/policy/policy_test.go b/policy/policy_test.go
index 246c77b3..de8d4691 100644
--- a/policy/policy_test.go
+++ b/policy/policy_test.go
@@ -1244,6 +1244,94 @@ func TestPolicyMatchAndRemoveCommunities(t *testing.T) {
assert.Equal(t, []uint32{stringToCommunityValue(community2)}, newPath.GetCommunities())
}
+func TestPolicyMatchAndRemoveCommunitiesRegexp(t *testing.T) {
+
+ // create path
+ community1 := "65000:100"
+ community2 := "65000:200"
+ community3 := "65100:100"
+ 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),
+ stringToCommunityValue(community3),
+ })
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := table.ProcessMessage(updateMsg, peer)[0]
+ // create policy
+ ps := createPrefixSet("ps1", "10.10.0.0/16", "21..24")
+ ns := createNeighborSet("ns1", "10.0.0.1")
+
+ ds := config.DefinedSets{}
+ ds.PrefixSets.PrefixSetList = []config.PrefixSet{ps}
+ ds.NeighborSets.NeighborSetList = []config.NeighborSet{ns}
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetCommunity = createSetCommunity("REMOVE", ".*:100")
+
+ pd := createPolicyDefinition("pd1", s)
+ pl := createRoutingPolicy(ds, pd)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
+ assert.NotEqual(t, nil, newPath)
+ assert.Equal(t, []uint32{stringToCommunityValue(community2)}, newPath.GetCommunities())
+}
+
+func TestPolicyMatchAndRemoveCommunitiesRegexp2(t *testing.T) {
+
+ // create path
+ community1 := "0:1"
+ community2 := "10:1"
+ community3 := "45686:2"
+ 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),
+ stringToCommunityValue(community3),
+ })
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := table.ProcessMessage(updateMsg, peer)[0]
+ // create policy
+ ps := createPrefixSet("ps1", "10.10.0.0/16", "21..24")
+ ns := createNeighborSet("ns1", "10.0.0.1")
+
+ ds := config.DefinedSets{}
+ ds.PrefixSets.PrefixSetList = []config.PrefixSet{ps}
+ ds.NeighborSets.NeighborSetList = []config.NeighborSet{ns}
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetCommunity = createSetCommunity("REMOVE", "^(0|45686):[0-9]+")
+
+ pd := createPolicyDefinition("pd1", s)
+ pl := createRoutingPolicy(ds, pd)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
+ assert.NotEqual(t, nil, newPath)
+ assert.Equal(t, []uint32{stringToCommunityValue(community2)}, newPath.GetCommunities())
+}
+
func TestPolicyMatchAndClearCommunities(t *testing.T) {
// create path