diff options
author | Naoto Hanaue <hanaue.naoto@po.ntts.co.jp> | 2015-06-23 17:13:45 +0900 |
---|---|---|
committer | Naoto Hanaue <hanaue.naoto@po.ntts.co.jp> | 2015-06-26 13:37:52 +0900 |
commit | b3bd568b8dd4a5536428a1bc9a3612b0f1315a39 (patch) | |
tree | dbca40cf4a409d189a60e6c6ad8944ae5aa07b50 | |
parent | 69b36e90ba70131bf67127968e6bb8fa80460161 (diff) |
policy: support med action
-rw-r--r-- | policy/policy.go | 103 | ||||
-rw-r--r-- | table/path.go | 37 |
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) { |