summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNaoto Hanaue <hanaue.naoto@po.ntts.co.jp>2015-08-06 15:13:14 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-08-06 21:59:43 +0900
commitf90d8c6620fba0eafd5bd5528ef8f4b3311a3343 (patch)
tree6ec535a11bb8357be3990a550f466363bc3860d9
parent87a71be40f37a3d39e56d8452bcf122a6b5ce422 (diff)
policy: support the match of consecutive AsPath and regular expressions to AsPath Condition
-rw-r--r--docs/sources/filter-detail.md18
-rw-r--r--policy/policy.go138
-rw-r--r--policy/policy_test.go119
3 files changed, 231 insertions, 44 deletions
diff --git a/docs/sources/filter-detail.md b/docs/sources/filter-detail.md
index b096ed27..f6147547 100644
--- a/docs/sources/filter-detail.md
+++ b/docs/sources/filter-detail.md
@@ -340,6 +340,11 @@ CommunitySets, ExtCommunitySets and AsPathSets section are each match part.
- Origin: "65100$" means the route is originated by AS 65100.
- Only: "^65100$" means the route is originated by AS 65100 and comes from it directly.
+ Further you can specify the consecutive aspath and use regexp in each element as follows:
+ - ^65100_65001
+ - 65100_[0-9]+_.*$
+ - ^6[0-9]_5.*_65.?00$
+
##### Examples
- example 1
- Match routes which come from AS 65100.
@@ -354,6 +359,19 @@ CommunitySets, ExtCommunitySets and AsPathSets section are each match part.
AsPath = "^65100"
```
+ - example 2
+ - Match routes which come Origin AS 65100 and use regular expressions to other AS.
+
+ ```
+ # example 2
+ [DefinedSets.BgpDefinedSets]
+ [DefinedSets.BgpDefinedSets.AsPathSets]
+ [[DefinedSets.BgpDefinedSets.AsPathSets.AsPathSetList]]
+ AsPathSetName = "aspath2"
+ [[DefinedSets.BgpDefinedSets.AsPathSets.AsPathSetList.AsPathList]]
+ AsPath = "[0-9]+_65[0-9]+_65100$"
+ ```
+
---
### 3. Defining PolicyDefinitions
diff --git a/policy/policy.go b/policy/policy.go
index 0ea3d373..70d1bbc3 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -397,8 +397,9 @@ const (
)
type AsPathElement struct {
- postiion AsnPos
- asn uint32
+ postiion AsnPos
+ asStr string
+ asRegExps []*regexp.Regexp
}
// create AsPathCondition object
@@ -412,48 +413,69 @@ func NewAsPathCondition(matchSet config.MatchAsPathSet, defAsPathSetList []confi
asPathSetName := matchSet.AsPathSet
options := matchSet.MatchSetOptions
- regAsn, _ := regexp.Compile("^(\\^?)([0-9]+)(\\$?)$")
asPathList := make([]*AsPathElement, 0)
for _, asPathSet := range defAsPathSetList {
if asPathSet.AsPathSetName == asPathSetName {
for _, aspath := range asPathSet.AsPathList {
a := aspath.AsPath
- if regAsn.MatchString(a) {
-
- group := regAsn.FindStringSubmatch(a)
- 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
+ if len(a) != 0 {
+ isTop := a[:1] == "^"
+ if isTop {
+ a = a[1:]
+ }
+ isEnd := a[len(a)-1:] == "$"
+ if isEnd {
+ a = a[:len(a)-1]
+ }
+ elems := strings.Split(a, "_")
+ asRegExps := make([]*regexp.Regexp, 0)
+ for _, el := range elems {
+ if len(el) == 0 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ "Value": aspath.AsPath,
+ "Elem": el,
+ }).Error("invalid element. do not enter a blank.")
+ return nil
+ }
+ regElem, err := regexp.Compile(el)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ "Value": aspath.AsPath,
+ "Elem": el,
+ "Error": err,
+ }).Error("can not comple AS_PATH values to Regular expressions.")
+ return nil
+ }
+ asRegExps = append(asRegExps, regElem)
}
- 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 := &AsPathElement{}
+ e.asRegExps = asRegExps
+ e.asStr = a
+ if isTop && isEnd {
+ e.postiion = AS_ONLY
+ } else if isTop && !isEnd {
e.postiion = AS_FROM
- } else if len(group[1]) == 0 && len(group[3]) == 1 {
+ } else if !isTop && isEnd {
e.postiion = AS_ORIGIN
} else {
- e.postiion = AS_ONLY
+ e.postiion = AS_ANY
}
-
asPathList = append(asPathList, e)
} else {
log.WithFields(log.Fields{
"Topic": "Policy",
"Type": "AsPath Condition",
- }).Error("cannot parse AS_PATH condition value.")
+ }).Error("does not parse AS_PATH condition value.")
return nil
}
}
-
c := &AsPathCondition{
AsPathList: asPathList,
MatchOption: options,
@@ -465,36 +487,64 @@ func NewAsPathCondition(matchSet config.MatchAsPathSet, defAsPathSetList []confi
}
func (c *AsPathCondition) checkMembers(aspath []uint32, checkAll bool) bool {
- result := false
- if checkAll {
- result = true
- }
- for _, member := range c.AsPathList {
- matched := false
- switch member.postiion {
+ checkElem := func(checkType AsnPos, regElems []*regexp.Regexp) bool {
+ aslen := len(aspath)
+ reglen := len(regElems)
+
+ if aslen < reglen {
+ return false
+ }
+
+ switch checkType {
+ case AS_ONLY:
+ if aslen != reglen {
+ return false
+ }
+ fallthrough
case AS_FROM:
- matched = aspath[0] == member.asn
+ for i := 0; i < reglen; i++ {
+ if !regElems[i].MatchString(fmt.Sprintf("%d", aspath[i])) {
+ return false
+ }
+ }
+ case AS_ORIGIN:
+ for i := 0; i < reglen; i++ {
+ if !regElems[reglen-i-1].MatchString(fmt.Sprintf("%d", aspath[aslen-i-1])) {
+ return false
+ }
+ }
case AS_ANY:
- for _, n := range aspath {
- if n == member.asn {
- matched = true
+ for i := 0; i < aslen; i++ {
+ eMatched := true
+ if aslen < i+reglen {
break
}
+ for j := 0; j < reglen; j++ {
+ if !regElems[j].MatchString(fmt.Sprintf("%d", aspath[i+j])) {
+ eMatched = false
+ break
+ }
+ }
+ if eMatched {
+ return true
+ }
}
- case AS_ORIGIN:
- matched = aspath[len(aspath)-1] == member.asn
-
- case AS_ONLY:
- matched = len(aspath) == 1 && aspath[0] == member.asn
-
+ return false
}
+ return true
+ }
- if matched {
+ result := false
+ if checkAll {
+ result = true
+ }
+ for _, member := range c.AsPathList {
+ if checkElem(member.postiion, member.asRegExps) {
log.WithFields(log.Fields{
"Topic": "Policy",
"Condition": "aspath length",
- "ASN": member.asn,
+ "ASN": member.asStr,
"Position": member.postiion,
}).Debug("aspath condition matched")
@@ -520,7 +570,7 @@ func (c *AsPathCondition) evaluate(path *table.Path) bool {
aspath := path.GetAsSeqList()
- if len(aspath) == 0 {
+ if c == nil || len(aspath) == 0 {
return false
}
@@ -1635,7 +1685,7 @@ func PrefixSetToApiStruct(ps config.PrefixSet) *api.PrefixSet {
resPrefixList := make([]*api.Prefix, 0)
for _, p := range ps.PrefixList {
resPrefix := &api.Prefix{
- IpPrefix: p.IpPrefix,
+ IpPrefix: p.IpPrefix,
MaskLengthRange: p.MasklengthRange,
}
resPrefixList = append(resPrefixList, resPrefix)
diff --git a/policy/policy_test.go b/policy/policy_test.go
index a6d4a4e4..72bf5c6c 100644
--- a/policy/policy_test.go
+++ b/policy/policy_test.go
@@ -653,6 +653,7 @@ func TestAsPathConditionEvaluate(t *testing.T) {
},
}
+
asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3,
asPathSet4, asPathSet5, asPathSet6}
@@ -686,9 +687,127 @@ func TestAsPathConditionEvaluate(t *testing.T) {
assert.Equal(t, true, p7.evaluate(path1))
assert.Equal(t, true, p8.evaluate(path2))
+}
+
+func TestMultipleAsPathConditionEvaluate(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, 54000, 65004, 65005}),
+ bgp.NewAsPathParam(1, []uint16{65001, 65010, 54000, 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]
+
+
+ // create match condition
+ asPathSet1 := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "^65001_65000"},
+ },
+ }
+
+ asPathSet2 := config.AsPathSet{
+ AsPathSetName: "asset2",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65004_65005$"},
+ },
+ }
+
+ asPathSet3 := config.AsPathSet{
+ AsPathSetName: "asset3",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65001_65000_54000"},
+ },
+ }
+
+ asPathSet4 := config.AsPathSet{
+ AsPathSetName: "asset4",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "54000_65004_65005"},
+ },
+ }
+ asPathSet5 := config.AsPathSet{
+ AsPathSetName: "asset5",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "^65001_65000_54000_65004_65005$"},
+ },
+ }
+
+ asPathSet6 := config.AsPathSet{
+ AsPathSetName: "asset6",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: ".*_[0-9]+_65005"},
+ },
+ }
+
+ asPathSet7 := config.AsPathSet{
+ AsPathSetName: "asset7",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: ".*_5[0-9]+_[0-9]+"},
+ },
+ }
+
+ asPathSet8 := config.AsPathSet{
+ AsPathSetName: "asset8",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "6[0-9]+_6[0-9]+_6[0-9]+"},
+ },
+ }
+
+ asPathSet9 := config.AsPathSet{
+ AsPathSetName: "asset9",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "6[0-9]+__6[0-9]+"},
+ },
+ }
+
+ asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3,
+ asPathSet4, asPathSet5, asPathSet6, asPathSet7, asPathSet8, asPathSet9}
+
+ createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition {
+ matchSet := config.MatchAsPathSet{}
+ matchSet.AsPathSet = name
+ matchSet.MatchSetOptions = option
+ p := NewAsPathCondition(matchSet, asPathSetList)
+ return p
+ }
+
+ p1 := createAspathC("asset1", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p2 := createAspathC("asset2", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p3 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p4 := createAspathC("asset4", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p5 := createAspathC("asset5", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p6 := createAspathC("asset6", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p7 := createAspathC("asset7", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p8 := createAspathC("asset8", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p9 := createAspathC("asset9", config.MATCH_SET_OPTIONS_TYPE_ANY)
+
+ // 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, true, p4.evaluate(path1))
+ assert.Equal(t, true, p5.evaluate(path1))
+ assert.Equal(t, true, p6.evaluate(path1))
+ assert.Equal(t, true, p7.evaluate(path1))
+ assert.Equal(t, false, p8.evaluate(path1))
+ assert.Equal(t, false, p9.evaluate(path1))
}
+
func TestAsPathConditionWithOtherCondition(t *testing.T) {
// setup