diff options
-rw-r--r-- | docs/sources/filter-detail.md | 18 | ||||
-rw-r--r-- | policy/policy.go | 138 | ||||
-rw-r--r-- | policy/policy_test.go | 119 |
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 |