diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-05-19 19:41:40 +0900 |
---|---|---|
committer | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-05-19 20:14:43 +0900 |
commit | b549c670b1fa749bd047e649d77091221d348c47 (patch) | |
tree | 160935a939391fe719817f3e9eb94f2c202368c4 /policy/policy.go | |
parent | f91a3a61b48fb7a3aad6aac492d487fb72b32a34 (diff) |
policy: support community condition
Diffstat (limited to 'policy/policy.go')
-rw-r--r-- | policy/policy.go | 174 |
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 } |