summaryrefslogtreecommitdiffhomepage
path: root/policy
diff options
context:
space:
mode:
authorHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-05-19 19:30:26 +0900
committerHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-05-19 20:14:43 +0900
commitf91a3a61b48fb7a3aad6aac492d487fb72b32a34 (patch)
treef1244dbec6e795c3de599911d26913cb8b94b2b7 /policy
parentcd4412ae538542ca7dc7f599bc30b7ac2b14fbb2 (diff)
policy: support aspath condition
Diffstat (limited to 'policy')
-rw-r--r--policy/policy.go131
-rw-r--r--policy/policy_test.go187
2 files changed, 302 insertions, 16 deletions
diff --git a/policy/policy.go b/policy/policy.go
index 236ffa6d..b701bd4a 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -23,6 +23,7 @@ import (
"github.com/osrg/gobgp/packet"
"github.com/osrg/gobgp/table"
"net"
+ "regexp"
"reflect"
"strconv"
"strings"
@@ -59,11 +60,11 @@ type Policy struct {
Statements []*Statement
}
-func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
+func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
stmtList := pd.StatementList
st := make([]*Statement, 0)
p := &Policy{
- Name: name,
+ Name: pd.Name,
}
for _, statement := range stmtList {
@@ -87,6 +88,13 @@ func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) *
conditions = append(conditions, ac)
}
+ // AsPathCondition
+ asPathSetName := statement.Conditions.BgpConditions.MatchAsPathSet
+ asc := NewAsPathCondition(asPathSetName, ds.BgpDefinedSets.AsPathSetList)
+ if asc != nil {
+ conditions = append(conditions, asc)
+ }
+
action := &RoutingActions{
AcceptRoute: false,
}
@@ -265,6 +273,7 @@ func (c *NeighborCondition) evaluate(path table.Path) bool {
cAddr := neighbor
pAddr := path.GetSource().Address
if pAddr.Equal(cAddr) {
+ log.Debug("neighbor matched : ", pAddr.String())
return true
}
}
@@ -325,6 +334,124 @@ func (c *AsPathLengthCondition) evaluate(path table.Path) bool {
}
+type AsPathCondition struct {
+ DefaultCondition
+ AsPathList []*AsPathElement
+}
+
+type AsnPos int
+
+const (
+ AS_FROM AsnPos = iota
+ AS_ANY
+ AS_ORIGIN
+ AS_ONLY
+)
+
+type AsPathElement struct {
+ postiion AsnPos
+ asn uint32
+}
+
+// create AsPathCondition object
+// AsPathCondition supports only following regexp:
+// - ^100 (from as100)
+// - ^100$ (from as100 and originated by as100)
+// - 100$ (originated by as100)
+// - 100 (from or through or originated by as100)
+func NewAsPathCondition(asPathSetName string, defAsPathSetList []config.AsPathSet) *AsPathCondition {
+
+ regAsn, _ := regexp.Compile("^(\\^?)([0-9]+)(\\$?)$")
+
+ asPathList := make([]*AsPathElement, 0)
+ for _, asPathSet := range defAsPathSetList {
+ if asPathSet.AsPathSetName == asPathSetName {
+ for _, as := range asPathSet.AsPathSetMembers {
+ if regAsn.MatchString(as) {
+
+ group := regAsn.FindStringSubmatch(as)
+ asn, err := strconv.Atoi(group[2])
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ }).Error("cannot parse AS Number.")
+ return nil
+ }
+ e := &AsPathElement{}
+ e.asn = uint32(asn)
+
+ if len(group[1]) == 0 && len(group[3]) == 0 {
+ e.postiion = AS_ANY
+ } else if len(group[1]) == 1 && len(group[3]) == 0 {
+ e.postiion = AS_FROM
+ } else if len(group[1]) == 0 && len(group[3]) == 1 {
+ e.postiion = AS_ORIGIN
+ } else {
+ e.postiion = AS_ONLY
+ }
+
+ asPathList = append(asPathList, e)
+
+ } else {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ }).Error("cannot parse AS_PATH condition value.")
+
+ return nil
+ }
+ }
+
+ c := &AsPathCondition{
+ AsPathList: asPathList,
+ }
+ return c
+ }
+ }
+ return nil
+}
+
+// compare AS_PATH in the message's AS_PATH attribute with
+// the one in condition.
+func (c *AsPathCondition) evaluate(path table.Path) bool {
+
+ aspath := path.GetAsSeqList()
+
+ if len(aspath) == 0 {
+ return false
+ }
+
+ matched := false
+ for _, member := range c.AsPathList {
+
+ switch member.postiion {
+ case AS_FROM:
+ matched = aspath[0] == member.asn
+ case AS_ANY:
+ for _, n := range aspath {
+ if n == member.asn {
+ matched = true
+ break
+ }
+ }
+ case AS_ORIGIN:
+ matched = aspath[len(aspath)-1] == member.asn
+
+ case AS_ONLY:
+ matched = len(aspath) == 1 && aspath[0] == member.asn
+
+ }
+
+ if matched {
+ log.Debugf("aspath matched : asn=%d, pos=%v)", member.asn, member.postiion)
+ return true
+ }
+
+ }
+ return false
+}
+
type Actions interface {
apply(table.Path) table.Path
}
diff --git a/policy/policy_test.go b/policy/policy_test.go
index ca006ddb..3aa50763 100644
--- a/policy/policy_test.go
+++ b/policy/policy_test.go
@@ -268,9 +268,8 @@ func TestPolicyNotMatch(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, false, match)
assert.Equal(t, ROUTE_TYPE_NONE, pType)
@@ -326,9 +325,8 @@ func TestPolicyMatchAndReject(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_REJECT, pType)
@@ -384,9 +382,8 @@ func TestPolicyMatchAndAccept(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
@@ -448,9 +445,8 @@ func TestPolicyRejectOnlyPrefixSet(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path1)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_REJECT, pType)
@@ -515,9 +511,8 @@ func TestPolicyRejectOnlyNeighborSet(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path1)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_REJECT, pType)
@@ -619,9 +614,8 @@ func TestPolicyDifferentRoutefamilyOfPathAndPolicy(t *testing.T) {
pd := config.PolicyDefinition{"pd1", []config.Statement{stIPv4, stIPv6}}
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match1, pType1, newPath1 := p.Apply(pathIPv4)
assert.Equal(t, true, match1)
assert.Equal(t, ROUTE_TYPE_REJECT, pType1)
@@ -751,12 +745,177 @@ func TestAsPathLengthConditionWithOtherCondition(t *testing.T) {
pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}}
//test
- pName := "pd1"
df := pl.DefinedSets
- p := NewPolicy(pName, pl.PolicyDefinitionList[0], df)
+ p := NewPolicy(pl.PolicyDefinitionList[0], df)
match, pType, newPath := p.Apply(path)
assert.Equal(t, true, match)
assert.Equal(t, ROUTE_TYPE_REJECT, pType)
assert.Equal(t, nil, newPath)
}
+
+func TestAsPathConditionEvaluate(t *testing.T) {
+
+ // setup
+ // create path
+ peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam1 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 65005}),
+ bgp.NewAsPathParam(1, []uint16{65001, 65010, 65004, 65005}),
+ }
+ aspath := bgp.NewPathAttributeAsPath(aspathParam1)
+ 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{}
+ updateMsg1 := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+ table.UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate))
+ path1 := table.ProcessMessage(updateMsg1, peer)[0]
+
+ aspathParam2 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{65010}),
+ bgp.NewAsPathParam(1, []uint16{65010}),
+ }
+ aspath2 := bgp.NewPathAttributeAsPath(aspathParam2)
+ pathAttributes = []bgp.PathAttributeInterface{origin, aspath2, nexthop, med}
+ updateMsg2 := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri)
+ table.UpdatePathAttrs4ByteAs(updateMsg2.Body.(*bgp.BGPUpdate))
+ path2 := table.ProcessMessage(updateMsg2, peer)[0]
+
+ // create match condition
+ asPathSet1 := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathSetMembers: []string{"^65001"},
+ }
+
+ asPathSet2 := config.AsPathSet{
+ AsPathSetName: "asset2",
+ AsPathSetMembers: []string{"65005$"},
+ }
+
+ asPathSet3 := config.AsPathSet{
+ AsPathSetName: "asset3",
+ AsPathSetMembers: []string{"65004", "65005$"},
+ }
+
+ asPathSet4 := config.AsPathSet{
+ AsPathSetName: "asset4",
+ AsPathSetMembers: []string{"65000$"},
+ }
+
+ asPathSet5 := config.AsPathSet{
+ AsPathSetName: "asset5",
+ AsPathSetMembers: []string{"65010"},
+ }
+
+ asPathSet6 := config.AsPathSet{
+ AsPathSetName: "asset6",
+ AsPathSetMembers: []string{"^65010$"},
+ }
+
+ asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3,
+ asPathSet4, asPathSet5, asPathSet6}
+
+ p1 := NewAsPathCondition("asset1", asPathSetList)
+ p2 := NewAsPathCondition("asset2", asPathSetList)
+ p3 := NewAsPathCondition("asset3", asPathSetList)
+ p4 := NewAsPathCondition("asset4", asPathSetList)
+ p5 := NewAsPathCondition("asset5", asPathSetList)
+ p6 := NewAsPathCondition("asset6", asPathSetList)
+
+ // test
+ assert.Equal(t, true, p1.evaluate(path1))
+ assert.Equal(t, true, p2.evaluate(path1))
+ assert.Equal(t, true, p3.evaluate(path1))
+ assert.Equal(t, false, p4.evaluate(path1))
+ assert.Equal(t, false, p5.evaluate(path1))
+ assert.Equal(t, false, p6.evaluate(path1))
+ assert.Equal(t, true, p6.evaluate(path2))
+
+}
+
+func TestAsPathConditionWithOtherCondition(t *testing.T) {
+
+ // setup
+ // 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, 65000, 65004, 65004, 65005}),
+ bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}),
+ }
+ 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)
+ table.UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := table.ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ asPathSet := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathSetMembers: []string{"65005$"},
+ }
+
+ prefixSet := config.PrefixSet{
+ PrefixSetName: "ps1",
+ PrefixList: []config.Prefix{
+ config.Prefix{
+ Address: net.ParseIP("10.11.1.0"),
+ Masklength: 16,
+ MasklengthRange: "21..24",
+ }},
+ }
+
+ neighborSet := config.NeighborSet{
+ NeighborSetName: "ns1",
+ NeighborInfoList: []config.NeighborInfo{
+ config.NeighborInfo{
+ Address: net.ParseIP("10.2.1.1"),
+ }},
+ }
+
+ ds := config.DefinedSets{
+ PrefixSetList: []config.PrefixSet{prefixSet},
+ NeighborSetList: []config.NeighborSet{neighborSet},
+ BgpDefinedSets: config.BgpDefinedSets{
+ AsPathSetList: []config.AsPathSet{asPathSet},
+ },
+ }
+
+ s := config.Statement{
+ Name: "statement1",
+ Conditions: config.Conditions{
+ MatchPrefixSet: "ps1",
+ MatchNeighborSet: "ns1",
+ BgpConditions: config.BgpConditions{
+ MatchAsPathSet: "asset1",
+ },
+ MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY,
+ },
+ Actions: config.Actions{
+ AcceptRoute: false,
+ RejectRoute: true,
+ },
+ }
+
+ pd := config.PolicyDefinition{"pd1", []config.Statement{s}}
+ pl := config.RoutingPolicy{
+ DefinedSets: ds,
+ PolicyDefinitionList: []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_REJECT, pType)
+ assert.Equal(t, nil, newPath)
+
+} \ No newline at end of file