summaryrefslogtreecommitdiffhomepage
path: root/policy/policy.go
diff options
context:
space:
mode:
authorHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-05-19 19:41:40 +0900
committerHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-05-19 20:14:43 +0900
commitb549c670b1fa749bd047e649d77091221d348c47 (patch)
tree160935a939391fe719817f3e9eb94f2c202368c4 /policy/policy.go
parentf91a3a61b48fb7a3aad6aac492d487fb72b32a34 (diff)
policy: support community condition
Diffstat (limited to 'policy/policy.go')
-rw-r--r--policy/policy.go174
1 files changed, 174 insertions, 0 deletions
diff --git a/policy/policy.go b/policy/policy.go
index b701bd4a..977116fd 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -95,6 +95,13 @@ func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
conditions = append(conditions, asc)
}
+ // CommunityCondition
+ communitySetName := statement.Conditions.BgpConditions.MatchCommunitySet
+ cc := NewCommunityCondition(communitySetName, ds.BgpDefinedSets.CommunitySetList)
+ if cc != nil {
+ conditions = append(conditions, cc)
+ }
+
action := &RoutingActions{
AcceptRoute: false,
}
@@ -452,6 +459,173 @@ func (c *AsPathCondition) evaluate(path table.Path) bool {
return false
}
+type CommunityCondition struct {
+ DefaultCondition
+ CommunityList []*CommunityElement
+}
+
+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(communitySetName string, defAsPathSetList []config.CommunitySet) *CommunityCondition {
+
+ // check format
+ 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 + ")$")
+
+ communityList := make([]*CommunityElement, 0)
+ for _, asPathSet := range defAsPathSetList {
+ if asPathSet.CommunitySetName == communitySetName {
+ for _, as := range asPathSet.CommunityMembers {
+
+ e := &CommunityElement{
+ isRegExp: false,
+ }
+
+ if regUint.MatchString(as) {
+ // specified by Uint
+ community, err := strconv.ParseUint(as, 10, 32)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Community Condition",
+ }).Error("failed to parse the community value.")
+ return nil
+ }
+
+ e.community = uint32(community)
+ e.communityStr = as
+
+ } else if regString.MatchString(as) {
+ // specified by string containing ":"
+ group := regString.FindStringSubmatch(as)
+ 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.")
+ return nil
+ }
+ e.community = uint32(asn<<16 | val)
+ e.communityStr = as
+
+ } else if regWellKnown.MatchString(as) {
+ // specified by well known community name
+ e.communityStr = as
+ switch as {
+ case COMMUNITY_INTERNET:
+ e.community = COMMUNITY_INTERNET_VAL
+ case COMMUNITY_NO_EXPORT:
+ e.community = COMMUNITY_NO_EXPORT_VAL
+ case COMMUNITY_NO_ADVERTISE:
+ e.community = COMMUNITY_NO_ADVERTISE_VAL
+ case COMMUNITY_NO_EXPORT_SUBCONFED:
+ e.community = COMMUNITY_NO_EXPORT_SUBCONFED_VAL
+ }
+
+ } else {
+ // specified by regular expression
+ e.isRegExp = true
+ e.communityStr = as
+ reg, err := regexp.Compile(as)
+ 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,
+ }
+ return c
+ }
+ }
+ return nil
+}
+
+// compare community in the message's attribute with
+// the one in the condition.
+func (c *CommunityCondition) evaluate(path table.Path) bool {
+
+ communities := path.GetCommunities()
+
+ if len(communities) == 0 {
+ return false
+ }
+
+ // create community string in advance.
+ strCommunities := make([]string, len(communities))
+ for i, c := range communities {
+ upper := strconv.FormatUint(uint64(c&0xFFFF0000>>16), 10)
+ lower := strconv.FormatUint(uint64(c&0x0000FFFF), 10)
+ strCommunities[i] = upper + ":" + lower
+ }
+
+ matched := false
+ idx := -1
+ for _, member := range c.CommunityList {
+ if member.isRegExp {
+ for i, c := range strCommunities {
+ if member.communityRegExp.MatchString(c) {
+ matched = true
+ idx = i
+ break
+ }
+ }
+ } else {
+ for i, c := range communities {
+ if c == member.community {
+ matched = true
+ idx = i
+ break
+ }
+ }
+ }
+
+ if matched {
+ log.Debugf("community matched : community=%s)", strCommunities[idx])
+ return true
+ }
+ }
+ return false
+}
+
type Actions interface {
apply(table.Path) table.Path
}