summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNaoto Hanaue <hanaue.naoto@po.ntts.co.jp>2015-06-23 17:13:45 +0900
committerNaoto Hanaue <hanaue.naoto@po.ntts.co.jp>2015-06-26 13:37:52 +0900
commitb3bd568b8dd4a5536428a1bc9a3612b0f1315a39 (patch)
treedbca40cf4a409d189a60e6c6ad8944ae5aa07b50
parent69b36e90ba70131bf67127968e6bb8fa80460161 (diff)
policy: support med action
-rw-r--r--policy/policy.go103
-rw-r--r--table/path.go37
2 files changed, 139 insertions, 1 deletions
diff --git a/policy/policy.go b/policy/policy.go
index 942aa70f..4f56fab6 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -105,13 +105,19 @@ func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy {
// routeing action
ra := NewRoutingAction(statement.Actions)
- // modification action
+ // Community action
mda := make([]Action, 0)
com := NewCommunityAction(statement.Actions.BgpActions.SetCommunity)
if com != nil {
mda = append(mda, com)
}
+ // Med Action
+ med := NewMedAction(statement.Actions.BgpActions.SetMed)
+ if med != nil {
+ mda = append(mda, med)
+ }
+
s := &Statement{
Name: statement.Name,
Conditions: conditions,
@@ -783,6 +789,101 @@ func (a *CommunityAction) apply(path table.Path) table.Path {
return path
}
+type MedAction struct {
+ DefaultAction
+ Value uint32
+ action ActionType
+}
+
+const (
+ MED_ACTION_NONE ActionType = iota
+ MED_ACTION_ADD
+ MED_ACTION_SUB
+// MED_ACTION_IGP
+)
+
+//const (
+// MED_IGP string = "IGP"
+//)
+
+// NewMedAction creates MedAction object.
+// If it cannot parse med string, then return nil.
+// Similarly, if option string is invalid, return nil.
+func NewMedAction(med config.BgpSetMedType) *MedAction {
+
+ m := &MedAction{}
+ matched, value, action := getMedValue(fmt.Sprintf("%v", 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 or well known med name,
+// it returns false and 0 and MED_ACTION_NONE.
+func getMedValue(medStr string) (bool, uint32, ActionType) {
+ regUint, _ := regexp.Compile("^([0-9]+)$")
+ regUintAc, _ := regexp.Compile("^(\\+|\\-)([0-9]+)$")
+// regIGP, _ := regexp.Compile("^(IGP)$")
+ if regUint.MatchString(medStr) {
+ val, err := strconv.ParseUint(medStr, 10, 32)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Error("failed to parser as number or med value.")
+ }
+ return true, uint32(val), MED_ACTION_NONE
+ }
+ if regUintAc.MatchString(medStr) {
+ group := regUintAc.FindStringSubmatch(medStr)
+ action := MED_ACTION_ADD
+ if group[1] == "-" {
+ action = MED_ACTION_SUB
+ }
+ val, err := strconv.ParseUint(group[2], 10, 32)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Error("failed to parser as number or med value.")
+ }
+ return true, uint32(val), action
+ }
+// if regIGP.MatchString(medStr) {
+// return true, uint32(0), MED_IGP
+// }
+ return false, uint32(0), MED_ACTION_NONE
+}
+
+func (a *MedAction) apply(path table.Path) table.Path {
+
+ var err error
+ switch a.action {
+ case MED_ACTION_NONE:
+ err = path.SetMed(a.Value, true, false)
+ case MED_ACTION_ADD:
+ err = path.SetMed(a.Value, false, false)
+ case MED_ACTION_SUB:
+ err = path.SetMed(a.Value, false, true)
+ }
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Policy",
+ "Type": "Med Action",
+ }).Error(err)
+ }
+
+ return path
+}
+
type Prefix struct {
Address net.IP
AddressFamily bgp.RouteFamily
diff --git a/table/path.go b/table/path.go
index c095ab24..a82c5e59 100644
--- a/table/path.go
+++ b/table/path.go
@@ -25,6 +25,7 @@ import (
"net"
"reflect"
"time"
+ "math"
)
type Path interface {
@@ -40,6 +41,7 @@ type Path interface {
SetCommunities([]uint32, bool)
RemoveCommunities([]uint32) int
ClearCommunities()
+ SetMed(uint32, bool, bool) error
setSource(source *PeerInfo)
GetSource() *PeerInfo
GetSourceAs() uint32
@@ -479,6 +481,41 @@ func (pd *PathDefault) ClearCommunities() {
}
}
+// SetMed replace, add or subtraction med with new ones.
+func (pd *PathDefault) SetMed(med uint32, doReplace bool, doSubstruction bool) error {
+ newMed := &bgp.PathAttributeMultiExitDisc{}
+ idx, attr := pd.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
+ if attr != nil{
+ m := attr.(*bgp.PathAttributeMultiExitDisc)
+ if doReplace {
+ newMed = bgp.NewPathAttributeMultiExitDisc(med)
+ } else {
+ if doSubstruction {
+ if m.Value - med < 0 {
+ return fmt.Errorf("med value invalid. the underflow threshold")
+ }
+ newMed = bgp.NewPathAttributeMultiExitDisc(m.Value - med)
+ } else {
+ if m.Value + med > math.MaxUint32 {
+ return fmt.Errorf("med value invalid. the overflow threshold")
+ }
+ newMed = bgp.NewPathAttributeMultiExitDisc(m.Value + med)
+ }
+ }
+ pd.pathAttrs[idx] = newMed
+ } else {
+ if doReplace {
+ newMed = bgp.NewPathAttributeMultiExitDisc(med)
+ } else {
+ if !doSubstruction {
+ newMed = bgp.NewPathAttributeMultiExitDisc(med)
+ }
+ }
+ pd.pathAttrs[idx] = newMed
+ }
+ return nil
+}
+
// create Path object based on route family
func CreatePath(source *PeerInfo, nlri bgp.AddrPrefixInterface, attrs []bgp.PathAttributeInterface, isWithdraw bool, now time.Time) (Path, error) {