summaryrefslogtreecommitdiffhomepage
path: root/table
diff options
context:
space:
mode:
Diffstat (limited to 'table')
-rw-r--r--table/path.go22
-rw-r--r--table/policy.go259
-rw-r--r--table/policy_test.go93
3 files changed, 355 insertions, 19 deletions
diff --git a/table/path.go b/table/path.go
index f8058730..81d76ddf 100644
--- a/table/path.go
+++ b/table/path.go
@@ -762,6 +762,28 @@ func (path *Path) SetExtCommunities(exts []bgp.ExtendedCommunityInterface, doRep
}
}
+func (path *Path) GetLargeCommunities() []*bgp.LargeCommunity {
+ if a := path.getPathAttr(bgp.BGP_ATTR_TYPE_LARGE_COMMUNITY); a != nil {
+ v := a.(*bgp.PathAttributeLargeCommunities).Values
+ ret := make([]*bgp.LargeCommunity, 0, len(v))
+ for _, c := range v {
+ ret = append(ret, c)
+ }
+ return ret
+ }
+ return nil
+}
+
+func (path *Path) SetLargeCommunities(cs []*bgp.LargeCommunity, doReplace bool) {
+ a := path.getPathAttr(bgp.BGP_ATTR_TYPE_LARGE_COMMUNITY)
+ if a == nil || doReplace {
+ path.setPathAttr(bgp.NewPathAttributeLargeCommunities(cs))
+ } else {
+ l := a.(*bgp.PathAttributeLargeCommunities).Values
+ path.setPathAttr(bgp.NewPathAttributeLargeCommunities(append(l, cs...)))
+ }
+}
+
func (path *Path) GetMed() (uint32, error) {
attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
if attr == nil {
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())
}
diff --git a/table/policy_test.go b/table/policy_test.go
index cfafb1ed..58b944e2 100644
--- a/table/policy_test.go
+++ b/table/policy_test.go
@@ -29,12 +29,7 @@ import (
"time"
)
-func init() {
- log.SetLevel(log.DebugLevel)
-}
-
func TestPrefixCalcurateNoRange(t *testing.T) {
- log.SetLevel(log.DebugLevel)
// create path
peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
origin := bgp.NewPathAttributeOrigin(0)
@@ -125,7 +120,6 @@ func TestPrefixCalcurateLengthRange(t *testing.T) {
}
func TestPrefixCalcurateNoRangeIPv6(t *testing.T) {
- log.SetLevel(log.DebugLevel)
// create path
peer := &PeerInfo{AS: 65001, Address: net.ParseIP("2001::192:168:50:1")}
origin := bgp.NewPathAttributeOrigin(0)
@@ -1415,8 +1409,6 @@ func TestAs4PathConditionEvaluateMixedWith2byteAS(t *testing.T) {
func TestCommunityConditionEvaluate(t *testing.T) {
- log.SetLevel(log.DebugLevel)
-
// setup
// create path
peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
@@ -1681,7 +1673,6 @@ func TestPolicyMatchAndAddCommunities(t *testing.T) {
pType, newPath := p.Apply(path, nil)
assert.Equal(t, ROUTE_TYPE_ACCEPT, pType)
assert.NotEqual(t, nil, newPath)
- log.Debug(newPath)
assert.Equal(t, []uint32{stringToCommunityValue(community)}, newPath.GetCommunities())
}
@@ -1914,8 +1905,6 @@ func TestPolicyMatchAndClearCommunities(t *testing.T) {
func TestExtCommunityConditionEvaluate(t *testing.T) {
- log.SetLevel(log.DebugLevel)
-
// setup
// create path
peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")}
@@ -2097,8 +2086,6 @@ func TestExtCommunityConditionEvaluate(t *testing.T) {
func TestExtCommunityConditionEvaluateWithOtherCondition(t *testing.T) {
- log.SetLevel(log.DebugLevel)
-
// setup
// create path
peer := &PeerInfo{AS: 65001, Address: net.ParseIP("10.2.1.1")}
@@ -2871,5 +2858,85 @@ func TestPrefixSetMatch(t *testing.T) {
path = NewPath(nil, bgp.NewIPAddrPrefix(6, "0.0.0.0"), false, []bgp.PathAttributeInterface{}, time.Now(), false)
assert.False(t, m.Evaluate(path, nil))
+}
+
+func TestLargeCommunityMatchAction(t *testing.T) {
+ coms := []*bgp.LargeCommunity{
+ &bgp.LargeCommunity{100, 100, 100},
+ &bgp.LargeCommunity{100, 200, 200},
+ }
+ p := NewPath(nil, nil, false, []bgp.PathAttributeInterface{bgp.NewPathAttributeLargeCommunities(coms)}, time.Time{}, false)
+
+ c := config.LargeCommunitySet{
+ LargeCommunitySetName: "l0",
+ LargeCommunityList: []string{
+ "100:100:100",
+ "100:300:100",
+ },
+ }
+
+ set, err := NewLargeCommunitySet(c)
+ assert.Equal(t, err, nil)
+
+ m, err := NewLargeCommunityCondition(config.MatchLargeCommunitySet{
+ LargeCommunitySet: "l0",
+ })
+ assert.Equal(t, err, nil)
+ m.set = set
+
+ assert.Equal(t, m.Evaluate(p, nil), true)
+
+ a, err := NewLargeCommunityAction(config.SetLargeCommunity{
+ config.SetLargeCommunityMethod{
+ []string{"100:100:100"},
+ },
+ config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE,
+ })
+ assert.Equal(t, err, nil)
+ p = a.Apply(p, nil)
+
+ assert.Equal(t, m.Evaluate(p, nil), false)
+
+ a, err = NewLargeCommunityAction(config.SetLargeCommunity{
+ config.SetLargeCommunityMethod{
+ []string{
+ "100:300:100",
+ "200:100:100",
+ },
+ },
+ config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD,
+ })
+ assert.Equal(t, err, nil)
+ p = a.Apply(p, nil)
+
+ assert.Equal(t, m.Evaluate(p, nil), true)
+
+ a, err = NewLargeCommunityAction(config.SetLargeCommunity{
+ config.SetLargeCommunityMethod{
+ []string{"^100:"},
+ },
+ config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE,
+ })
+ assert.Equal(t, err, nil)
+ p = a.Apply(p, nil)
+
+ assert.Equal(t, m.Evaluate(p, nil), false)
+
+ c = config.LargeCommunitySet{
+ LargeCommunitySetName: "l1",
+ LargeCommunityList: []string{
+ "200:",
+ },
+ }
+
+ set, err = NewLargeCommunitySet(c)
+ assert.Equal(t, err, nil)
+
+ m, err = NewLargeCommunityCondition(config.MatchLargeCommunitySet{
+ LargeCommunitySet: "l1",
+ })
+ assert.Equal(t, err, nil)
+ m.set = set
+ assert.Equal(t, m.Evaluate(p, nil), true)
}