summaryrefslogtreecommitdiffhomepage
path: root/table
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2015-10-09 19:39:03 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-10-09 19:39:03 +0900
commitdd6140c6a28eb6e2dc41b47611240647e2b938fd (patch)
treeec40225abe267982913580c3c654f45422a32766 /table
parenteb67afbdad499466e9407b4b30e9854664dd0486 (diff)
table: merge policy package into table
Diffstat (limited to 'table')
-rw-r--r--table/policy.go2065
-rw-r--r--table/policy_test.go2139
2 files changed, 4204 insertions, 0 deletions
diff --git a/table/policy.go b/table/policy.go
new file mode 100644
index 00000000..bec56e07
--- /dev/null
+++ b/table/policy.go
@@ -0,0 +1,2065 @@
+// Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package table
+
+import (
+ "fmt"
+ "net"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+
+ log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/config"
+ "github.com/osrg/gobgp/packet"
+)
+
+type RouteType int
+
+const (
+ ROUTE_TYPE_NONE RouteType = iota
+ ROUTE_TYPE_ACCEPT
+ ROUTE_TYPE_REJECT
+)
+
+func (t RouteType) String() string {
+ switch t {
+ case ROUTE_TYPE_NONE:
+ return "NONE"
+ case ROUTE_TYPE_ACCEPT:
+ return "ACCEPT"
+ case ROUTE_TYPE_REJECT:
+ return "REJECT"
+ default:
+ return fmt.Sprintf("Unknown(%d)", t)
+ }
+}
+
+func (t RouteType) ToApiStruct() gobgpapi.RouteAction {
+ switch t {
+ case ROUTE_TYPE_ACCEPT:
+ return gobgpapi.RouteAction_ACCEPT
+ case ROUTE_TYPE_REJECT:
+ return gobgpapi.RouteAction_REJECT
+ default:
+ return gobgpapi.RouteAction_NONE
+ }
+}
+
+type PolicyDirection int
+
+const (
+ POLICY_DIRECTION_IN = iota
+ POLICY_DIRECTION_IMPORT = iota
+ POLICY_DIRECTION_EXPORT
+)
+
+type AttributeComparison int
+
+const (
+ // "== comparison"
+ ATTRIBUTE_EQ AttributeComparison = iota
+ // ">= comparison"
+ ATTRIBUTE_GE
+ // "<= comparison"
+ ATTRIBUTE_LE
+)
+
+type Policy struct {
+ Name string
+ Statements []*Statement
+}
+
+func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
+ stmtList := pd.Statements.StatementList
+ st := make([]*Statement, 0)
+ p := &Policy{
+ Name: pd.Name,
+ }
+
+ for _, statement := range stmtList {
+ conditions := make([]Condition, 0)
+
+ // prefix match
+ pc := NewPrefixCondition(statement.Conditions.MatchPrefixSet, ds.PrefixSets.PrefixSetList)
+ if pc != nil {
+ conditions = append(conditions, pc)
+ }
+
+ // neighbor match
+ nc := NewNeighborCondition(statement.Conditions.MatchNeighborSet, ds.NeighborSets.NeighborSetList)
+ if nc != nil {
+ conditions = append(conditions, nc)
+ }
+
+ // AsPathLengthCondition
+ c := statement.Conditions.BgpConditions.AsPathLength
+ ac := NewAsPathLengthCondition(c)
+ if ac != nil {
+ conditions = append(conditions, ac)
+ }
+
+ if statement.Conditions.BgpConditions.RpkiValidationResult != config.RPKI_VALIDATION_RESULT_TYPE_NONE {
+ conditions = append(conditions, NewRPKIValidationCondition(statement.Conditions.BgpConditions.RpkiValidationResult))
+ }
+
+ bgpDefset := &ds.BgpDefinedSets
+ bgpConditions := &statement.Conditions.BgpConditions
+ // AsPathCondition
+ asc := NewAsPathCondition(bgpConditions.MatchAsPathSet, bgpDefset.AsPathSets.AsPathSetList)
+ if asc != nil {
+ conditions = append(conditions, asc)
+ }
+
+ // CommunityCondition
+ cc := NewCommunityCondition(bgpConditions.MatchCommunitySet, bgpDefset.CommunitySets.CommunitySetList)
+ if cc != nil {
+ conditions = append(conditions, cc)
+ }
+
+ // ExtendedCommunityCondition
+ ecc := NewExtCommunityCondition(bgpConditions.MatchExtCommunitySet, bgpDefset.ExtCommunitySets.ExtCommunitySetList)
+ if ecc != nil {
+ conditions = append(conditions, ecc)
+ }
+
+ // routing action
+ ra := NewRoutingAction(statement.Actions)
+
+ // Community action
+ mda := make([]Action, 0)
+ com := NewCommunityAction(statement.Actions.BgpActions.SetCommunity)
+ if com != nil {
+ mda = append(mda, com)
+ }
+
+ ext := NewExtCommunityAction(statement.Actions.BgpActions.SetExtCommunity)
+ if ext != nil {
+ mda = append(mda, ext)
+ }
+
+ // Med Action
+ med := NewMedAction(statement.Actions.BgpActions.SetMed)
+ if med != nil {
+ mda = append(mda, med)
+ }
+
+ //AsPathPrependAction
+ ppa := NewAsPathPrependAction(statement.Actions.BgpActions.SetAsPathPrepend)
+ if ppa != nil {
+ mda = append(mda, ppa)
+ }
+
+ s := &Statement{
+ Name: statement.Name,
+ Conditions: conditions,
+ routingAction: ra,
+ modificationActions: mda,
+ }
+
+ st = append(st, s)
+ }
+ p.Statements = st
+ return p
+}
+
+type Statement struct {
+ Name string
+ Conditions []Condition
+ routingAction *RoutingAction
+ modificationActions []Action
+}
+
+// evaluate each condition in the statement according to MatchSetOptions
+func (s *Statement) evaluate(p *Path) bool {
+
+ for _, condition := range s.Conditions {
+ r := condition.evaluate(p)
+ if !r {
+ return false
+ }
+ }
+ return true
+}
+
+type Condition interface {
+ evaluate(*Path) bool
+}
+
+type DefaultCondition struct {
+ CallPolicy string
+}
+
+func (c *DefaultCondition) evaluate(path *Path) bool {
+ return false
+}
+
+type PrefixCondition struct {
+ DefaultCondition
+ PrefixConditionName string
+ PrefixList []Prefix
+ MatchOption config.MatchSetOptionsRestrictedType
+}
+
+func NewPrefixCondition(matchPref config.MatchPrefixSet, defPrefixList []config.PrefixSet) *PrefixCondition {
+
+ prefixSetName := matchPref.PrefixSet
+ options := matchPref.MatchSetOptions
+
+ prefixList := make([]Prefix, 0)
+ for _, ps := range defPrefixList {
+ if ps.PrefixSetName == prefixSetName {
+ for _, prefix := range ps.PrefixList {
+ prefix, e := NewPrefix(prefix.IpPrefix, prefix.MasklengthRange)
+ if e != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "prefix": prefix,
+ "msg": e,
+ }).Error("failed to generate a NewPrefix from configration.")
+ } else {
+ prefixList = append(prefixList, prefix)
+ }
+ }
+ }
+ }
+
+ if len(prefixList) == 0 {
+ return nil
+ }
+
+ pc := &PrefixCondition{
+ PrefixConditionName: prefixSetName,
+ PrefixList: prefixList,
+ MatchOption: options,
+ }
+
+ return pc
+}
+
+// compare prefixes in this condition and nlri of path and
+// subsequent comparison is skipped if that matches the conditions.
+// If PrefixList's length is zero, return true.
+func (c *PrefixCondition) evaluate(path *Path) bool {
+
+ if len(c.PrefixList) == 0 {
+ log.Debug("PrefixList doesn't have elements")
+ return true
+ }
+
+ result := false
+ for _, cp := range c.PrefixList {
+ if ipPrefixCalculate(path, cp) {
+ result = true
+ break
+ }
+ }
+ if c.MatchOption == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT {
+ result = !result
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "prefix",
+ "Path": path,
+ "Matched": result,
+ }).Debug("evaluate prefix")
+
+ return result
+}
+
+type NeighborCondition struct {
+ DefaultCondition
+ NeighborConditionName string
+ NeighborList []net.IP
+ MatchOption config.MatchSetOptionsRestrictedType
+}
+
+func NewNeighborCondition(matchNeighborSet config.MatchNeighborSet, defNeighborSetList []config.NeighborSet) *NeighborCondition {
+
+ neighborSetName := matchNeighborSet.NeighborSet
+ options := matchNeighborSet.MatchSetOptions
+
+ neighborList := make([]net.IP, 0)
+ for _, neighborSet := range defNeighborSetList {
+ if neighborSet.NeighborSetName == neighborSetName {
+ for _, nl := range neighborSet.NeighborInfoList {
+ neighborList = append(neighborList, nl.Address)
+ }
+ }
+ }
+
+ if len(neighborList) == 0 {
+ return nil
+ }
+
+ nc := &NeighborCondition{
+ NeighborConditionName: neighborSetName,
+ NeighborList: neighborList,
+ MatchOption: options,
+ }
+
+ return nc
+}
+
+// compare neighbor ipaddress of this condition and source address of path
+// and, subsequent comparisons are skipped if that matches the conditions.
+// If NeighborList's length is zero, return true.
+func (c *NeighborCondition) evaluate(path *Path) bool {
+
+ if len(c.NeighborList) == 0 {
+ log.Debug("NeighborList doesn't have elements")
+ return true
+ }
+
+ if path.Owner == nil {
+ return false
+ }
+ result := false
+ for _, neighbor := range c.NeighborList {
+ if path.Owner.Equal(neighbor) {
+ result = true
+ break
+ }
+ }
+
+ if c.MatchOption == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT {
+ result = !result
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "neighbor",
+ "NeighborAddress": path.Owner,
+ "Matched": result,
+ }).Debug("evaluate neighbor")
+
+ return result
+}
+
+type AsPathLengthCondition struct {
+ DefaultCondition
+ Value uint32
+ Operator AttributeComparison
+}
+
+// create AsPathLengthCondition object
+func NewAsPathLengthCondition(defAsPathLength config.AsPathLength) *AsPathLengthCondition {
+
+ value := defAsPathLength.Value
+ var op AttributeComparison
+
+ switch defAsPathLength.Operator {
+ case "eq":
+ op = ATTRIBUTE_EQ
+
+ case "ge":
+ op = ATTRIBUTE_GE
+
+ case "le":
+ op = ATTRIBUTE_LE
+ default:
+ return nil
+ }
+
+ ac := &AsPathLengthCondition{
+ Value: value,
+ Operator: op,
+ }
+
+ return ac
+}
+
+// compare AS_PATH length in the message's AS_PATH attribute with
+// the one in condition.
+func (c *AsPathLengthCondition) evaluate(path *Path) bool {
+
+ length := uint32(path.GetAsPathLen())
+ result := false
+
+ switch c.Operator {
+ case ATTRIBUTE_EQ:
+ result = c.Value == length
+
+ case ATTRIBUTE_GE:
+ result = c.Value <= length
+
+ case ATTRIBUTE_LE:
+ result = c.Value >= length
+ default:
+ result = false
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "aspath length",
+ "Reason": c.Operator,
+ "Matched": result,
+ }).Debug("evaluate aspath length")
+
+ return result
+}
+
+type AsPathCondition struct {
+ DefaultCondition
+ AsRegExpList []*regexp.Regexp
+ MatchOption config.MatchSetOptionsType
+}
+
+const (
+ ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)"
+)
+
+func NewAsPathCondition(matchSet config.MatchAsPathSet, defAsPathSetList []config.AsPathSet) *AsPathCondition {
+ asPathSetName := matchSet.AsPathSet
+ options := matchSet.MatchSetOptions
+
+ asRegExpList := make([]*regexp.Regexp, 0)
+ for _, asPathSet := range defAsPathSetList {
+ if asPathSet.AsPathSetName == asPathSetName {
+ for _, aspath := range asPathSet.AsPathList {
+ a := aspath.AsPath
+ if len(a) != 0 {
+ r, err := regexp.Compile(strings.Replace(a, "_", ASPATH_REGEXP_MAGIC, -1))
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ "Value": aspath.AsPath,
+ "Error": err,
+ }).Error("can not comple AS_PATH values to Regular expressions.")
+ return nil
+ }
+
+ asRegExpList = append(asRegExpList, r)
+ } else {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPath Condition",
+ }).Error("does not parse AS_PATH condition value.")
+ return nil
+ }
+ }
+ c := &AsPathCondition{
+ AsRegExpList: asRegExpList,
+ MatchOption: options,
+ }
+ return c
+ }
+ }
+ return nil
+}
+
+func (c *AsPathCondition) checkMembers(aspathStr string, checkAll bool) bool {
+ for _, r := range c.AsRegExpList {
+ if r.MatchString(aspathStr) {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "aspath length",
+ "AS": aspathStr,
+ "ASN": r,
+ }).Debug("aspath condition matched")
+
+ if !checkAll {
+ return true
+ }
+ } else {
+ if checkAll {
+ return false
+ }
+ }
+ }
+ return checkAll
+}
+
+// compare AS_PATH in the message's AS_PATH attribute with
+// the one in condition.
+func (c *AsPathCondition) evaluate(path *Path) bool {
+
+ aspathStr := path.GetAsString()
+
+ result := false
+ if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL {
+ result = c.checkMembers(aspathStr, true)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY {
+ result = c.checkMembers(aspathStr, false)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT {
+ result = !c.checkMembers(aspathStr, false)
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "aspath",
+ "MatchOption": c.MatchOption,
+ "Matched": result,
+ }).Debug("evaluate aspath")
+
+ return result
+}
+
+type CommunityCondition struct {
+ DefaultCondition
+ CommunityList []*CommunityElement
+ MatchOption config.MatchSetOptionsType
+}
+
+const (
+ COMMUNITY_INTERNET string = "INTERNET"
+ COMMUNITY_NO_EXPORT string = "NO_EXPORT"
+ COMMUNITY_NO_ADVERTISE string = "NO_ADVERTISE"
+ COMMUNITY_NO_EXPORT_SUBCONFED string = "NO_EXPORT_SUBCONFED"
+)
+
+const (
+ COMMUNITY_INTERNET_VAL uint32 = 0x00000000
+ COMMUNITY_NO_EXPORT_VAL = 0xFFFFFF01
+ COMMUNITY_NO_ADVERTISE_VAL = 0xFFFFFF02
+ COMMUNITY_NO_EXPORT_SUBCONFED_VAL = 0xFFFFFF03
+)
+
+type CommunityElement struct {
+ community uint32
+ communityStr string
+ isRegExp bool
+ communityRegExp *regexp.Regexp
+}
+
+// create CommunityCondition object
+// 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(matchSet config.MatchCommunitySet, defCommunitySetList []config.CommunitySet) *CommunityCondition {
+
+ communitySetName := matchSet.CommunitySet
+ options := matchSet.MatchSetOptions
+
+ communityList := make([]*CommunityElement, 0)
+ for _, communitySet := range defCommunitySetList {
+ if communitySet.CommunitySetName == communitySetName {
+ for _, community := range communitySet.CommunityList {
+ c := community.Community
+ e := &CommunityElement{
+ isRegExp: false,
+ communityStr: c,
+ }
+
+ if matched, v := getCommunityValue(c); matched {
+ e.community = v
+ } else {
+ // specified by regular expression
+ e.isRegExp = true
+ reg, err := regexp.Compile(c)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Community Condition",
+ }).Error("Regular expression can't be compiled.")
+ return nil
+ }
+ e.communityRegExp = reg
+ }
+ communityList = append(communityList, e)
+ }
+
+ c := &CommunityCondition{
+ CommunityList: communityList,
+ MatchOption: options,
+ }
+ return c
+ }
+ }
+ 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
+}
+
+func (c *CommunityCondition) checkMembers(communities []uint32, checkAll bool) bool {
+
+ result := false
+ if checkAll {
+ result = true
+ }
+
+ makeStr := func(c uint32) string {
+ upper := strconv.FormatUint(uint64(c&0xFFFF0000>>16), 10)
+ lower := strconv.FormatUint(uint64(c&0x0000FFFF), 10)
+ return upper + ":" + lower
+ }
+
+ var strCommunities []string = nil
+ matched := false
+ idx := -1
+ for _, member := range c.CommunityList {
+ if member.isRegExp {
+
+ if strCommunities == nil {
+ // create community string.
+ strCommunities = make([]string, len(communities))
+ for i, c := range communities {
+ strCommunities[i] = makeStr(c)
+ }
+ }
+
+ for i, c := range strCommunities {
+ if member.communityRegExp.MatchString(c) {
+ matched = true
+ idx = i
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "RegExp": member.communityRegExp.String(),
+ }).Debug("community regexp used")
+ break
+ }
+ }
+
+ } else {
+ for i, c := range communities {
+ if c == member.community {
+ matched = true
+ idx = i
+ break
+ }
+ }
+ }
+
+ if matched {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "Community",
+ "Community": makeStr(communities[idx]),
+ }).Debug("condition matched")
+
+ if !checkAll {
+ result = true
+ break
+ }
+
+ } else {
+ if checkAll {
+ result = false
+ break
+ }
+ }
+ }
+
+ return result
+
+}
+
+// compare community in the message's attribute with
+// the one in the condition.
+func (c *CommunityCondition) evaluate(path *Path) bool {
+
+ communities := path.GetCommunities()
+
+ if len(communities) == 0 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "community",
+ "MatchOption": c.MatchOption,
+ "Matched": false,
+ }).Debug("community length is zero")
+ return false
+ }
+
+ result := false
+ if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL {
+ result = c.checkMembers(communities, true)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY {
+ result = c.checkMembers(communities, false)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT {
+ result = !c.checkMembers(communities, false)
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "community",
+ "MatchOption": c.MatchOption,
+ "Matched": result,
+ }).Debug("evaluate community")
+
+ return result
+}
+
+type ExtCommunityCondition struct {
+ DefaultCondition
+ ExtCommunityList []*ExtCommunityElement
+ MatchOption config.MatchSetOptionsType
+}
+
+type ExtCommunityElement struct {
+ ecType bgp.ExtendedCommunityAttrType
+ ecSubType bgp.ExtendedCommunityAttrSubType
+ globalAdmin interface{}
+ localAdmin uint32
+ comStr string
+ isRegExp bool
+ regExp *regexp.Regexp
+}
+
+func NewExtCommunityCondition(matchSet config.MatchExtCommunitySet, defExtComSetList []config.ExtCommunitySet) *ExtCommunityCondition {
+
+ extComSetName := matchSet.ExtCommunitySet
+ option := matchSet.MatchSetOptions
+
+ extCommunityElemList := make([]*ExtCommunityElement, 0)
+ for _, extComSet := range defExtComSetList {
+ if extComSet.ExtCommunitySetName == extComSetName {
+ for _, ecommunity := range extComSet.ExtCommunityList {
+ matchAll := false
+ ec := ecommunity.ExtCommunity
+ e := &ExtCommunityElement{
+ isRegExp: false,
+ comStr: ec,
+ }
+ matchType, val := getECommunitySubType(ec)
+ if !matchType {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Extended Community Condition",
+ }).Error("failed to parse the sub type %s.", ec)
+ return nil
+ }
+ switch val[1] {
+ case "RT":
+ e.ecSubType = bgp.EC_SUBTYPE_ROUTE_TARGET
+ case "SoO":
+ e.ecSubType = bgp.EC_SUBTYPE_ROUTE_ORIGIN
+ default:
+ e.ecSubType = bgp.ExtendedCommunityAttrSubType(0xFF)
+ }
+
+ if matchVal, elem := getECommunityValue(val[2]); matchVal {
+ if matchElem, ecType, gAdmin := getECommunityElem(elem[1]); matchElem {
+ e.ecType = ecType
+ e.globalAdmin = gAdmin
+ lAdmin, err := strconv.ParseUint(elem[2], 10, 32)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Extended Community Condition",
+ }).Errorf("failed to parse the local administrator %d.", elem[2])
+ return nil
+ }
+ e.localAdmin = uint32(lAdmin)
+ matchAll = true
+ }
+ }
+ if !matchAll {
+ e.isRegExp = true
+ reg, err := regexp.Compile(ec)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Extended Community Condition",
+ }).Errorf("Regular expression can't be compiled %s.", val[2])
+ return nil
+ }
+ e.regExp = reg
+ }
+ extCommunityElemList = append(extCommunityElemList, e)
+ }
+ ce := &ExtCommunityCondition{
+ ExtCommunityList: extCommunityElemList,
+ MatchOption: option,
+ }
+ return ce
+ }
+ }
+ return nil
+}
+
+func getECommunitySubType(eComStr string) (bool, []string) {
+ regSubType, _ := regexp.Compile("^(RT|SoO):(.*)$")
+ if regSubType.MatchString(eComStr) {
+ eComVal := regSubType.FindStringSubmatch(eComStr)
+ return true, eComVal
+ }
+ return false, nil
+}
+
+func getECommunityValue(eComVal string) (bool, []string) {
+ regVal, _ := regexp.Compile("^([0-9\\.]+):([0-9]+)$")
+ if regVal.MatchString(eComVal) {
+ eComElem := regVal.FindStringSubmatch(eComVal)
+ return true, eComElem
+ }
+ return false, nil
+}
+
+func getECommunityElem(gAdmin string) (bool, bgp.ExtendedCommunityAttrType, interface{}) {
+ addr := net.ParseIP(gAdmin)
+ if addr.To4() != nil {
+ return true, bgp.EC_TYPE_TRANSITIVE_IP4_SPECIFIC, addr
+ }
+ regAs, _ := regexp.Compile("^([0-9]+)$")
+ if regAs.MatchString(gAdmin) {
+ as, err := strconv.ParseUint(gAdmin, 10, 16)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Extended Community Condition",
+ }).Errorf("failed to parse the global administrator %d.", gAdmin)
+ }
+ return true, bgp.EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC, uint16(as)
+ }
+ regAs4, _ := regexp.Compile("^([0-9]+).([0-9]+)$")
+ if regAs4.MatchString(gAdmin) {
+ as4Elem := regAs4.FindStringSubmatch(gAdmin)
+ highAs, errHigh := strconv.ParseUint(as4Elem[1], 10, 16)
+ lowAs, errLow := strconv.ParseUint(as4Elem[2], 10, 16)
+ if errHigh != nil || errLow != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Extended Community Condition",
+ }).Errorf("failed to parse the global administrator %d.", gAdmin)
+ }
+ return true, bgp.EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC, uint32(highAs<<16 | lowAs)
+ }
+ return false, bgp.ExtendedCommunityAttrType(0xFF), nil
+}
+
+func (c *ExtCommunityCondition) checkMembers(eCommunities []bgp.ExtendedCommunityInterface, checkAll bool) bool {
+
+ result := false
+ if checkAll {
+ result = true
+ }
+
+ makeAs4Str := func(ec *ExtCommunityElement) string {
+ t := ec.ecType
+ str := fmt.Sprintf("%d", ec.localAdmin)
+ switch t {
+ case bgp.EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC:
+ str = fmt.Sprintf("%d:%s", ec.globalAdmin.(uint16), str)
+ case bgp.EC_TYPE_TRANSITIVE_IP4_SPECIFIC:
+ str = fmt.Sprintf("%s:%s", ec.globalAdmin.(net.IP).String(), str)
+ case bgp.EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC:
+ ga := ec.globalAdmin.(uint32)
+ upper := strconv.FormatUint(uint64(ga&0xFFFF0000>>16), 10)
+ lower := strconv.FormatUint(uint64(ga&0x0000FFFF), 10)
+ str = fmt.Sprintf("%s.%s:%s", upper, lower, str)
+ }
+ return str
+ }
+
+ makeTypeSubStr := func(st bgp.ExtendedCommunityAttrSubType) string {
+ subStr := ""
+ switch st {
+ case bgp.EC_SUBTYPE_ROUTE_TARGET:
+ subStr = "RT"
+ case bgp.EC_SUBTYPE_ROUTE_ORIGIN:
+ subStr = "SoO"
+ }
+ return subStr
+ }
+
+ matched := false
+ matchStr := ""
+ for _, member := range c.ExtCommunityList {
+ for _, ec := range eCommunities {
+ t, st := ec.GetTypes()
+ if member.isRegExp {
+ ecString := fmt.Sprintf("%s:%s", makeTypeSubStr(st), ec.String())
+ if member.regExp.MatchString(ecString) {
+ matched = true
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "RegExp": member.regExp.String(),
+ }).Debug("extended community regexp used")
+ matchStr = ec.String()
+ break
+ }
+ } else if member.ecType == t && member.ecSubType == st {
+ if makeAs4Str(member) == ec.String() {
+ matched = true
+ matchStr = ec.String()
+ break
+ }
+
+ }
+ }
+ if matched {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "Extended Community",
+ "Extended Community": matchStr,
+ }).Debug("condition matched")
+
+ if !checkAll {
+ result = true
+ break
+ }
+
+ } else {
+ if checkAll {
+ result = false
+ break
+ }
+ }
+ }
+ return result
+}
+
+// compare extended community in the message's attribute with
+// the one in the condition.
+func (c *ExtCommunityCondition) evaluate(path *Path) bool {
+
+ eCommunities := path.GetExtCommunities()
+ if len(eCommunities) == 0 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "extended community",
+ "Matched": false,
+ "Path": path,
+ }).Debug("extended community length is zero")
+ return false
+ }
+
+ result := false
+ if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL {
+ result = c.checkMembers(eCommunities, true)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY {
+ result = c.checkMembers(eCommunities, false)
+ } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT {
+ result = !c.checkMembers(eCommunities, false)
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Condition": "extended community",
+ "MatchOption": c.MatchOption,
+ "Matched": result,
+ "Path": path,
+ }).Debug("evaluate extended community")
+
+ return result
+}
+
+type RPKIValidationCondition struct {
+ result config.RpkiValidationResultType
+}
+
+func NewRPKIValidationCondition(result config.RpkiValidationResultType) *RPKIValidationCondition {
+ return &RPKIValidationCondition{
+ result: result,
+ }
+}
+
+func (c *RPKIValidationCondition) evaluate(path *Path) bool {
+ return c.result == path.Validation
+}
+
+type Action interface {
+ apply(*Path) *Path
+}
+
+type RoutingAction struct {
+ AcceptRoute bool
+}
+
+func NewRoutingAction(action config.Actions) *RoutingAction {
+ return &RoutingAction{
+ AcceptRoute: action.RouteDisposition.AcceptRoute,
+ }
+}
+
+func (r *RoutingAction) apply(path *Path) *Path {
+ if r.AcceptRoute {
+ return path
+ }
+ return nil
+}
+
+type CommunityAction struct {
+ Values []uint32
+ ext []byte
+ action config.BgpSetCommunityOptionType
+ RegexpValues []*regexp.Regexp
+}
+
+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{}
+ communities := action.SetCommunityMethod.Communities
+ if len(communities) == 0 && action.Options != COMMUNITY_ACTION_REPLACE {
+ return nil
+ }
+
+ values := make([]uint32, 0, len(communities))
+ regexpValues := make([]*regexp.Regexp, 0, len(communities))
+
+ for _, com := range communities {
+ matched, value := getCommunityValue(com)
+ if matched {
+ values = append(values, value)
+ continue
+ }
+
+ exp, err := regexp.Compile(com)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Community Action",
+ }).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
+ }
+
+ 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
+ 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 RegexpRemoveCommunities(path *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)
+ match := false
+ for _, exp := range exps {
+ if exp.MatchString(c) {
+ match = true
+ break
+ }
+ }
+ if match == false {
+ newComms = append(newComms, comm)
+ }
+ }
+ path.SetCommunities(newComms, true)
+}
+
+func (a *CommunityAction) apply(path *Path) *Path {
+ if len(a.ext) > 0 {
+ return a.extApply(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)
+ if len(a.RegexpValues) > 0 {
+ RegexpRemoveCommunities(path, a.RegexpValues)
+ }
+ case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE:
+ path.SetCommunities(list, true)
+ }
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Action": "community",
+ "Values": list,
+ "Method": a.action,
+ }).Debug("community action applied")
+
+ return path
+}
+
+func (a *CommunityAction) extApply(path *Path) *Path {
+ path.SetExtCommunities(a.ext, false)
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Action": "extended community",
+ "Values": a.ext,
+ "Method": a.action,
+ }).Debug("extended community action applied")
+
+ return path
+}
+
+func NewExtCommunityAction(action config.SetExtCommunity) *CommunityAction {
+ communities := action.SetExtCommunityMethod.Communities
+ if len(communities) == 0 {
+ return nil
+ }
+
+ b := make([]byte, len(communities)*8)
+ for i, c := range communities {
+ l := strings.Split(c, ":")
+ if len(l) != 8 {
+ goto E
+ }
+ for j, v := range l {
+ v, err := strconv.ParseInt(v, 0, 32)
+ if err != nil {
+ goto E
+ }
+ b[j+i*8] = uint8(v)
+ }
+ }
+ return &CommunityAction{
+ ext: b,
+ }
+E:
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Action": "ExtCommunity",
+ "Values": communities,
+ }).Error("invalid extended community action")
+ return nil
+}
+
+type ActionType int
+
+type MedAction struct {
+ Value int64
+ action ActionType
+}
+
+const (
+ MED_ACTION_NONE ActionType = iota
+ MED_ACTION_REPLACE
+ MED_ACTION_ADD
+ MED_ACTION_SUB
+)
+
+// NewMedAction creates MedAction object.
+// If it cannot parse med string, then return nil.
+func NewMedAction(med config.BgpSetMedType) *MedAction {
+
+ if med == "" {
+ return nil
+ }
+
+ m := &MedAction{}
+
+ matched, value, action := getMedValue(fmt.Sprintf("%s", med))
+ if !matched {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Error("med string invalid.")
+ return nil
+ }
+ m.Value = value
+ m.action = action
+ return m
+}
+
+// getMedValue returns uint32 med value and action type (+ or -).
+// if the string doesn't match a number or operator,
+// it returns false and 0.
+func getMedValue(medStr string) (bool, int64, ActionType) {
+ regMed, _ := regexp.Compile("^(\\+|\\-)?([0-9]+)$")
+ if regMed.MatchString(medStr) {
+ group := regMed.FindStringSubmatch(medStr)
+ action := MED_ACTION_REPLACE
+ if group[1] == "+" {
+ action = MED_ACTION_ADD
+ } else if group[1] == "-" {
+ action = MED_ACTION_SUB
+ }
+ val, err := strconv.ParseInt(medStr, 10, 64)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Error("failed to parser as number or med value.")
+ }
+ return true, int64(val), action
+ }
+ return false, int64(0), MED_ACTION_NONE
+}
+func (a *MedAction) apply(path *Path) *Path {
+
+ var err error
+ switch a.action {
+ case MED_ACTION_REPLACE:
+ err = path.SetMed(a.Value, true)
+ case MED_ACTION_ADD:
+ err = path.SetMed(a.Value, false)
+ case MED_ACTION_SUB:
+ err = path.SetMed(a.Value, false)
+ }
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Warn(err)
+ } else {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Action": "med",
+ "Value": a.Value,
+ "ActionType": a.action,
+ }).Debug("med action applied")
+ }
+
+ return path
+}
+
+type AsPathPrependAction struct {
+ asn uint32
+ useLeftMost bool
+ repeat uint8
+}
+
+// NewAsPathPrependAction creates AsPathPrependAction object.
+// If ASN cannot be parsed, nil will be returned.
+func NewAsPathPrependAction(action config.SetAsPathPrepend) *AsPathPrependAction {
+
+ a := &AsPathPrependAction{}
+
+ if action.As == "" {
+ return nil
+ }
+
+ if action.As == "last-as" {
+ a.useLeftMost = true
+ } else {
+ asn, err := strconv.ParseUint(action.As, 10, 32)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPathPrepend Action",
+ "Value": action.As,
+ }).Error("As number string invalid.")
+ return nil
+ }
+ a.asn = uint32(asn)
+ }
+ a.repeat = action.RepeatN
+
+ return a
+}
+
+func (a *AsPathPrependAction) apply(path *Path) *Path {
+
+ var asn uint32
+ if a.useLeftMost {
+ asns := path.GetAsSeqList()
+ if len(asns) == 0 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPathPrepend Action",
+ }).Error("aspath length is zero.")
+ return path
+ }
+ asn = asns[0]
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "AsPathPrepend Action",
+ "LastAs": asn,
+ "Repeat": a.repeat,
+ }).Debug("use last AS.")
+ } else {
+ asn = a.asn
+ }
+
+ path.PrependAsn(asn, a.repeat)
+
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Action": "aspath prepend",
+ "ASN": asn,
+ "Repeat": a.repeat,
+ }).Debug("aspath prepend action applied")
+
+ return path
+}
+
+type Prefix struct {
+ Prefix *net.IPNet
+ AddressFamily bgp.RouteFamily
+ MasklengthRangeMax uint8
+ MasklengthRangeMin uint8
+}
+
+func NewPrefix(prefixStr string, maskRange string) (Prefix, error) {
+ p := Prefix{}
+ addr, ipPref, e := net.ParseCIDR(prefixStr)
+ if e != nil {
+ return p, e
+ }
+
+ if ipv4Family := addr.To4(); ipv4Family != nil {
+ p.AddressFamily, _ = bgp.GetRouteFamily("ipv4-unicast")
+ } else if ipv6Family := addr.To16(); ipv6Family != nil {
+ p.AddressFamily, _ = bgp.GetRouteFamily("ipv6-unicast")
+ } else {
+ return p, fmt.Errorf("can not determine the address family.")
+ }
+
+ p.Prefix = ipPref
+
+ if maskRange == "" {
+ l, _ := ipPref.Mask.Size()
+ maskLength := uint8(l)
+ p.MasklengthRangeMax = maskLength
+ p.MasklengthRangeMin = maskLength
+ } else {
+ exp := regexp.MustCompile("(\\d+)\\.\\.(\\d+)")
+ elems := exp.FindStringSubmatch(maskRange)
+ if len(elems) != 3 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Prefix",
+ "MaskRangeFormat": maskRange,
+ }).Warn("mask length range format is invalid.")
+ return p, fmt.Errorf("mask length range format is invalid")
+ }
+ // we've already checked the range is sane by regexp
+ min, _ := strconv.Atoi(elems[1])
+ max, _ := strconv.Atoi(elems[2])
+ p.MasklengthRangeMin = uint8(min)
+ p.MasklengthRangeMax = uint8(max)
+ }
+ return p, nil
+}
+
+// Compare path with a policy's condition in stored order in the policy.
+// If a condition match, then this function stops evaluation and
+// subsequent conditions are skipped.
+func (p *Policy) Apply(path *Path) (RouteType, *Path) {
+ for _, statement := range p.Statements {
+
+ result := statement.evaluate(path)
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Path": path,
+ "PolicyName": p.Name,
+ }).Debug("statement evaluate : ", result)
+
+ if result {
+ //Routing action
+ p := statement.routingAction.apply(path)
+ if p == nil {
+ return ROUTE_TYPE_REJECT, path
+ }
+ if len(statement.modificationActions) == 0 {
+ return ROUTE_TYPE_ACCEPT, path
+ }
+ // apply all modification actions
+ cloned := path.Clone(p.Owner, p.IsWithdraw)
+ for _, action := range statement.modificationActions {
+ cloned = action.apply(cloned)
+ }
+ return ROUTE_TYPE_ACCEPT, cloned
+ }
+ }
+ return ROUTE_TYPE_NONE, path
+}
+
+func ipPrefixCalculate(path *Path, cPrefix Prefix) bool {
+ rf := path.GetRouteFamily()
+ log.Debug("path routefamily : ", rf.String())
+ var pAddr net.IP
+ var pMasklen uint8
+
+ if rf != cPrefix.AddressFamily {
+ return false
+ }
+
+ switch rf {
+ case bgp.RF_IPv4_UC:
+ pAddr = path.GetNlri().(*bgp.IPAddrPrefix).Prefix
+ pMasklen = path.GetNlri().(*bgp.IPAddrPrefix).Length
+ case bgp.RF_IPv6_UC:
+ pAddr = path.GetNlri().(*bgp.IPv6AddrPrefix).Prefix
+ pMasklen = path.GetNlri().(*bgp.IPv6AddrPrefix).Length
+ default:
+ return false
+ }
+
+ return (cPrefix.MasklengthRangeMin <= pMasklen && pMasklen <= cPrefix.MasklengthRangeMax) && cPrefix.Prefix.Contains(pAddr)
+}
+
+const (
+ OPTIONS_ANY string = "ANY"
+ OPTIONS_ALL = "ALL"
+ OPTIONS_INVERT = "INVERT"
+)
+
+func MatchSetOptionToString(option config.MatchSetOptionsType) string {
+ op := OPTIONS_ANY
+ switch option {
+ case config.MATCH_SET_OPTIONS_TYPE_ALL:
+ op = OPTIONS_ALL
+ case config.MATCH_SET_OPTIONS_TYPE_INVERT:
+ op = OPTIONS_INVERT
+ }
+ return op
+}
+
+func MatchSetOptionsRestrictedToString(option config.MatchSetOptionsRestrictedType) string {
+ op := OPTIONS_ANY
+ if option == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT {
+ op = OPTIONS_INVERT
+ }
+ return op
+}
+
+func MatchSetOptionsToType(option string) config.MatchSetOptionsType {
+ op := config.MATCH_SET_OPTIONS_TYPE_ANY
+ switch option {
+ case OPTIONS_ALL:
+ op = config.MATCH_SET_OPTIONS_TYPE_ALL
+ case OPTIONS_INVERT:
+ op = config.MATCH_SET_OPTIONS_TYPE_INVERT
+ }
+ return op
+}
+
+func MatchSetOptionsRestrictedToType(option string) config.MatchSetOptionsRestrictedType {
+ op := config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY
+ if option == OPTIONS_INVERT {
+ op = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT
+ }
+ return op
+}
+
+// find index PrefixSet of request from PrefixSet of configuration file.
+// Return the idxPrefixSet of the location where the name of PrefixSet matches,
+// and idxPrefix of the location where element of PrefixSet matches
+func IndexOfPrefixSet(conPrefixSetList []config.PrefixSet, reqPrefixSet config.PrefixSet) (int, int) {
+ idxPrefixSet := -1
+ idxPrefix := -1
+ for i, conPrefixSet := range conPrefixSetList {
+ if conPrefixSet.PrefixSetName == reqPrefixSet.PrefixSetName {
+ idxPrefixSet = i
+ if reqPrefixSet.PrefixList == nil {
+ return idxPrefixSet, idxPrefix
+ }
+ for j, conPrefix := range conPrefixSet.PrefixList {
+ if reflect.DeepEqual(conPrefix.IpPrefix, reqPrefixSet.PrefixList[0].IpPrefix) &&
+ conPrefix.MasklengthRange == reqPrefixSet.PrefixList[0].MasklengthRange {
+ idxPrefix = j
+ return idxPrefixSet, idxPrefix
+ }
+ }
+ }
+ }
+ return idxPrefixSet, idxPrefix
+}
+
+// find index NeighborSet of request from NeighborSet of configuration file.
+// Return the idxNeighborSet of the location where the name of NeighborSet matches,
+// and idxNeighbor of the location where element of NeighborSet matches
+func IndexOfNeighborSet(conNeighborSetList []config.NeighborSet, reqNeighborSet config.NeighborSet) (int, int) {
+ idxNeighborSet := -1
+ idxNeighbor := -1
+ for i, conNeighborSet := range conNeighborSetList {
+ if conNeighborSet.NeighborSetName == reqNeighborSet.NeighborSetName {
+ idxNeighborSet = i
+ if reqNeighborSet.NeighborInfoList == nil {
+ return idxNeighborSet, idxNeighbor
+ }
+ for j, conNeighbor := range conNeighborSet.NeighborInfoList {
+ if reflect.DeepEqual(conNeighbor.Address, reqNeighborSet.NeighborInfoList[0].Address) {
+ idxNeighbor = j
+ return idxNeighborSet, idxNeighbor
+ }
+ }
+ }
+ }
+ return idxNeighborSet, idxNeighbor
+}
+
+// find index AsPathSet of request from AsPathSet of configuration file.
+// Return the idxAsPathSet of the location where the name of AsPathSet matches,
+// and idxAsPath of the location where element of AsPathSet matches
+func IndexOfAsPathSet(conAsPathSetList []config.AsPathSet, reqAsPathSet config.AsPathSet) (int, int) {
+ idxAsPathSet := -1
+ idxAsPath := -1
+ for i, conAsPathSet := range conAsPathSetList {
+ if conAsPathSet.AsPathSetName == reqAsPathSet.AsPathSetName {
+ idxAsPathSet = i
+ if len(reqAsPathSet.AsPathList) == 0 {
+ return idxAsPathSet, idxAsPath
+ }
+ for j, conAsPath := range conAsPathSet.AsPathList {
+ if conAsPath == reqAsPathSet.AsPathList[0] {
+ idxAsPath = j
+ return idxAsPathSet, idxAsPath
+ }
+ }
+ }
+ }
+ return idxAsPathSet, idxAsPath
+}
+
+// find index CommunitySet of request from CommunitySet of configuration file.
+// Return the idxCommunitySet of the location where the name of CommunitySet matches,
+// and idxCommunity of the location where element of CommunitySet matches
+func IndexOfCommunitySet(conCommunitySetList []config.CommunitySet, reqCommunitySet config.CommunitySet) (int, int) {
+ idxCommunitySet := -1
+ idxCommunity := -1
+ for i, conCommunitySet := range conCommunitySetList {
+ if conCommunitySet.CommunitySetName == reqCommunitySet.CommunitySetName {
+ idxCommunitySet = i
+ if len(reqCommunitySet.CommunityList) == 0 {
+ return idxCommunitySet, idxCommunity
+ }
+ for j, conCommunity := range conCommunitySet.CommunityList {
+ if conCommunity == reqCommunitySet.CommunityList[0] {
+ idxCommunity = j
+ return idxCommunitySet, idxCommunity
+ }
+ }
+ }
+ }
+ return idxCommunitySet, idxCommunity
+}
+
+// find index ExtCommunitySet of request from ExtCommunitySet of configuration file.
+// Return the idxExtCommunitySet of the location where the name of ExtCommunitySet matches,
+// and idxExtCommunity of the location where element of ExtCommunitySet matches
+func IndexOfExtCommunitySet(conExtCommunitySetList []config.ExtCommunitySet, reqExtCommunitySet config.ExtCommunitySet) (int, int) {
+ idxExtCommunitySet := -1
+ idxExtCommunity := -1
+ for i, conExtCommunitySet := range conExtCommunitySetList {
+ if conExtCommunitySet.ExtCommunitySetName == reqExtCommunitySet.ExtCommunitySetName {
+ idxExtCommunitySet = i
+ if len(reqExtCommunitySet.ExtCommunityList) == 0 {
+ return idxExtCommunitySet, idxExtCommunity
+ }
+ for j, conExtCommunity := range conExtCommunitySet.ExtCommunityList {
+ if conExtCommunity == reqExtCommunitySet.ExtCommunityList[0] {
+ idxExtCommunity = j
+ return idxExtCommunitySet, idxExtCommunity
+ }
+ }
+ }
+ }
+ return idxExtCommunitySet, idxExtCommunity
+}
+
+// find index PolicyDefinition of request from PolicyDefinition of configuration file.
+// Return the idxPolicyDefinition of the location where the name of PolicyDefinition matches,
+// and idxStatement of the location where Statement of PolicyDefinition matches
+func IndexOfPolicyDefinition(conPolicyList []config.PolicyDefinition, reqPolicy config.PolicyDefinition) (int, int) {
+ idxPolicyDefinition := -1
+ idxStatement := -1
+ for i, conPolicy := range conPolicyList {
+ if conPolicy.Name == reqPolicy.Name {
+ idxPolicyDefinition = i
+ if reqPolicy.Statements.StatementList == nil {
+ return idxPolicyDefinition, idxStatement
+ }
+ for j, conStatement := range conPolicy.Statements.StatementList {
+ if conStatement.Name == reqPolicy.Statements.StatementList[0].Name {
+ idxStatement = j
+ return idxPolicyDefinition, idxStatement
+ }
+ }
+ }
+ }
+ return idxPolicyDefinition, idxStatement
+}
+
+func PrefixSetToApiStruct(ps config.PrefixSet) *gobgpapi.PrefixSet {
+ resPrefixList := make([]*gobgpapi.Prefix, 0)
+ for _, p := range ps.PrefixList {
+ resPrefix := &gobgpapi.Prefix{
+ IpPrefix: p.IpPrefix,
+ MaskLengthRange: p.MasklengthRange,
+ }
+ resPrefixList = append(resPrefixList, resPrefix)
+ }
+ resPrefixSet := &gobgpapi.PrefixSet{
+ PrefixSetName: ps.PrefixSetName,
+ PrefixList: resPrefixList,
+ }
+
+ return resPrefixSet
+}
+
+func PrefixSetToConfigStruct(reqPrefixSet *gobgpapi.PrefixSet) (bool, config.PrefixSet) {
+ var prefix config.Prefix
+ var prefixSet config.PrefixSet
+ isReqPrefixSet := true
+ if reqPrefixSet.PrefixList != nil {
+ prefix = config.Prefix{
+ IpPrefix: reqPrefixSet.PrefixList[0].IpPrefix,
+ MasklengthRange: reqPrefixSet.PrefixList[0].MaskLengthRange,
+ }
+ prefixList := []config.Prefix{prefix}
+
+ prefixSet = config.PrefixSet{
+ PrefixSetName: reqPrefixSet.PrefixSetName,
+ PrefixList: prefixList,
+ }
+ } else {
+ isReqPrefixSet = false
+ prefixSet = config.PrefixSet{
+ PrefixSetName: reqPrefixSet.PrefixSetName,
+ PrefixList: nil,
+ }
+ }
+ return isReqPrefixSet, prefixSet
+}
+
+func NeighborSetToApiStruct(ns config.NeighborSet) *gobgpapi.NeighborSet {
+ resNeighborList := make([]*gobgpapi.Neighbor, 0)
+ for _, n := range ns.NeighborInfoList {
+ resNeighbor := &gobgpapi.Neighbor{
+ Address: n.Address.String(),
+ }
+ resNeighborList = append(resNeighborList, resNeighbor)
+ }
+ resNeighborSet := &gobgpapi.NeighborSet{
+ NeighborSetName: ns.NeighborSetName,
+ NeighborList: resNeighborList,
+ }
+ return resNeighborSet
+}
+
+func NeighborSetToConfigStruct(reqNeighborSet *gobgpapi.NeighborSet) (bool, config.NeighborSet) {
+ var neighbor config.NeighborInfo
+ var neighborSet config.NeighborSet
+ isReqNeighborSet := true
+ if reqNeighborSet.NeighborList != nil {
+ neighbor = config.NeighborInfo{
+ Address: net.ParseIP(reqNeighborSet.NeighborList[0].Address),
+ }
+ neighborList := []config.NeighborInfo{neighbor}
+
+ neighborSet = config.NeighborSet{
+ NeighborSetName: reqNeighborSet.NeighborSetName,
+ NeighborInfoList: neighborList,
+ }
+ } else {
+ isReqNeighborSet = false
+ neighborSet = config.NeighborSet{
+ NeighborSetName: reqNeighborSet.NeighborSetName,
+ NeighborInfoList: nil,
+ }
+ }
+ return isReqNeighborSet, neighborSet
+}
+
+func AsPathSetToApiStruct(as config.AsPathSet) *gobgpapi.AsPathSet {
+ resAsPathMembers := make([]string, 0)
+ for _, a := range as.AsPathList {
+ resAsPathMembers = append(resAsPathMembers, a.AsPath)
+ }
+ resAsPathSet := &gobgpapi.AsPathSet{
+ AsPathSetName: as.AsPathSetName,
+ AsPathMembers: resAsPathMembers,
+ }
+ return resAsPathSet
+}
+
+func AsPathSetToConfigStruct(reqAsPathSet *gobgpapi.AsPathSet) (bool, config.AsPathSet) {
+ isAsPathSetSet := true
+ if len(reqAsPathSet.AsPathMembers) == 0 {
+ isAsPathSetSet = false
+ }
+ asPathList := make([]config.AsPath, 0)
+ for _, a := range reqAsPathSet.AsPathMembers {
+ asPathList = append(asPathList, config.AsPath{AsPath: a})
+ }
+ asPathSet := config.AsPathSet{
+ AsPathSetName: reqAsPathSet.AsPathSetName,
+ AsPathList: asPathList,
+ }
+ return isAsPathSetSet, asPathSet
+}
+
+func CommunitySetToApiStruct(cs config.CommunitySet) *gobgpapi.CommunitySet {
+ resCommunityMembers := make([]string, 0)
+ for _, c := range cs.CommunityList {
+ resCommunityMembers = append(resCommunityMembers, c.Community)
+ }
+ resCommunitySet := &gobgpapi.CommunitySet{
+ CommunitySetName: cs.CommunitySetName,
+ CommunityMembers: resCommunityMembers,
+ }
+ return resCommunitySet
+}
+
+func CommunitySetToConfigStruct(reqCommunitySet *gobgpapi.CommunitySet) (bool, config.CommunitySet) {
+ isCommunitySet := true
+ if len(reqCommunitySet.CommunityMembers) == 0 {
+ isCommunitySet = false
+ }
+ communityList := make([]config.Community, 0)
+ for _, c := range reqCommunitySet.CommunityMembers {
+ communityList = append(communityList, config.Community{Community: c})
+ }
+ communitySet := config.CommunitySet{
+ CommunitySetName: reqCommunitySet.CommunitySetName,
+ CommunityList: communityList,
+ }
+ return isCommunitySet, communitySet
+}
+
+func ExtCommunitySetToApiStruct(es config.ExtCommunitySet) *gobgpapi.ExtCommunitySet {
+ resExtCommunityMembers := make([]string, 0)
+ for _, ec := range es.ExtCommunityList {
+ resExtCommunityMembers = append(resExtCommunityMembers, ec.ExtCommunity)
+ }
+ resExtCommunitySet := &gobgpapi.ExtCommunitySet{
+ ExtCommunitySetName: es.ExtCommunitySetName,
+ ExtCommunityMembers: resExtCommunityMembers,
+ }
+ return resExtCommunitySet
+}
+
+func ExtCommunitySetToConfigStruct(reqExtCommunitySet *gobgpapi.ExtCommunitySet) (bool, config.ExtCommunitySet) {
+ isExtCommunitySet := true
+ if len(reqExtCommunitySet.ExtCommunityMembers) == 0 {
+ isExtCommunitySet = false
+ }
+ extCommunityList := make([]config.ExtCommunity, 0)
+ for _, ec := range reqExtCommunitySet.ExtCommunityMembers {
+ extCommunityList = append(extCommunityList, config.ExtCommunity{ExtCommunity: ec})
+ }
+ ExtCommunitySet := config.ExtCommunitySet{
+ ExtCommunitySetName: reqExtCommunitySet.ExtCommunitySetName,
+ ExtCommunityList: extCommunityList,
+ }
+ return isExtCommunitySet, ExtCommunitySet
+}
+
+func AsPathLengthToApiStruct(asPathLength config.AsPathLength) *gobgpapi.AsPathLength {
+ value := ""
+ if asPathLength.Operator != "" {
+ value = fmt.Sprintf("%d", asPathLength.Value)
+ }
+ resAsPathLength := &gobgpapi.AsPathLength{
+ Value: value,
+ Operator: asPathLength.Operator,
+ }
+ return resAsPathLength
+}
+
+func AsPathLengthToConfigStruct(reqAsPathLength *gobgpapi.AsPathLength) config.AsPathLength {
+ operator := reqAsPathLength.Operator
+ value := reqAsPathLength.Value
+ valueUint, _ := strconv.ParseUint(value, 10, 32)
+ asPathLength := config.AsPathLength{
+ Operator: operator,
+ Value: uint32(valueUint),
+ }
+ return asPathLength
+}
+
+func ConditionsToConfigStruct(reqConditions *gobgpapi.Conditions) config.Conditions {
+ conditions := config.Conditions{}
+ if reqConditions == nil {
+ return conditions
+ }
+ if reqConditions.MatchPrefixSet != nil {
+ conditions.MatchPrefixSet.PrefixSet = reqConditions.MatchPrefixSet.PrefixSetName
+ conditions.MatchPrefixSet.MatchSetOptions =
+ MatchSetOptionsRestrictedToType(reqConditions.MatchPrefixSet.MatchSetOptions)
+ }
+ if reqConditions.MatchNeighborSet != nil {
+ conditions.MatchNeighborSet.NeighborSet = reqConditions.MatchNeighborSet.NeighborSetName
+ conditions.MatchNeighborSet.MatchSetOptions =
+ MatchSetOptionsRestrictedToType(reqConditions.MatchNeighborSet.MatchSetOptions)
+ }
+ if reqConditions.MatchAsPathSet != nil {
+ conditions.BgpConditions.MatchAsPathSet.AsPathSet = reqConditions.MatchAsPathSet.AsPathSetName
+ conditions.BgpConditions.MatchAsPathSet.MatchSetOptions =
+ MatchSetOptionsToType(reqConditions.MatchAsPathSet.MatchSetOptions)
+ }
+ if reqConditions.MatchCommunitySet != nil {
+ conditions.BgpConditions.MatchCommunitySet.CommunitySet = reqConditions.MatchCommunitySet.CommunitySetName
+ conditions.BgpConditions.MatchCommunitySet.MatchSetOptions =
+ MatchSetOptionsToType(reqConditions.MatchCommunitySet.MatchSetOptions)
+ }
+ if reqConditions.MatchExtCommunitySet != nil {
+ conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet = reqConditions.MatchExtCommunitySet.ExtCommunitySetName
+ conditions.BgpConditions.MatchExtCommunitySet.MatchSetOptions =
+ MatchSetOptionsToType(reqConditions.MatchExtCommunitySet.MatchSetOptions)
+ }
+ if reqConditions.MatchAsPathLength != nil {
+ conditions.BgpConditions.AsPathLength =
+ AsPathLengthToConfigStruct(reqConditions.MatchAsPathLength)
+ }
+ return conditions
+}
+
+func ActionsToApiStruct(conActions config.Actions) *gobgpapi.Actions {
+ action := gobgpapi.RouteAction_REJECT
+ if conActions.RouteDisposition.AcceptRoute {
+ action = gobgpapi.RouteAction_ACCEPT
+ }
+
+ //TODO: support CommunitySetRef
+ communityAction := &gobgpapi.CommunityAction{
+ Communities: conActions.BgpActions.SetCommunity.SetCommunityMethod.Communities,
+ Options: conActions.BgpActions.SetCommunity.Options,
+ }
+ medAction := fmt.Sprintf("%s", conActions.BgpActions.SetMed)
+ asprependAction := &gobgpapi.AsPrependAction{
+ conActions.BgpActions.SetAsPathPrepend.As,
+ uint32(conActions.BgpActions.SetAsPathPrepend.RepeatN),
+ }
+ extCommunityAction := &gobgpapi.CommunityAction{
+ Communities: conActions.BgpActions.SetExtCommunity.SetExtCommunityMethod.Communities,
+ Options: conActions.BgpActions.SetExtCommunity.Options,
+ }
+
+ resActions := &gobgpapi.Actions{
+ RouteAction: action,
+ Community: communityAction,
+ Med: medAction,
+ AsPrepend: asprependAction,
+ ExtCommunity: extCommunityAction,
+ }
+ return resActions
+}
+
+func ActionsToConfigStruct(reqActions *gobgpapi.Actions) config.Actions {
+ actions := config.Actions{}
+ if reqActions == nil {
+ return actions
+ }
+ if reqActions.Community != nil {
+ actions.BgpActions.SetCommunity.SetCommunityMethod.Communities = reqActions.Community.Communities
+ actions.BgpActions.SetCommunity.Options = reqActions.Community.Options
+ }
+ if reqActions.Med != "" {
+ actions.BgpActions.SetMed = config.BgpSetMedType(reqActions.Med)
+ }
+ if reqActions.AsPrepend != nil {
+ actions.BgpActions.SetAsPathPrepend.As = reqActions.AsPrepend.As
+ actions.BgpActions.SetAsPathPrepend.RepeatN = uint8(reqActions.AsPrepend.Repeatn)
+ }
+
+ switch reqActions.RouteAction {
+ case gobgpapi.RouteAction_ACCEPT:
+ actions.RouteDisposition.AcceptRoute = true
+ case gobgpapi.RouteAction_REJECT:
+ actions.RouteDisposition.RejectRoute = true
+ }
+ return actions
+}
+
+func StatementToConfigStruct(reqStatement *gobgpapi.Statement) config.Statement {
+ statement := config.Statement{
+ Name: reqStatement.StatementNeme,
+ Conditions: ConditionsToConfigStruct(reqStatement.Conditions),
+ Actions: ActionsToConfigStruct(reqStatement.Actions),
+ }
+ return statement
+}
+
+func PolicyDefinitionToConfigStruct(reqPolicy *gobgpapi.PolicyDefinition) (bool, config.PolicyDefinition) {
+ isReqStatement := true
+ policy := config.PolicyDefinition{
+ Name: reqPolicy.PolicyDefinitionName,
+ }
+ if reqPolicy.StatementList != nil {
+ statement := StatementToConfigStruct(reqPolicy.StatementList[0])
+ policy.Statements.StatementList = []config.Statement{statement}
+ } else {
+ isReqStatement = false
+ }
+ return isReqStatement, policy
+}
+
+func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSets) *gobgpapi.PolicyDefinition {
+ conPrefixSetList := df.PrefixSets.PrefixSetList
+ conNeighborSetList := df.NeighborSets.NeighborSetList
+ conAsPathSetList := df.BgpDefinedSets.AsPathSets.AsPathSetList
+ conCommunitySetList := df.BgpDefinedSets.CommunitySets.CommunitySetList
+ conExtCommunitySetList := df.BgpDefinedSets.ExtCommunitySets.ExtCommunitySetList
+ resStatementList := make([]*gobgpapi.Statement, 0)
+ for _, st := range pd.Statements.StatementList {
+ co := st.Conditions
+ bco := co.BgpConditions
+ ac := st.Actions
+
+ prefixSet := &gobgpapi.PrefixSet{PrefixSetName: co.MatchPrefixSet.PrefixSet}
+ conPrefixSet := config.PrefixSet{PrefixSetName: co.MatchPrefixSet.PrefixSet}
+ idxPrefixSet, _ := IndexOfPrefixSet(conPrefixSetList, conPrefixSet)
+ if idxPrefixSet != -1 {
+ prefixSet = PrefixSetToApiStruct(conPrefixSetList[idxPrefixSet])
+ prefixSet.MatchSetOptions = MatchSetOptionsRestrictedToString(st.Conditions.MatchPrefixSet.MatchSetOptions)
+ }
+ neighborSet := &gobgpapi.NeighborSet{NeighborSetName: co.MatchNeighborSet.NeighborSet}
+ conNeighborSet := config.NeighborSet{NeighborSetName: co.MatchNeighborSet.NeighborSet}
+ idxNeighborSet, _ := IndexOfNeighborSet(conNeighborSetList, conNeighborSet)
+ if idxNeighborSet != -1 {
+ neighborSet = NeighborSetToApiStruct(conNeighborSetList[idxNeighborSet])
+ neighborSet.MatchSetOptions = MatchSetOptionsRestrictedToString(st.Conditions.MatchNeighborSet.MatchSetOptions)
+ }
+
+ asPathSet := &gobgpapi.AsPathSet{AsPathSetName: bco.MatchAsPathSet.AsPathSet}
+ conAsPathSet := config.AsPathSet{AsPathSetName: bco.MatchAsPathSet.AsPathSet}
+ idxAsPathSet, _ := IndexOfAsPathSet(conAsPathSetList, conAsPathSet)
+ if idxAsPathSet != -1 {
+ asPathSet = AsPathSetToApiStruct(conAsPathSetList[idxAsPathSet])
+ asPathSet.MatchSetOptions = MatchSetOptionToString(bco.MatchAsPathSet.MatchSetOptions)
+ }
+
+ communitySet := &gobgpapi.CommunitySet{CommunitySetName: bco.MatchCommunitySet.CommunitySet}
+ conCommunitySet := config.CommunitySet{CommunitySetName: bco.MatchCommunitySet.CommunitySet}
+ idxCommunitySet, _ := IndexOfCommunitySet(conCommunitySetList, conCommunitySet)
+ if idxCommunitySet != -1 {
+ communitySet = CommunitySetToApiStruct(conCommunitySetList[idxCommunitySet])
+ communitySet.MatchSetOptions = MatchSetOptionToString(bco.MatchCommunitySet.MatchSetOptions)
+ }
+
+ extCommunitySet := &gobgpapi.ExtCommunitySet{ExtCommunitySetName: bco.MatchExtCommunitySet.ExtCommunitySet}
+ conExtCommunitySet := config.ExtCommunitySet{ExtCommunitySetName: bco.MatchExtCommunitySet.ExtCommunitySet}
+ idxExtCommunitySet, _ := IndexOfExtCommunitySet(conExtCommunitySetList, conExtCommunitySet)
+ if idxExtCommunitySet != -1 {
+ extCommunitySet = ExtCommunitySetToApiStruct(conExtCommunitySetList[idxExtCommunitySet])
+ extCommunitySet.MatchSetOptions = MatchSetOptionToString(bco.MatchExtCommunitySet.MatchSetOptions)
+ }
+
+ resConditions := &gobgpapi.Conditions{
+ MatchPrefixSet: prefixSet,
+ MatchNeighborSet: neighborSet,
+ MatchAsPathSet: asPathSet,
+ MatchCommunitySet: communitySet,
+ MatchExtCommunitySet: extCommunitySet,
+ MatchAsPathLength: AsPathLengthToApiStruct(st.Conditions.BgpConditions.AsPathLength),
+ }
+ resActions := ActionsToApiStruct(ac)
+ resStatement := &gobgpapi.Statement{
+ StatementNeme: st.Name,
+ Conditions: resConditions,
+ Actions: resActions,
+ }
+ resStatementList = append(resStatementList, resStatement)
+ }
+ resPolicyDefinition := &gobgpapi.PolicyDefinition{
+ PolicyDefinitionName: pd.Name,
+ StatementList: resStatementList,
+ }
+ return resPolicyDefinition
+}
+
+func PoliciesToString(reqPolicies []*gobgpapi.PolicyDefinition) []string {
+ policies := make([]string, 0)
+ for _, reqPolicy := range reqPolicies {
+ policies = append(policies, reqPolicy.PolicyDefinitionName)
+ }
+ return policies
+}
+
+func CanImportToVrf(v *Vrf, path *Path) bool {
+ f := func(arg []bgp.ExtendedCommunityInterface) []config.ExtCommunity {
+ ret := make([]config.ExtCommunity, 0, len(arg))
+ for _, a := range arg {
+ ret = append(ret, config.ExtCommunity{
+ ExtCommunity: fmt.Sprintf("RT:%s", a.String()),
+ })
+ }
+ return ret
+ }
+ set := config.ExtCommunitySet{
+ ExtCommunitySetName: v.Name,
+ ExtCommunityList: f(v.ImportRt),
+ }
+ matchSet := config.MatchExtCommunitySet{
+ ExtCommunitySet: v.Name,
+ MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY,
+ }
+ return NewExtCommunityCondition(matchSet, []config.ExtCommunitySet{set}).evaluate(path)
+}
diff --git a/table/policy_test.go b/table/policy_test.go
new file mode 100644
index 00000000..588a769b
--- /dev/null
+++ b/table/policy_test.go
@@ -0,0 +1,2139 @@
+// Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package table
+
+import (
+ "fmt"
+ log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/config"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ "math"
+ "net"
+ "regexp"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+)
+
+func init() {
+ log.SetLevel(log.DebugLevel)
+}
+
+func TestPrefixCalcurateNoRange(t *testing.T) {
+ log.SetLevel(log.DebugLevel)
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.0")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("10.10.0.0/24", "")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, true, match1)
+ pl2, _ := NewPrefix("10.10.0.0/23", "")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, false, match2)
+ pl3, _ := NewPrefix("10.10.0.0/16", "21..24")
+ match3 := ipPrefixCalculate(path, pl3)
+ assert.Equal(t, true, match3)
+}
+
+func TestPrefixCalcurateAddress(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("10.11.0.0/16", "21..24")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("10.10.0.0/16", "21..24")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, true, match2)
+}
+
+func TestPrefixCalcurateLength(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("10.10.64.0/24", "21..24")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("10.10.64.0/16", "21..24")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, true, match2)
+}
+
+func TestPrefixCalcurateLengthRange(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("10.10.0.0/16", "21..23")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("10.10.0.0/16", "25..26")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, false, match2)
+ pl3, _ := NewPrefix("10.10.0.0/16", "21..24")
+ match3 := ipPrefixCalculate(path, pl3)
+ assert.Equal(t, true, match3)
+}
+
+func TestPrefixCalcurateNoRangeIPv6(t *testing.T) {
+ log.SetLevel(log.DebugLevel)
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ mpnlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mpreach := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mpnlri)
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{mpreach, origin, aspath, med}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("2001:123:123::/48", "")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("2001:123:123:1::/64", "")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, true, match2)
+ pl3, _ := NewPrefix("2001:123:123::/48", "64..80")
+ match3 := ipPrefixCalculate(path, pl3)
+ assert.Equal(t, true, match3)
+}
+
+func TestPrefixCalcurateAddressIPv6(t *testing.T) {
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ mpnlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mpreach := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mpnlri)
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{mpreach, origin, aspath, med}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("2001:123:128::/48", "64..80")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("2001:123:123::/48", "64..80")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, true, match2)
+}
+
+func TestPrefixCalcurateLengthIPv6(t *testing.T) {
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ mpnlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mpreach := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mpnlri)
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{mpreach, origin, aspath, med}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("2001:123:123:64::/64", "64..80")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("2001:123:123:64::/48", "64..80")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, true, match2)
+}
+
+func TestPrefixCalcurateLengthRangeIPv6(t *testing.T) {
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ mpnlri := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mpreach := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mpnlri)
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{mpreach, origin, aspath, med}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil)
+ path := ProcessMessage(updateMsg, peer)[0]
+ // test
+ pl1, _ := NewPrefix("2001:123:123::/48", "62..63")
+ match1 := ipPrefixCalculate(path, pl1)
+ assert.Equal(t, false, match1)
+ pl2, _ := NewPrefix("2001:123:123::/48", "65..66")
+ match2 := ipPrefixCalculate(path, pl2)
+ assert.Equal(t, false, match2)
+ pl3, _ := NewPrefix("2001:123:123::/48", "63..65")
+ match3 := ipPrefixCalculate(path, pl3)
+ assert.Equal(t, true, match3)
+}
+
+func TestPolicyNotMatch(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ ps := createPrefixSet("ps1", "10.3.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", false)
+ 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_NONE, pType)
+ assert.Equal(t, newPath, path)
+}
+
+func TestPolicyMatchAndReject(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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", false)
+ 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_REJECT, pType)
+ assert.Equal(t, newPath, path)
+}
+
+func TestPolicyMatchAndAccept(t *testing.T) {
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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)
+ 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.Equal(t, path, newPath)
+}
+
+func TestPolicyRejectOnlyPrefixSet(t *testing.T) {
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.1.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.1.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.1.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path1 := ProcessMessage(updateMsg, peer)[0]
+
+ peer = &PeerInfo{AS: 65002, Address: net.ParseIP("10.0.2.2")}
+ origin = bgp.NewPathAttributeOrigin(0)
+ aspathParam = []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65002})}
+ aspath = bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop = bgp.NewPathAttributeNextHop("10.0.2.2")
+ med = bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes = []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri = []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.9.2.102")}
+ updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path2 := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ ps := createPrefixSet("ps1", "10.10.1.0/16", "21..24")
+ ds := config.DefinedSets{}
+ ds.PrefixSets.PrefixSetList = []config.PrefixSet{ps}
+
+ s := createStatement("statement1", "ps1", "ns1", false)
+ pd := createPolicyDefinition("pd1", s)
+ pl := createRoutingPolicy(ds, pd)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path1)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType)
+ assert.Equal(t, newPath, path1)
+
+ pType2, newPath2 := p.Apply(path2)
+ assert.Equal(t, ROUTE_TYPE_NONE, pType2)
+ assert.Equal(t, newPath2, path2)
+}
+
+func TestPolicyRejectOnlyNeighborSet(t *testing.T) {
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.1.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.1.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.1.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path1 := ProcessMessage(updateMsg, peer)[0]
+
+ peer = &PeerInfo{AS: 65002, Address: net.ParseIP("10.0.2.2")}
+ origin = bgp.NewPathAttributeOrigin(0)
+ aspathParam = []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65002})}
+ aspath = bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop = bgp.NewPathAttributeNextHop("10.0.2.2")
+ med = bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes = []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri = []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.2.102")}
+ updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path2 := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ ns := createNeighborSet("ns1", "10.0.1.1")
+ ds := config.DefinedSets{}
+ ds.NeighborSets.NeighborSetList = []config.NeighborSet{ns}
+
+ s := createStatement("statement1", "ps1", "ns1", false)
+ pd := createPolicyDefinition("pd1", s)
+ pl := createRoutingPolicy(ds, pd)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path1)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType)
+ assert.Equal(t, newPath, path1)
+
+ pType2, newPath2 := p.Apply(path2)
+ assert.Equal(t, ROUTE_TYPE_NONE, pType2)
+ assert.Equal(t, newPath2, path2)
+}
+
+func TestPolicyDifferentRoutefamilyOfPathAndPolicy(t *testing.T) {
+ // create path ipv4
+ peerIPv4 := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ originIPv4 := bgp.NewPathAttributeOrigin(0)
+ aspathParamIPv4 := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspathIPv4 := bgp.NewPathAttributeAsPath(aspathParamIPv4)
+ nexthopIPv4 := bgp.NewPathAttributeNextHop("10.0.0.1")
+ medIPv4 := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributesIPv4 := []bgp.PathAttributeInterface{originIPv4, aspathIPv4, nexthopIPv4, medIPv4}
+ nlriIPv4 := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsgIPv4 := bgp.NewBGPUpdateMessage(nil, pathAttributesIPv4, nlriIPv4)
+ pathIPv4 := ProcessMessage(updateMsgIPv4, peerIPv4)[0]
+ // create path ipv6
+ peerIPv6 := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
+ originIPv6 := bgp.NewPathAttributeOrigin(0)
+ aspathParamIPv6 := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})}
+ aspathIPv6 := bgp.NewPathAttributeAsPath(aspathParamIPv6)
+ mpnlriIPv6 := []bgp.AddrPrefixInterface{bgp.NewIPv6AddrPrefix(64, "2001:123:123:1::")}
+ mpreachIPv6 := bgp.NewPathAttributeMpReachNLRI("2001::192:168:50:1", mpnlriIPv6)
+ medIPv6 := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributesIPv6 := []bgp.PathAttributeInterface{mpreachIPv6, originIPv6, aspathIPv6, medIPv6}
+ updateMsgIPv6 := bgp.NewBGPUpdateMessage(nil, pathAttributesIPv6, nil)
+ pathIPv6 := ProcessMessage(updateMsgIPv6, peerIPv6)[0]
+ // create policy
+ psIPv4 := createPrefixSet("psIPv4", "10.10.0.0/16", "21..24")
+ nsIPv4 := createNeighborSet("nsIPv4", "10.0.0.1")
+
+ psIPv6 := createPrefixSet("psIPv6", "2001:123:123::/48", "64..80")
+ nsIPv6 := createNeighborSet("nsIPv6", "2001::192:168:50:1")
+
+ ds := config.DefinedSets{}
+ ds.PrefixSets.PrefixSetList = []config.PrefixSet{psIPv4, psIPv6}
+ ds.NeighborSets.NeighborSetList = []config.NeighborSet{nsIPv4, nsIPv6}
+
+ stIPv4 := createStatement("statement1", "psIPv4", "nsIPv4", false)
+ stIPv6 := createStatement("statement2", "psIPv6", "nsIPv6", false)
+
+ pd := createPolicyDefinition("pd1", stIPv4, stIPv6)
+ pl := createRoutingPolicy(ds, pd)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType1, newPath1 := p.Apply(pathIPv4)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType1)
+ assert.Equal(t, newPath1, pathIPv4)
+
+ pType2, newPath2 := p.Apply(pathIPv6)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType2)
+ assert.Equal(t, newPath2, pathIPv6)
+}
+
+func TestAsPathLengthConditionEvaluate(t *testing.T) {
+ // setup
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create match condition
+ asPathLength := config.AsPathLength{
+ Operator: "eq",
+ Value: 5,
+ }
+ c := NewAsPathLengthCondition(asPathLength)
+
+ // test
+ assert.Equal(t, true, c.evaluate(path))
+
+ // create match condition
+ asPathLength = config.AsPathLength{
+ Operator: "ge",
+ Value: 3,
+ }
+ c = NewAsPathLengthCondition(asPathLength)
+
+ // test
+ assert.Equal(t, true, c.evaluate(path))
+
+ // create match condition
+ asPathLength = config.AsPathLength{
+ Operator: "le",
+ Value: 3,
+ }
+ c = NewAsPathLengthCondition(asPathLength)
+
+ // test
+ assert.Equal(t, false, c.evaluate(path))
+}
+
+func TestAsPathLengthConditionWithOtherCondition(t *testing.T) {
+ // setup
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ ps := createPrefixSet("ps1", "10.10.1.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}
+
+ // create match condition
+ asPathLength := config.AsPathLength{
+ Operator: "le",
+ Value: 10,
+ }
+
+ s := createStatement("statement1", "ps1", "ns1", false)
+ s.Conditions.BgpConditions.AsPathLength = asPathLength
+ 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_REJECT, pType)
+ assert.Equal(t, newPath, path)
+
+}
+
+func TestAsPathConditionEvaluate(t *testing.T) {
+
+ // setup
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam1 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate))
+ path1 := ProcessMessage(updateMsg1, peer)[0]
+
+ aspathParam2 := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(2, []uint16{65010}),
+ }
+ aspath2 := bgp.NewPathAttributeAsPath(aspathParam2)
+ pathAttributes = []bgp.PathAttributeInterface{origin, aspath2, nexthop, med}
+ updateMsg2 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg2.Body.(*bgp.BGPUpdate))
+ path2 := ProcessMessage(updateMsg2, peer)[0]
+
+ // create match condition
+ asPathSet1 := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "^65001"},
+ },
+ }
+
+ asPathSet2 := config.AsPathSet{
+ AsPathSetName: "asset2",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65005$"},
+ },
+ }
+
+ asPathSet3 := config.AsPathSet{
+ AsPathSetName: "asset3",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65004"},
+ config.AsPath{AsPath: "65005$"},
+ },
+ }
+
+ asPathSet4 := config.AsPathSet{
+ AsPathSetName: "asset4",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65000$"},
+ },
+ }
+
+ asPathSet5 := config.AsPathSet{
+ AsPathSetName: "asset5",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "65010"},
+ },
+ }
+
+ asPathSet6 := config.AsPathSet{
+ AsPathSetName: "asset6",
+ AsPathList: []config.AsPath{
+ config.AsPath{AsPath: "^65010$"},
+ },
+ }
+
+ asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3,
+ asPathSet4, asPathSet5, asPathSet6}
+
+ 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)
+
+ //TODO: add ALL and INVERT cases.
+ p7 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_ALL)
+ p8 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_INVERT)
+
+ // 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, true, p5.evaluate(path1))
+ assert.Equal(t, false, p6.evaluate(path1))
+ assert.Equal(t, true, p6.evaluate(path2))
+
+ assert.Equal(t, true, p7.evaluate(path1))
+ assert.Equal(t, true, p8.evaluate(path2))
+}
+
+func TestMultipleAsPathConditionEvaluate(t *testing.T) {
+
+ // setup
+ // create path
+ peer := &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}),
+ }
+ aspath := bgp.NewPathAttributeAsPath(aspathParam1)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate))
+ path1 := 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]+_5[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, true, p8.evaluate(path1))
+ assert.Equal(t, false, p9.evaluate(path1))
+}
+
+func TestAsPathCondition(t *testing.T) {
+ type astest struct {
+ path *Path
+ result bool
+ }
+
+ makeTest := func(asPathAttrType uint8, ases []uint32, result bool) astest {
+ aspathParam := []bgp.AsPathParamInterface{
+ bgp.NewAs4PathParam(asPathAttrType, ases),
+ }
+ pathAttributes := []bgp.PathAttributeInterface{bgp.NewPathAttributeAsPath(aspathParam)}
+ p := NewPath(nil, nil, false, pathAttributes, false, time.Time{}, false)
+ return astest{
+ path: p,
+ result: result,
+ }
+ }
+
+ tests := make(map[string][]astest)
+
+ tests["^(100_)+(200_)+$"] = []astest{
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{100, 200}, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{100, 100, 200}, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{100, 100, 200, 200}, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{100, 100, 200, 200, 300}, false),
+ }
+
+ aslen255 := func() []uint32 {
+ r := make([]uint32, 255)
+ for i := 0; i < 255; i++ {
+ r[i] = 1
+ }
+ return r
+ }()
+ tests["^([0-9]+_){0,255}$"] = []astest{
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, aslen255, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, append(aslen255, 1), false),
+ }
+
+ tests["(_7521)$"] = []astest{
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{7521}, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{1000, 7521}, true),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{7521, 1000}, false),
+ makeTest(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{1000, 7521, 100}, false),
+ }
+
+ for k, v := range tests {
+ r, _ := regexp.Compile(strings.Replace(k, "_", ASPATH_REGEXP_MAGIC, -1))
+ c := &AsPathCondition{
+ AsRegExpList: []*regexp.Regexp{r},
+ MatchOption: config.MATCH_SET_OPTIONS_TYPE_ANY,
+ }
+ for _, a := range v {
+ result := c.evaluate(a.path)
+ if a.result != result {
+ log.WithFields(log.Fields{
+ "EXP": k,
+ "ASN": r,
+ "ASSTR": a.path.GetAsString(),
+ "Expected": a.result,
+ "Result": result,
+ }).Fatal("failed")
+ }
+ }
+ }
+}
+
+func TestAsPathConditionWithOtherCondition(t *testing.T) {
+
+ // setup
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}),
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ asPathSet := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathList: []config.AsPath{config.AsPath{"65005$"}},
+ }
+
+ ps := createPrefixSet("ps1", "10.10.1.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}
+ ds.BgpDefinedSets.AsPathSets.AsPathSetList = []config.AsPathSet{asPathSet}
+
+ s := createStatement("statement1", "ps1", "ns1", false)
+ s.Conditions.BgpConditions.MatchAsPathSet.AsPathSet = "asset1"
+
+ 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_REJECT, pType)
+ assert.Equal(t, newPath, path)
+
+}
+
+func TestCommunityConditionEvaluate(t *testing.T) {
+
+ log.SetLevel(log.DebugLevel)
+
+ // setup
+ // create path
+ peer := &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)
+ communities := bgp.NewPathAttributeCommunities([]uint32{
+ stringToCommunityValue("65001:100"),
+ stringToCommunityValue("65001:200"),
+ stringToCommunityValue("65001:300"),
+ stringToCommunityValue("65001:400"),
+ 0x00000000,
+ 0xFFFFFF01,
+ 0xFFFFFF02,
+ 0xFFFFFF03})
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate))
+ path1 := ProcessMessage(updateMsg1, peer)[0]
+
+ // create match condition
+ comSet1 := config.CommunitySet{
+ CommunitySetName: "comset1",
+ CommunityList: []config.Community{
+ config.Community{"65001:10"},
+ config.Community{"65001:50"},
+ config.Community{"65001:100"},
+ },
+ }
+
+ comSet2 := config.CommunitySet{
+ CommunitySetName: "comset2",
+ CommunityList: []config.Community{
+ config.Community{"65001:200"},
+ },
+ }
+
+ comSet3 := config.CommunitySet{
+ CommunitySetName: "comset3",
+ CommunityList: []config.Community{
+ config.Community{"4259905936"},
+ },
+ }
+
+ comSet4 := config.CommunitySet{
+ CommunitySetName: "comset4",
+ CommunityList: []config.Community{
+ config.Community{"^[0-9]*:300$"},
+ },
+ }
+
+ comSet5 := config.CommunitySet{
+ CommunitySetName: "comset5",
+ CommunityList: []config.Community{
+ config.Community{"INTERNET"},
+ },
+ }
+
+ comSet6 := config.CommunitySet{
+ CommunitySetName: "comset6",
+ CommunityList: []config.Community{
+ config.Community{"NO_EXPORT"},
+ },
+ }
+
+ comSet7 := config.CommunitySet{
+ CommunitySetName: "comset7",
+ CommunityList: []config.Community{
+ config.Community{"NO_ADVERTISE"},
+ },
+ }
+
+ comSet8 := config.CommunitySet{
+ CommunitySetName: "comset8",
+ CommunityList: []config.Community{
+ config.Community{"NO_EXPORT_SUBCONFED"},
+ },
+ }
+
+ comSet9 := config.CommunitySet{
+ CommunitySetName: "comset9",
+ CommunityList: []config.Community{
+ config.Community{"65001:100"},
+ config.Community{"65001:200"},
+ config.Community{"65001:300"},
+ },
+ }
+
+ comSet10 := config.CommunitySet{
+ CommunitySetName: "comset10",
+ CommunityList: []config.Community{
+ config.Community{"65001:1"},
+ config.Community{"65001:2"},
+ config.Community{"65001:3"},
+ },
+ }
+
+ comSetList := []config.CommunitySet{comSet1, comSet2, comSet3,
+ comSet4, comSet5, comSet6, comSet7, comSet8, comSet9, comSet10}
+
+ createCommunityC := func(name string, option config.MatchSetOptionsType) *CommunityCondition {
+ matchSet := config.MatchCommunitySet{}
+ matchSet.CommunitySet = name
+ matchSet.MatchSetOptions = option
+ c := NewCommunityCondition(matchSet, comSetList)
+ return c
+ }
+
+ // ANY case
+ p1 := createCommunityC("comset1", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p2 := createCommunityC("comset2", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p3 := createCommunityC("comset3", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p4 := createCommunityC("comset4", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p5 := createCommunityC("comset5", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p6 := createCommunityC("comset6", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p7 := createCommunityC("comset7", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p8 := createCommunityC("comset8", config.MATCH_SET_OPTIONS_TYPE_ANY)
+
+ // ALL case
+ p9 := createCommunityC("comset9", config.MATCH_SET_OPTIONS_TYPE_ALL)
+
+ // INVERT case
+ p10 := createCommunityC("comset10", config.MATCH_SET_OPTIONS_TYPE_INVERT)
+
+ // 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, true, p8.evaluate(path1))
+ assert.Equal(t, true, p9.evaluate(path1))
+ assert.Equal(t, true, p10.evaluate(path1))
+
+}
+
+func TestCommunityConditionEvaluateWithOtherCondition(t *testing.T) {
+
+ // setup
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}),
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 65004, 65005}),
+ }
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ communities := bgp.NewPathAttributeCommunities([]uint32{
+ stringToCommunityValue("65001:100"),
+ stringToCommunityValue("65001:200"),
+ stringToCommunityValue("65001:300"),
+ stringToCommunityValue("65001:400"),
+ 0x00000000,
+ 0xFFFFFF01,
+ 0xFFFFFF02,
+ 0xFFFFFF03})
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ asPathSet := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathList: []config.AsPath{
+ config.AsPath{"65005$"},
+ },
+ }
+
+ comSet1 := config.CommunitySet{
+ CommunitySetName: "comset1",
+ CommunityList: []config.Community{
+ config.Community{"65001:100"},
+ config.Community{"65001:200"},
+ config.Community{"65001:300"},
+ },
+ }
+
+ comSet2 := config.CommunitySet{
+ CommunitySetName: "comset2",
+ CommunityList: []config.Community{
+ config.Community{"65050:\\d+"},
+ },
+ }
+
+ 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}
+ ds.BgpDefinedSets.AsPathSets.AsPathSetList = []config.AsPathSet{asPathSet}
+ ds.BgpDefinedSets.CommunitySets.CommunitySetList = []config.CommunitySet{comSet1, comSet2}
+
+ s1 := createStatement("statement1", "ps1", "ns1", false)
+ s1.Conditions.BgpConditions.MatchAsPathSet.AsPathSet = "asset1"
+ s1.Conditions.BgpConditions.MatchCommunitySet.CommunitySet = "comset1"
+
+ s2 := createStatement("statement2", "ps1", "ns1", false)
+ s2.Conditions.BgpConditions.MatchAsPathSet.AsPathSet = "asset1"
+ s2.Conditions.BgpConditions.MatchCommunitySet.CommunitySet = "comset2"
+
+ pd1 := createPolicyDefinition("pd1", s1)
+ pd2 := createPolicyDefinition("pd2", s2)
+ pl := createRoutingPolicy(ds, pd1, pd2)
+
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType)
+ assert.Equal(t, newPath, path)
+
+ df = pl.DefinedSets
+ p = NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[1], df)
+ pType, newPath = p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_NONE, pType)
+ assert.Equal(t, newPath, path)
+
+}
+
+func TestPolicyMatchAndAddCommunities(t *testing.T) {
+
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ community := "65000:100"
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetCommunity = createSetCommunity("ADD", community)
+
+ 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)
+ log.Debug(newPath)
+ assert.Equal(t, []uint32{stringToCommunityValue(community)}, newPath.GetCommunities())
+}
+
+func TestPolicyMatchAndReplaceCommunities(t *testing.T) {
+
+ // create path
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ community := "65000:100"
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetCommunity = createSetCommunity("REPLACE", community)
+
+ 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(community)}, newPath.GetCommunities())
+}
+
+func TestPolicyMatchAndRemoveCommunities(t *testing.T) {
+
+ // create path
+ community1 := "65000:100"
+ community2 := "65000:200"
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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", community1)
+
+ 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 TestPolicyMatchAndRemoveCommunitiesRegexp(t *testing.T) {
+
+ // create path
+ community1 := "65000:100"
+ community2 := "65000:200"
+ community3 := "65100:100"
+ peer := &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 := 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 := &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 := 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
+ community1 := "65000:100"
+ community2 := "65000:200"
+ peer := &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.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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)
+ // action NULL is obsolate
+ s.Actions.BgpActions.SetCommunity.Options = "REPLACE"
+ s.Actions.BgpActions.SetCommunity.SetCommunityMethod.Communities = nil
+
+ 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{}, newPath.GetCommunities())
+}
+
+func TestExtCommunityConditionEvaluate(t *testing.T) {
+
+ log.SetLevel(log.DebugLevel)
+
+ // setup
+ // create path
+ peer := &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)
+ eComAsSpecific1 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65001,
+ LocalAdmin: 200,
+ IsTransitive: true,
+ }
+ eComIpPrefix1 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ IPv4: net.ParseIP("10.0.0.1"),
+ LocalAdmin: 300,
+ IsTransitive: true,
+ }
+ eComAs4Specific1 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030000,
+ LocalAdmin: 200,
+ IsTransitive: true,
+ }
+ eComAsSpecific2 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65002,
+ LocalAdmin: 200,
+ IsTransitive: false,
+ }
+ eComIpPrefix2 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ IPv4: net.ParseIP("10.0.0.2"),
+ LocalAdmin: 300,
+ IsTransitive: false,
+ }
+ eComAs4Specific2 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030001,
+ LocalAdmin: 200,
+ IsTransitive: false,
+ }
+ eComAsSpecific3 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_ORIGIN),
+ AS: 65010,
+ LocalAdmin: 300,
+ IsTransitive: true,
+ }
+ eComIpPrefix3 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_ORIGIN),
+ IPv4: net.ParseIP("10.0.10.10"),
+ LocalAdmin: 400,
+ IsTransitive: true,
+ }
+ eComAs4Specific3 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030002,
+ LocalAdmin: 500,
+ IsTransitive: true,
+ }
+ ec := []bgp.ExtendedCommunityInterface{eComAsSpecific1, eComIpPrefix1, eComAs4Specific1, eComAsSpecific2,
+ eComIpPrefix2, eComAs4Specific2, eComAsSpecific3, eComIpPrefix3, eComAs4Specific3}
+ extCommunities := bgp.NewPathAttributeExtendedCommunities(ec)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, extCommunities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate))
+ path1 := ProcessMessage(updateMsg1, peer)[0]
+
+ convUintStr := func(as uint32) string {
+ upper := strconv.FormatUint(uint64(as&0xFFFF0000>>16), 10)
+ lower := strconv.FormatUint(uint64(as&0x0000FFFF), 10)
+ str := fmt.Sprintf("%s.%s", upper, lower)
+ return str
+ }
+
+ // create match condition
+ ecomSet1 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet1",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:65001:200"},
+ },
+ }
+ ecomSet2 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet2",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:10.0.0.1:300"},
+ },
+ }
+ ecomSet3 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet3",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{fmt.Sprintf("RT:%s:200", convUintStr(65030000))},
+ },
+ }
+ ecomSet4 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet4",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:65002:200"},
+ },
+ }
+ ecomSet5 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet5",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:10.0.0.2:300"},
+ },
+ }
+ ecomSet6 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet6",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{fmt.Sprintf("RT:%s:200", convUintStr(65030001))},
+ },
+ }
+ ecomSet7 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet7",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"SoO:65010:300"},
+ },
+ }
+ ecomSet8 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet8",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"SoO:10.0.10.10:[0-9]+"},
+ },
+ }
+ ecomSet9 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet9",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:[0-9]+:[0-9]+"},
+ },
+ }
+ ecomSet10 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet10",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:65001:200"},
+ config.ExtCommunity{"RT:10.0.0.1:300"},
+ config.ExtCommunity{"SoO:10.0.10.10:[0-9]+"},
+ },
+ }
+
+ ecomSet11 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet11",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:65001:2"},
+ config.ExtCommunity{"RT:10.0.0.1:3"},
+ config.ExtCommunity{"SoO:11.0.10.10:[0-9]+"},
+ },
+ }
+
+ comSetList := []config.ExtCommunitySet{ecomSet1, ecomSet2, ecomSet3, ecomSet4, ecomSet5, ecomSet6, ecomSet7,
+ ecomSet8, ecomSet9, ecomSet10, ecomSet11}
+
+ createExtCommunityC := func(name string, option config.MatchSetOptionsType) *ExtCommunityCondition {
+ matchSet := config.MatchExtCommunitySet{}
+ matchSet.ExtCommunitySet = name
+ matchSet.MatchSetOptions = option
+ c := NewExtCommunityCondition(matchSet, comSetList)
+ return c
+ }
+
+ p1 := createExtCommunityC("ecomSet1", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p2 := createExtCommunityC("ecomSet2", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p3 := createExtCommunityC("ecomSet3", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p4 := createExtCommunityC("ecomSet4", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p5 := createExtCommunityC("ecomSet5", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p6 := createExtCommunityC("ecomSet6", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p7 := createExtCommunityC("ecomSet7", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p8 := createExtCommunityC("ecomSet8", config.MATCH_SET_OPTIONS_TYPE_ANY)
+ p9 := createExtCommunityC("ecomSet9", config.MATCH_SET_OPTIONS_TYPE_ANY)
+
+ // ALL case
+ p10 := createExtCommunityC("ecomSet10", config.MATCH_SET_OPTIONS_TYPE_ALL)
+
+ // INVERT case
+ p11 := createExtCommunityC("ecomSet11", config.MATCH_SET_OPTIONS_TYPE_INVERT)
+
+ // 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, p7.evaluate(path1))
+ assert.Equal(t, true, p8.evaluate(path1))
+ assert.Equal(t, true, p9.evaluate(path1))
+ assert.Equal(t, true, p10.evaluate(path1))
+ assert.Equal(t, true, p11.evaluate(path1))
+
+}
+
+func TestExtCommunityConditionEvaluateWithOtherCondition(t *testing.T) {
+
+ log.SetLevel(log.DebugLevel)
+
+ // setup
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.2.1.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{
+ bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}),
+ bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 65004, 65005}),
+ }
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.2.1.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+ eComAsSpecific1 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65001,
+ LocalAdmin: 200,
+ IsTransitive: true,
+ }
+ eComIpPrefix1 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ IPv4: net.ParseIP("10.0.0.1"),
+ LocalAdmin: 300,
+ IsTransitive: true,
+ }
+ eComAs4Specific1 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030000,
+ LocalAdmin: 200,
+ IsTransitive: true,
+ }
+ eComAsSpecific2 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65002,
+ LocalAdmin: 200,
+ IsTransitive: false,
+ }
+ eComIpPrefix2 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ IPv4: net.ParseIP("10.0.0.2"),
+ LocalAdmin: 300,
+ IsTransitive: false,
+ }
+ eComAs4Specific2 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030001,
+ LocalAdmin: 200,
+ IsTransitive: false,
+ }
+ eComAsSpecific3 := &bgp.TwoOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_ORIGIN),
+ AS: 65010,
+ LocalAdmin: 300,
+ IsTransitive: true,
+ }
+ eComIpPrefix3 := &bgp.IPv4AddressSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_ORIGIN),
+ IPv4: net.ParseIP("10.0.10.10"),
+ LocalAdmin: 400,
+ IsTransitive: true,
+ }
+ eComAs4Specific3 := &bgp.FourOctetAsSpecificExtended{
+ SubType: bgp.ExtendedCommunityAttrSubType(bgp.EC_SUBTYPE_ROUTE_TARGET),
+ AS: 65030002,
+ LocalAdmin: 500,
+ IsTransitive: true,
+ }
+ ec := []bgp.ExtendedCommunityInterface{eComAsSpecific1, eComIpPrefix1, eComAs4Specific1, eComAsSpecific2,
+ eComIpPrefix2, eComAs4Specific2, eComAsSpecific3, eComIpPrefix3, eComAs4Specific3}
+ extCommunities := bgp.NewPathAttributeExtendedCommunities(ec)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, extCommunities}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate))
+ path := ProcessMessage(updateMsg, peer)[0]
+
+ // create policy
+ asPathSet := config.AsPathSet{
+ AsPathSetName: "asset1",
+ AsPathList: []config.AsPath{
+ config.AsPath{"65005$"},
+ },
+ }
+
+ ecomSet1 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet1",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:65001:201"},
+ },
+ }
+ ecomSet2 := config.ExtCommunitySet{
+ ExtCommunitySetName: "ecomSet2",
+ ExtCommunityList: []config.ExtCommunity{
+ config.ExtCommunity{"RT:[0-9]+:[0-9]+"},
+ },
+ }
+
+ ps := createPrefixSet("ps1", "10.10.1.0/16", "21..24")
+ ns := createNeighborSet("ns1", "10.2.1.1")
+
+ ds := config.DefinedSets{}
+ ds.PrefixSets.PrefixSetList = []config.PrefixSet{ps}
+ ds.NeighborSets.NeighborSetList = []config.NeighborSet{ns}
+ ds.BgpDefinedSets.AsPathSets.AsPathSetList = []config.AsPathSet{asPathSet}
+ ds.BgpDefinedSets.ExtCommunitySets.ExtCommunitySetList = []config.ExtCommunitySet{ecomSet1, ecomSet2}
+
+ s1 := createStatement("statement1", "ps1", "ns1", false)
+ s1.Conditions.BgpConditions.MatchAsPathSet.AsPathSet = "asset1"
+ s1.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet = "ecomSet1"
+
+ s2 := createStatement("statement2", "ps1", "ns1", false)
+ s2.Conditions.BgpConditions.MatchAsPathSet.AsPathSet = "asset1"
+ s2.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet = "ecomSet2"
+
+ pd1 := createPolicyDefinition("pd1", s1)
+ pd2 := createPolicyDefinition("pd2", s2)
+ pl := createRoutingPolicy(ds, pd1, pd2)
+ //test
+ df := pl.DefinedSets
+ p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df)
+ pType, newPath := p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_NONE, pType)
+ assert.Equal(t, newPath, path)
+
+ p = NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[1], df)
+ pType, newPath = p.Apply(path)
+ assert.Equal(t, ROUTE_TYPE_REJECT, pType)
+ assert.Equal(t, newPath, path)
+
+}
+
+func TestPolicyMatchAndReplaceMed(t *testing.T) {
+
+ // create path
+ peer := &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(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := "200"
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+ v, err := newPath.GetMed()
+ assert.Nil(t, err)
+ newMed := fmt.Sprintf("%d", v)
+ assert.Equal(t, m, newMed)
+}
+
+func TestPolicyMatchAndAddingMed(t *testing.T) {
+
+ // create path
+ peer := &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(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := "+200"
+ ma := "300"
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+
+ v, err := newPath.GetMed()
+ assert.Nil(t, err)
+ newMed := fmt.Sprintf("%d", v)
+ assert.Equal(t, ma, newMed)
+}
+
+func TestPolicyMatchAndAddingMedOverFlow(t *testing.T) {
+
+ // create path
+ peer := &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(1)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := fmt.Sprintf("+%d", math.MaxUint32)
+ ma := "1"
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+
+ v, err := newPath.GetMed()
+ assert.Nil(t, err)
+ newMed := fmt.Sprintf("%d", v)
+ assert.Equal(t, ma, newMed)
+}
+
+func TestPolicyMatchAndSubtractMed(t *testing.T) {
+
+ // create path
+ peer := &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(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := "-50"
+ ma := "50"
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+
+ v, err := newPath.GetMed()
+ assert.Nil(t, err)
+ newMed := fmt.Sprintf("%d", v)
+ assert.Equal(t, ma, newMed)
+}
+
+func TestPolicyMatchAndSubtractMedUnderFlow(t *testing.T) {
+
+ // create path
+ peer := &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(100)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := "-101"
+ ma := "100"
+
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+
+ v, err := newPath.GetMed()
+ assert.Nil(t, err)
+ newMed := fmt.Sprintf("%d", v)
+ assert.Equal(t, ma, newMed)
+}
+
+func TestPolicyMatchWhenPathHaveNotMed(t *testing.T) {
+
+ // create path
+ peer := &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")
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+ path := 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}
+
+ m := "-50"
+ s := createStatement("statement1", "ps1", "ns1", true)
+ s.Actions.BgpActions.SetMed = config.BgpSetMedType(m)
+
+ 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)
+
+ _, err := newPath.GetMed()
+ assert.NotNil(t, err)
+}
+
+func TestPolicyAsPathPrepend(t *testing.T) {
+
+ assert := assert.New(t)
+
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001, 65000})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+
+ body := updateMsg.Body.(*bgp.BGPUpdate)
+ UpdatePathAttrs4ByteAs(body)
+ path := 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.SetAsPathPrepend.As = "65002"
+ s.Actions.BgpActions.SetAsPathPrepend.RepeatN = 10
+
+ 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(ROUTE_TYPE_ACCEPT, pType)
+ assert.NotEqual(nil, newPath)
+ assert.Equal([]uint32{65002, 65002, 65002, 65002, 65002, 65002, 65002, 65002, 65002, 65002, 65001, 65000}, newPath.GetAsSeqList())
+}
+
+func TestPolicyAsPathPrependLastAs(t *testing.T) {
+
+ assert := assert.New(t)
+ // create path
+ peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
+ origin := bgp.NewPathAttributeOrigin(0)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65002, 65001, 65000})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ nexthop := bgp.NewPathAttributeNextHop("10.0.0.1")
+ med := bgp.NewPathAttributeMultiExitDisc(0)
+
+ pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med}
+ nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.0.101")}
+ updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
+
+ body := updateMsg.Body.(*bgp.BGPUpdate)
+ UpdatePathAttrs4ByteAs(body)
+ path := 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.SetAsPathPrepend.As = "last-as"
+ s.Actions.BgpActions.SetAsPathPrepend.RepeatN = 5
+
+ 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(ROUTE_TYPE_ACCEPT, pType)
+ assert.NotEqual(nil, newPath)
+ assert.Equal([]uint32{65002, 65002, 65002, 65002, 65002, 65002, 65001, 65000}, newPath.GetAsSeqList())
+}
+
+func createStatement(name, psname, nsname string, accept bool) config.Statement {
+
+ c := config.Conditions{
+ MatchPrefixSet: config.MatchPrefixSet{
+ PrefixSet: psname,
+ },
+ MatchNeighborSet: config.MatchNeighborSet{
+ NeighborSet: nsname,
+ },
+ }
+ a := config.Actions{
+ RouteDisposition: config.RouteDisposition{
+ AcceptRoute: accept,
+ RejectRoute: !accept,
+ },
+ }
+ s := config.Statement{
+ Name: name,
+ Conditions: c,
+ Actions: a,
+ }
+ return s
+}
+
+func createSetCommunity(operation string, community ...string) config.SetCommunity {
+
+ s := config.SetCommunity{
+ SetCommunityMethod: config.SetCommunityMethod{
+ Communities: community,
+ },
+ Options: operation,
+ }
+ return s
+}
+
+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)
+}
+
+func createPolicyDefinition(defName string, stmt ...config.Statement) config.PolicyDefinition {
+ pd := config.PolicyDefinition{
+ Name: defName,
+ Statements: config.Statements{
+ StatementList: stmt,
+ },
+ }
+ return pd
+}
+
+func createRoutingPolicy(ds config.DefinedSets, pd ...config.PolicyDefinition) config.RoutingPolicy {
+ pl := config.RoutingPolicy{
+ DefinedSets: ds,
+ PolicyDefinitions: config.PolicyDefinitions{
+ PolicyDefinitionList: pd,
+ },
+ }
+ return pl
+}
+
+func createPrefixSet(name string, prefix string, maskLength string) config.PrefixSet {
+ ps := config.PrefixSet{
+ PrefixSetName: name,
+ PrefixList: []config.Prefix{
+ config.Prefix{
+ IpPrefix: prefix,
+ MasklengthRange: maskLength,
+ }},
+ }
+ return ps
+}
+
+func createNeighborSet(name string, addr string) config.NeighborSet {
+ ns := config.NeighborSet{
+ NeighborSetName: name,
+ NeighborInfoList: []config.NeighborInfo{
+ config.NeighborInfo{
+ Address: net.ParseIP(addr),
+ }},
+ }
+ return ns
+}