summaryrefslogtreecommitdiffhomepage
path: root/table/policy.go
diff options
context:
space:
mode:
authorWataru Ishida <ishida.wataru@lab.ntt.co.jp>2016-10-06 05:38:00 +0000
committerWataru Ishida <ishida.wataru@lab.ntt.co.jp>2016-10-10 05:18:17 +0000
commitd46da74d4fba3fe169d0c4f05b0e657ec95f5336 (patch)
tree94b962ebdf526bc4f84e5aef5ce18707dbfd933f /table/policy.go
parent2cd0de0139cb47edac0c418f4efd4e5c6d185f63 (diff)
policy: support large-community match/action
close #1133 Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'table/policy.go')
-rw-r--r--table/policy.go259
1 files changed, 253 insertions, 6 deletions
diff --git a/table/policy.go b/table/policy.go
index 2122e508..a90d7fe3 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -44,6 +44,7 @@ const (
DEFINED_TYPE_AS_PATH
DEFINED_TYPE_COMMUNITY
DEFINED_TYPE_EXT_COMMUNITY
+ DEFINED_TYPE_LARGE_COMMUNITY
)
type RouteType int
@@ -126,6 +127,7 @@ const (
CONDITION_AS_PATH_LENGTH
CONDITION_RPKI
CONDITION_ROUTE_TYPE
+ CONDITION_LARGE_COMMUNITY
)
type ActionType int
@@ -138,6 +140,7 @@ const (
ACTION_AS_PATH_PREPEND
ACTION_NEXTHOP
ACTION_LOCAL_PREF
+ ACTION_LARGE_COMMUNITY
)
func NewMatchOption(c interface{}) (MatchOption, error) {
@@ -733,6 +736,8 @@ func (lhs *regExpSet) Append(arg DefinedSet) error {
list = arg.(*CommunitySet).list
case DEFINED_TYPE_EXT_COMMUNITY:
list = arg.(*ExtCommunitySet).list
+ case DEFINED_TYPE_LARGE_COMMUNITY:
+ list = arg.(*LargeCommunitySet).list
default:
return fmt.Errorf("invalid defined-set type: %d", lhs.Type())
}
@@ -752,6 +757,8 @@ func (lhs *regExpSet) Remove(arg DefinedSet) error {
list = arg.(*CommunitySet).list
case DEFINED_TYPE_EXT_COMMUNITY:
list = arg.(*ExtCommunitySet).list
+ case DEFINED_TYPE_LARGE_COMMUNITY:
+ list = arg.(*LargeCommunitySet).list
default:
return fmt.Errorf("invalid defined-set type: %d", lhs.Type())
}
@@ -773,11 +780,16 @@ func (lhs *regExpSet) Remove(arg DefinedSet) error {
}
func (lhs *regExpSet) Replace(arg DefinedSet) error {
- rhs, ok := arg.(*regExpSet)
- if !ok {
+ switch c := arg.(type) {
+ case *CommunitySet:
+ lhs.list = c.list
+ case *ExtCommunitySet:
+ lhs.list = c.list
+ case *LargeCommunitySet:
+ lhs.list = c.list
+ default:
return fmt.Errorf("type cast failed")
}
- lhs.list = rhs.list
return nil
}
@@ -966,6 +978,57 @@ func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) {
}, nil
}
+type LargeCommunitySet struct {
+ regExpSet
+}
+
+func (s *LargeCommunitySet) ToConfig() *config.LargeCommunitySet {
+ list := make([]string, 0, len(s.list))
+ for _, exp := range s.list {
+ list = append(list, exp.String())
+ }
+ return &config.LargeCommunitySet{
+ LargeCommunitySetName: s.name,
+ LargeCommunityList: list,
+ }
+}
+
+func ParseLargeCommunityRegexp(arg string) (*regexp.Regexp, error) {
+ if regexp.MustCompile("\\d+:\\d+:\\d+").MatchString(arg) {
+ return regexp.MustCompile(fmt.Sprintf("^%s$", arg)), nil
+ }
+ exp, err := regexp.Compile(arg)
+ if err != nil {
+ return nil, fmt.Errorf("invalid large-community format: %s", arg)
+ }
+ return exp, nil
+}
+
+func NewLargeCommunitySet(c config.LargeCommunitySet) (*LargeCommunitySet, error) {
+ name := c.LargeCommunitySetName
+ if name == "" {
+ if len(c.LargeCommunityList) == 0 {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("empty large community set name")
+ }
+ list := make([]*regexp.Regexp, 0, len(c.LargeCommunityList))
+ for _, x := range c.LargeCommunityList {
+ exp, err := ParseLargeCommunityRegexp(x)
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, exp)
+ }
+ return &LargeCommunitySet{
+ regExpSet: regExpSet{
+ typ: DEFINED_TYPE_LARGE_COMMUNITY,
+ name: name,
+ list: list,
+ },
+ }, nil
+}
+
type Condition interface {
Name() string
Type() ConditionType
@@ -1310,6 +1373,64 @@ func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondi
}, nil
}
+type LargeCommunityCondition struct {
+ name string
+ set *LargeCommunitySet
+ option MatchOption
+}
+
+func (c *LargeCommunityCondition) Type() ConditionType {
+ return CONDITION_LARGE_COMMUNITY
+}
+
+func (c *LargeCommunityCondition) Set() DefinedSet {
+ return c.set
+}
+
+func (c *LargeCommunityCondition) Option() MatchOption {
+ return c.option
+}
+
+func (c *LargeCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
+ result := false
+ cs := path.GetLargeCommunities()
+ for _, x := range c.set.list {
+ result = false
+ for _, y := range cs {
+ if x.MatchString(y.String()) {
+ result = true
+ break
+ }
+ }
+ if c.option == MATCH_OPTION_ALL && !result {
+ break
+ }
+ if (c.option == MATCH_OPTION_ANY || c.option == MATCH_OPTION_INVERT) && result {
+ break
+ }
+ }
+ if c.option == MATCH_OPTION_INVERT {
+ result = !result
+ }
+ return result
+}
+
+func (c *LargeCommunityCondition) Name() string { return c.name }
+
+func NewLargeCommunityCondition(c config.MatchLargeCommunitySet) (*LargeCommunityCondition, error) {
+ if c.LargeCommunitySet == "" {
+ return nil, nil
+ }
+ o, err := NewMatchOption(c.MatchSetOptions)
+ if err != nil {
+ return nil, err
+ }
+ return &LargeCommunityCondition{
+ name: c.LargeCommunitySet,
+ option: o,
+ }, nil
+}
+
type AsPathLengthCondition struct {
length uint32
operator AttributeComparison
@@ -1507,6 +1628,25 @@ func RegexpRemoveExtCommunities(path *Path, exps []*regexp.Regexp, subtypes []bg
path.SetExtCommunities(newComms, true)
}
+func RegexpRemoveLargeCommunities(path *Path, exps []*regexp.Regexp) {
+ comms := path.GetLargeCommunities()
+ newComms := make([]*bgp.LargeCommunity, 0, len(comms))
+ for _, comm := range comms {
+ c := comm.String()
+ match := false
+ for _, exp := range exps {
+ if exp.MatchString(c) {
+ match = true
+ break
+ }
+ }
+ if match == false {
+ newComms = append(newComms, comm)
+ }
+ }
+ path.SetLargeCommunities(newComms, true)
+}
+
func (a *CommunityAction) Type() ActionType {
return ACTION_COMMUNITY
}
@@ -1668,6 +1808,80 @@ func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error
}, nil
}
+type LargeCommunityAction struct {
+ action config.BgpSetCommunityOptionType
+ list []*bgp.LargeCommunity
+ removeList []*regexp.Regexp
+}
+
+func (a *LargeCommunityAction) Type() ActionType {
+ return ACTION_LARGE_COMMUNITY
+}
+
+func (a *LargeCommunityAction) Apply(path *Path, _ *PolicyOptions) *Path {
+ switch a.action {
+ case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD:
+ path.SetLargeCommunities(a.list, false)
+ case config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE:
+ RegexpRemoveLargeCommunities(path, a.removeList)
+ case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE:
+ path.SetLargeCommunities(a.list, true)
+ }
+ return path
+}
+
+func (a *LargeCommunityAction) ToConfig() *config.SetLargeCommunity {
+ cs := make([]string, 0, len(a.list)+len(a.removeList))
+ for _, comm := range a.list {
+ cs = append(cs, comm.String())
+ }
+ for _, exp := range a.removeList {
+ cs = append(cs, exp.String())
+ }
+ return &config.SetLargeCommunity{
+ SetLargeCommunityMethod: config.SetLargeCommunityMethod{CommunitiesList: cs},
+ Options: config.BgpSetCommunityOptionType(a.action),
+ }
+}
+
+func NewLargeCommunityAction(c config.SetLargeCommunity) (*LargeCommunityAction, error) {
+ a, ok := CommunityOptionValueMap[strings.ToLower(string(c.Options))]
+ if !ok {
+ if len(c.SetLargeCommunityMethod.CommunitiesList) == 0 {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("invalid option name: %s", c.Options)
+ }
+ var list []*bgp.LargeCommunity
+ var removeList []*regexp.Regexp
+ if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
+ removeList = make([]*regexp.Regexp, 0, len(c.SetLargeCommunityMethod.CommunitiesList))
+ } else {
+ list = make([]*bgp.LargeCommunity, 0, len(c.SetLargeCommunityMethod.CommunitiesList))
+ }
+ for _, x := range c.SetLargeCommunityMethod.CommunitiesList {
+ if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE {
+ exp, err := ParseLargeCommunityRegexp(x)
+ if err != nil {
+ return nil, err
+ }
+ removeList = append(removeList, exp)
+ } else {
+ comm, err := bgp.ParseLargeCommunity(x)
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, comm)
+ }
+ }
+ return &LargeCommunityAction{
+ action: a,
+ list: list,
+ removeList: removeList,
+ }, nil
+
+}
+
type MedAction struct {
value int64
action MedActionType
@@ -1943,6 +2157,9 @@ func (s *Statement) ToConfig() *config.Statement {
case *ExtCommunityCondition:
v := c.(*ExtCommunityCondition)
cond.BgpConditions.MatchExtCommunitySet = config.MatchExtCommunitySet{ExtCommunitySet: v.set.Name(), MatchSetOptions: config.IntToMatchSetOptionsTypeMap[int(v.option)]}
+ case *LargeCommunityCondition:
+ v := c.(*LargeCommunityCondition)
+ cond.BgpConditions.MatchLargeCommunitySet = config.MatchLargeCommunitySet{LargeCommunitySet: v.set.Name(), MatchSetOptions: config.IntToMatchSetOptionsTypeMap[int(v.option)]}
case *RpkiValidationCondition:
v := c.(*RpkiValidationCondition)
cond.BgpConditions.RpkiValidationResult = v.result
@@ -1967,6 +2184,8 @@ func (s *Statement) ToConfig() *config.Statement {
act.BgpActions.SetCommunity = *a.(*CommunityAction).ToConfig()
case *ExtCommunityAction:
act.BgpActions.SetExtCommunity = *a.(*ExtCommunityAction).ToConfig()
+ case *LargeCommunityAction:
+ act.BgpActions.SetLargeCommunity = *a.(*LargeCommunityAction).ToConfig()
case *MedAction:
act.BgpActions.SetMed = a.(*MedAction).ToConfig()
case *LocalPrefAction:
@@ -2132,6 +2351,9 @@ func NewStatement(c config.Statement) (*Statement, error) {
func() (Condition, error) {
return NewExtCommunityCondition(c.Conditions.BgpConditions.MatchExtCommunitySet)
},
+ func() (Condition, error) {
+ return NewLargeCommunityCondition(c.Conditions.BgpConditions.MatchLargeCommunitySet)
+ },
}
cs = make([]Condition, 0, len(cfs))
for _, f := range cfs {
@@ -2155,6 +2377,9 @@ func NewStatement(c config.Statement) (*Statement, error) {
return NewExtCommunityAction(c.Actions.BgpActions.SetExtCommunity)
},
func() (Action, error) {
+ return NewLargeCommunityAction(c.Actions.BgpActions.SetLargeCommunity)
+ },
+ func() (Action, error) {
return NewMedAction(c.Actions.BgpActions.SetMed)
},
func() (Action, error) {
@@ -2478,6 +2703,14 @@ func (r *RoutingPolicy) validateCondition(v Condition) (err error) {
c := v.(*ExtCommunityCondition)
c.set = i.(*ExtCommunitySet)
}
+ case CONDITION_LARGE_COMMUNITY:
+ m := r.definedSetMap[DEFINED_TYPE_LARGE_COMMUNITY]
+ if i, ok := m[v.Name()]; !ok {
+ return fmt.Errorf("not found large-community set %s", v.Name())
+ } else {
+ c := v.(*LargeCommunityCondition)
+ c.set = i.(*LargeCommunitySet)
+ }
case CONDITION_AS_PATH_LENGTH:
case CONDITION_RPKI:
}
@@ -2576,6 +2809,17 @@ func (r *RoutingPolicy) reload(c config.RoutingPolicy) error {
}
dmap[DEFINED_TYPE_EXT_COMMUNITY][y.Name()] = y
}
+ dmap[DEFINED_TYPE_LARGE_COMMUNITY] = make(map[string]DefinedSet)
+ for _, x := range bd.LargeCommunitySets {
+ y, err := NewLargeCommunitySet(x)
+ if err != nil {
+ return err
+ }
+ if y == nil {
+ return fmt.Errorf("empty large-community set")
+ }
+ dmap[DEFINED_TYPE_LARGE_COMMUNITY][y.Name()] = y
+ }
pmap := make(map[string]*Policy)
smap := make(map[string]*Statement)
for _, x := range c.PolicyDefinitions {
@@ -2632,9 +2876,10 @@ func (r *RoutingPolicy) GetDefinedSet(typ DefinedType) (*config.DefinedSets, err
PrefixSets: make([]config.PrefixSet, 0),
NeighborSets: make([]config.NeighborSet, 0),
BgpDefinedSets: config.BgpDefinedSets{
- CommunitySets: make([]config.CommunitySet, 0),
- ExtCommunitySets: make([]config.ExtCommunitySet, 0),
- AsPathSets: make([]config.AsPathSet, 0),
+ CommunitySets: make([]config.CommunitySet, 0),
+ ExtCommunitySets: make([]config.ExtCommunitySet, 0),
+ LargeCommunitySets: make([]config.LargeCommunitySet, 0),
+ AsPathSets: make([]config.AsPathSet, 0),
},
}
for _, s := range set {
@@ -2647,6 +2892,8 @@ func (r *RoutingPolicy) GetDefinedSet(typ DefinedType) (*config.DefinedSets, err
sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *s.(*CommunitySet).ToConfig())
case *ExtCommunitySet:
sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *s.(*ExtCommunitySet).ToConfig())
+ case *LargeCommunitySet:
+ sets.BgpDefinedSets.LargeCommunitySets = append(sets.BgpDefinedSets.LargeCommunitySets, *s.(*LargeCommunitySet).ToConfig())
case *AsPathSet:
sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *s.(*AsPathSet).ToConfig())
}