summaryrefslogtreecommitdiffhomepage
path: root/policy/policy.go
diff options
context:
space:
mode:
Diffstat (limited to 'policy/policy.go')
-rw-r--r--policy/policy.go274
1 files changed, 274 insertions, 0 deletions
diff --git a/policy/policy.go b/policy/policy.go
new file mode 100644
index 00000000..9bb4bc8c
--- /dev/null
+++ b/policy/policy.go
@@ -0,0 +1,274 @@
+// 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 policy
+
+import (
+ "fmt"
+ log "github.com/Sirupsen/logrus"
+ "github.com/osrg/gobgp/config"
+ "github.com/osrg/gobgp/packet"
+ "github.com/osrg/gobgp/table"
+ "net"
+ "strconv"
+ "strings"
+)
+
+type RouteType int
+
+const (
+ ROUTE_TYPE_NONE = iota
+ ROUTE_TYPE_ACCEPT
+ ROUTE_TYPE_REJECT
+)
+
+type MaskLengthRangeType int
+
+const (
+ MASK_LENGTH_RANGE_MIN = iota
+ MASK_LENGTH_RANGE_MAX
+)
+
+type Policy struct {
+ Name string
+ Statements []Statement
+}
+
+func NewPolicy(name string, pd config.PolicyDefinition, cdf config.DefinedSets) *Policy {
+ cst := pd.StatementList
+ st := make([]Statement, 0)
+ p := &Policy{
+ Name: name,
+ Statements: st,
+ }
+ for _, cs := range cst {
+ pName := cs.Conditions.MatchPrefixSet
+ npl := make([]Prefix, 0)
+ for _, psl := range cdf.PrefixSetList {
+ if psl.PrefixSetName == pName {
+ for _, ps := range psl.PrefixList {
+ npl = append(npl, NewPrefix(ps.Address, ps.Masklength, ps.MasklengthRange))
+ }
+ }
+ }
+ nName := cs.Conditions.MatchNeighborSet
+ nnl := make([]net.IP, 0)
+ for _, nsl := range cdf.NeighborSetList {
+ if nsl.NeighborSetName == nName {
+ for _, nl := range nsl.NeighborInfoList {
+ nnl = append(nnl, nl.Address)
+ }
+ }
+ }
+ con := Conditions{
+ PrefixList: npl,
+ NeighborList: nnl,
+ }
+ act := Actions{
+ AcceptRoute: cs.Actions.AcceptRoute,
+ RejectRoute: cs.Actions.RejectRoute,
+ }
+ s := Statement{
+ Name: cs.Name,
+ Conditions: con,
+ Actions: act,
+ }
+ st = append(st, s)
+ }
+ p.Statements = st
+ return p
+}
+
+type Statement struct {
+ Name string
+ Conditions Conditions
+ Actions Actions
+}
+
+type Conditions struct {
+ //CallPolicy string
+ PrefixList []Prefix
+ NeighborList []net.IP
+}
+
+type Actions struct {
+ AcceptRoute bool
+ RejectRoute bool
+}
+
+type Prefix struct {
+ Address net.IP
+ Masklength uint8
+ MasklengthRange map[MaskLengthRangeType]uint8
+}
+
+func NewPrefix(addr net.IP, maskLen uint8, maskRange string) Prefix {
+ mlr := make(map[MaskLengthRangeType]uint8)
+ p := Prefix{
+ Address: addr,
+ Masklength: maskLen,
+ MasklengthRange: make(map[MaskLengthRangeType]uint8),
+ }
+ idx := strings.Index(maskRange, "..")
+ if idx == -1 {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Address": addr,
+ "Masklength": maskLen,
+ }).Warn("mask length range of condition is invalid format")
+ return p
+ }
+ if idx != 0 {
+ min, e := strconv.ParseUint(maskRange[:idx], 10, 8)
+ if e != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Error": e,
+ }).Error("failed to parse the min length of mask length range")
+ return p
+ }
+ mlr[MASK_LENGTH_RANGE_MIN] = uint8(min)
+ }
+ if idx != len(maskRange)-1 {
+ max, e := strconv.ParseUint(maskRange[idx+2:], 10, 8)
+ if e != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Error": e,
+ }).Error("failed to parse the max length of mask length range")
+ return p
+ }
+ mlr[MASK_LENGTH_RANGE_MAX] = uint8(max)
+ }
+ p.MasklengthRange = mlr
+ return p
+}
+
+//compare path and condition of policy
+//and, subsequent comparison skip if that matches the conditions.
+func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) {
+ for _, statement := range p.Statements {
+ matchPrefix := false
+ matchNeighbor := false
+ if len(statement.Conditions.PrefixList) <= 0 && len(statement.Conditions.NeighborList) <= 0 {
+ return false, ROUTE_TYPE_NONE, nil
+ } else if len(statement.Conditions.PrefixList) <= 0 && len(statement.Conditions.NeighborList) > 0 {
+ matchPrefix = true
+ matchNeighbor = statement.compareNeighbor(path)
+ } else if len(statement.Conditions.NeighborList) <= 0 && len(statement.Conditions.PrefixList) > 0 {
+ matchPrefix = statement.comparePrefix(path)
+ matchNeighbor = true
+ } else {
+ matchPrefix = statement.comparePrefix(path)
+ matchNeighbor = statement.compareNeighbor(path)
+ }
+ an := statement.Actions
+
+ //if match the one of the prefix list and match to any of tye neighbor list,
+ //determines that matches the conditions of the statement
+ if matchPrefix && matchNeighbor {
+ if an.AcceptRoute {
+ // accept the path
+ // and return the path updated in acction definition
+ // TODO update path using acction definition.
+ // implementation waiting for yang.
+ newPath := path
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "ROUTE_ACCEPT",
+ "OldPath": path,
+ "NewPath": newPath,
+ }).Debug("Apply policy to path")
+ return true, ROUTE_TYPE_ACCEPT, newPath
+
+ } else {
+ // reject the path
+ // and return the path updated in acction definition
+ // TODO update path using acction definition.
+ // implementation waiting for yang.
+ newPath := path
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "ROUTE_REJECT",
+ "OldPath": path,
+ "NewPath": newPath,
+ }).Debug("Apply policy to path")
+ return true, ROUTE_TYPE_REJECT, nil
+ }
+ }
+ }
+ return false, ROUTE_TYPE_NONE, nil
+}
+
+//compare prefix of condition policy and nlri of path
+//and, subsequent comparison skip if that matches the conditions.
+func (s *Statement) comparePrefix(path table.Path) bool {
+ for _, cp := range s.Conditions.PrefixList {
+ if IpPrefixCalcurate(path, cp) {
+ return true
+ }
+ }
+ return false
+}
+
+//compare neighbor ipaddress of condition policy and source of path
+//and, subsequent comparison skip if that matches the conditions.
+func (s *Statement) compareNeighbor(path table.Path) bool {
+ for _, neighbor := range s.Conditions.NeighborList {
+ cAddr := neighbor
+ pAddr := path.GetSource().Address
+ if pAddr.Equal(cAddr) {
+ return true
+ }
+
+ }
+ return false
+}
+
+func IpPrefixCalcurate(path table.Path, cPrefix Prefix) bool {
+ pAddr := path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Prefix
+ pMaskLen := path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Length
+ cp := fmt.Sprintf("%s/%d", cPrefix.Address, cPrefix.Masklength)
+ rMin, okMin := cPrefix.MasklengthRange[MASK_LENGTH_RANGE_MIN]
+ rMax, okMax := cPrefix.MasklengthRange[MASK_LENGTH_RANGE_MAX]
+
+ //TODO add conditional processing by RouteFamily.
+
+ if !okMin && !okMax {
+ if pAddr.Equal(cPrefix.Address) && pMaskLen == cPrefix.Masklength {
+ return true
+ } else {
+ return false
+ }
+ } else if !okMin {
+ rMin = uint8(0)
+ } else if !okMax {
+ rMax = uint8(32)
+ }
+
+ _, ipNet, e := net.ParseCIDR(cp)
+ if e != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Prefix": ipNet,
+ "Error": e,
+ }).Error("failed to parse the prefix of condition")
+ return false
+ }
+ if ipNet.Contains(pAddr) && (rMin <= pMaskLen && pMaskLen <= rMax) {
+ return true
+ }
+ return false
+}