summaryrefslogtreecommitdiffhomepage
path: root/table/policy.go
diff options
context:
space:
mode:
Diffstat (limited to 'table/policy.go')
-rw-r--r--table/policy.go298
1 files changed, 269 insertions, 29 deletions
diff --git a/table/policy.go b/table/policy.go
index 07b0f046..7ac8a6c3 100644
--- a/table/policy.go
+++ b/table/policy.go
@@ -17,6 +17,7 @@ package table
import (
"bytes"
+ "encoding/json"
"fmt"
"net"
"reflect"
@@ -178,6 +179,18 @@ const (
ATTRIBUTE_LE
)
+func (c AttributeComparison) String() string {
+ switch c {
+ case ATTRIBUTE_EQ:
+ return "="
+ case ATTRIBUTE_GE:
+ return ">="
+ case ATTRIBUTE_LE:
+ return "<="
+ }
+ return "?"
+}
+
const (
ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)"
)
@@ -188,10 +201,29 @@ type DefinedSet interface {
Append(DefinedSet) error
Remove(DefinedSet) error
Replace(DefinedSet) error
+ String() string
+ List() []string
}
type DefinedSetMap map[DefinedType]map[string]DefinedSet
+type DefinedSetList []DefinedSet
+
+func (l DefinedSetList) Len() int {
+ return len(l)
+}
+
+func (l DefinedSetList) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
+
+func (l DefinedSetList) Less(i, j int) bool {
+ if l[i].Type() != l[j].Type() {
+ return l[i].Type() < l[j].Type()
+ }
+ return l[i].Name() < l[j].Name()
+}
+
type Prefix struct {
Prefix *net.IPNet
AddressFamily bgp.RouteFamily
@@ -347,6 +379,18 @@ func (lhs *PrefixSet) Replace(arg DefinedSet) error {
return nil
}
+func (s *PrefixSet) List() []string {
+ var list []string
+ s.tree.Walk(func(s string, v interface{}) bool {
+ ps := v.([]*Prefix)
+ for _, p := range ps {
+ list = append(list, fmt.Sprintf("%s %d..%d", p.Prefix.String(), p.MasklengthRangeMin, p.MasklengthRangeMax))
+ }
+ return false
+ })
+ return list
+}
+
func (s *PrefixSet) ToConfig() *config.PrefixSet {
list := make([]config.Prefix, 0, s.tree.Len())
s.tree.Walk(func(s string, v interface{}) bool {
@@ -362,6 +406,14 @@ func (s *PrefixSet) ToConfig() *config.PrefixSet {
}
}
+func (s *PrefixSet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *PrefixSet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func NewPrefixSetFromApiStruct(name string, prefixes []*Prefix) (*PrefixSet, error) {
if name == "" {
return nil, fmt.Errorf("empty prefix set name")
@@ -465,17 +517,29 @@ func (lhs *NeighborSet) Replace(arg DefinedSet) error {
return nil
}
-func (s *NeighborSet) ToConfig() *config.NeighborSet {
+func (s *NeighborSet) List() []string {
list := make([]string, 0, len(s.list))
for _, n := range s.list {
list = append(list, n.String())
}
+ return list
+}
+
+func (s *NeighborSet) ToConfig() *config.NeighborSet {
return &config.NeighborSet{
NeighborSetName: s.name,
- NeighborInfoList: list,
+ NeighborInfoList: s.List(),
}
}
+func (s *NeighborSet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *NeighborSet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func NewNeighborSetFromApiStruct(name string, list []net.IP) (*NeighborSet, error) {
return &NeighborSet{
name: name,
@@ -667,7 +731,7 @@ func (lhs *AsPathSet) Replace(arg DefinedSet) error {
return nil
}
-func (s *AsPathSet) ToConfig() *config.AsPathSet {
+func (s *AsPathSet) List() []string {
list := make([]string, 0, len(s.list)+len(s.singleList))
for _, exp := range s.singleList {
list = append(list, exp.String())
@@ -675,12 +739,24 @@ func (s *AsPathSet) ToConfig() *config.AsPathSet {
for _, exp := range s.list {
list = append(list, exp.String())
}
+ return list
+}
+
+func (s *AsPathSet) ToConfig() *config.AsPathSet {
return &config.AsPathSet{
AsPathSetName: s.name,
- AsPathList: list,
+ AsPathList: s.List(),
}
}
+func (s *AsPathSet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *AsPathSet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func NewAsPathSet(c config.AsPathSet) (*AsPathSet, error) {
name := c.AsPathSetName
if name == "" {
@@ -797,17 +873,29 @@ type CommunitySet struct {
regExpSet
}
-func (s *CommunitySet) ToConfig() *config.CommunitySet {
+func (s *CommunitySet) List() []string {
list := make([]string, 0, len(s.list))
for _, exp := range s.list {
list = append(list, exp.String())
}
+ return list
+}
+
+func (s *CommunitySet) ToConfig() *config.CommunitySet {
return &config.CommunitySet{
CommunitySetName: s.name,
- CommunityList: list,
+ CommunityList: s.List(),
}
}
+func (s *CommunitySet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *CommunitySet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func ParseCommunity(arg string) (uint32, error) {
i, err := strconv.ParseUint(arg, 10, 32)
if err == nil {
@@ -927,7 +1015,7 @@ type ExtCommunitySet struct {
subtypeList []bgp.ExtendedCommunityAttrSubType
}
-func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
+func (s *ExtCommunitySet) List() []string {
list := make([]string, 0, len(s.list))
f := func(idx int, arg string) string {
switch s.subtypeList[idx] {
@@ -944,12 +1032,24 @@ func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
for idx, exp := range s.list {
list = append(list, f(idx, exp.String()))
}
+ return list
+}
+
+func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet {
return &config.ExtCommunitySet{
ExtCommunitySetName: s.name,
- ExtCommunityList: list,
+ ExtCommunityList: s.List(),
}
}
+func (s *ExtCommunitySet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *ExtCommunitySet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) {
name := c.ExtCommunitySetName
if name == "" {
@@ -982,17 +1082,29 @@ type LargeCommunitySet struct {
regExpSet
}
-func (s *LargeCommunitySet) ToConfig() *config.LargeCommunitySet {
+func (s *LargeCommunitySet) List() []string {
list := make([]string, 0, len(s.list))
for _, exp := range s.list {
list = append(list, exp.String())
}
+ return list
+}
+
+func (s *LargeCommunitySet) ToConfig() *config.LargeCommunitySet {
return &config.LargeCommunitySet{
LargeCommunitySetName: s.name,
- LargeCommunityList: list,
+ LargeCommunityList: s.List(),
}
}
+func (s *LargeCommunitySet) String() string {
+ return strings.Join(s.List(), "\n")
+}
+
+func (s *LargeCommunitySet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
func ParseLargeCommunityRegexp(arg string) (*regexp.Regexp, error) {
if regexp.MustCompile("\\d+:\\d+:\\d+").MatchString(arg) {
return regexp.MustCompile(fmt.Sprintf("^%s$", arg)), nil
@@ -1037,7 +1149,6 @@ type Condition interface {
}
type PrefixCondition struct {
- name string
set *PrefixSet
option MatchOption
}
@@ -1096,7 +1207,7 @@ func (c *PrefixCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return result
}
-func (c *PrefixCondition) Name() string { return c.name }
+func (c *PrefixCondition) Name() string { return c.set.name }
func NewPrefixCondition(c config.MatchPrefixSet) (*PrefixCondition, error) {
if c.PrefixSet == "" {
@@ -1107,13 +1218,14 @@ func NewPrefixCondition(c config.MatchPrefixSet) (*PrefixCondition, error) {
return nil, err
}
return &PrefixCondition{
- name: c.PrefixSet,
+ set: &PrefixSet{
+ name: c.PrefixSet,
+ },
option: o,
}, nil
}
type NeighborCondition struct {
- name string
set *NeighborSet
option MatchOption
}
@@ -1165,7 +1277,7 @@ func (c *NeighborCondition) Evaluate(path *Path, options *PolicyOptions) bool {
return result
}
-func (c *NeighborCondition) Name() string { return c.name }
+func (c *NeighborCondition) Name() string { return c.set.name }
func NewNeighborCondition(c config.MatchNeighborSet) (*NeighborCondition, error) {
if c.NeighborSet == "" {
@@ -1176,13 +1288,14 @@ func NewNeighborCondition(c config.MatchNeighborSet) (*NeighborCondition, error)
return nil, err
}
return &NeighborCondition{
- name: c.NeighborSet,
+ set: &NeighborSet{
+ name: c.NeighborSet,
+ },
option: o,
}, nil
}
type AsPathCondition struct {
- name string
set *AsPathSet
option MatchOption
}
@@ -1236,7 +1349,7 @@ func (c *AsPathCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return true
}
-func (c *AsPathCondition) Name() string { return c.name }
+func (c *AsPathCondition) Name() string { return c.set.name }
func NewAsPathCondition(c config.MatchAsPathSet) (*AsPathCondition, error) {
if c.AsPathSet == "" {
@@ -1247,13 +1360,14 @@ func NewAsPathCondition(c config.MatchAsPathSet) (*AsPathCondition, error) {
return nil, err
}
return &AsPathCondition{
- name: c.AsPathSet,
+ set: &AsPathSet{
+ name: c.AsPathSet,
+ },
option: o,
}, nil
}
type CommunityCondition struct {
- name string
set *CommunitySet
option MatchOption
}
@@ -1294,7 +1408,7 @@ func (c *CommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return result
}
-func (c *CommunityCondition) Name() string { return c.name }
+func (c *CommunityCondition) Name() string { return c.set.name }
func NewCommunityCondition(c config.MatchCommunitySet) (*CommunityCondition, error) {
if c.CommunitySet == "" {
@@ -1305,13 +1419,16 @@ func NewCommunityCondition(c config.MatchCommunitySet) (*CommunityCondition, err
return nil, err
}
return &CommunityCondition{
- name: c.CommunitySet,
+ set: &CommunitySet{
+ regExpSet: regExpSet{
+ name: c.CommunitySet,
+ },
+ },
option: o,
}, nil
}
type ExtCommunityCondition struct {
- name string
set *ExtCommunitySet
option MatchOption
}
@@ -1357,7 +1474,7 @@ func (c *ExtCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return result
}
-func (c *ExtCommunityCondition) Name() string { return c.name }
+func (c *ExtCommunityCondition) Name() string { return c.set.name }
func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondition, error) {
if c.ExtCommunitySet == "" {
@@ -1368,13 +1485,16 @@ func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondi
return nil, err
}
return &ExtCommunityCondition{
- name: c.ExtCommunitySet,
+ set: &ExtCommunitySet{
+ regExpSet: regExpSet{
+ name: c.ExtCommunitySet,
+ },
+ },
option: o,
}, nil
}
type LargeCommunityCondition struct {
- name string
set *LargeCommunitySet
option MatchOption
}
@@ -1415,7 +1535,7 @@ func (c *LargeCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return result
}
-func (c *LargeCommunityCondition) Name() string { return c.name }
+func (c *LargeCommunityCondition) Name() string { return c.set.name }
func NewLargeCommunityCondition(c config.MatchLargeCommunitySet) (*LargeCommunityCondition, error) {
if c.LargeCommunitySet == "" {
@@ -1426,7 +1546,11 @@ func NewLargeCommunityCondition(c config.MatchLargeCommunitySet) (*LargeCommunit
return nil, err
}
return &LargeCommunityCondition{
- name: c.LargeCommunitySet,
+ set: &LargeCommunitySet{
+ regExpSet: regExpSet{
+ name: c.LargeCommunitySet,
+ },
+ },
option: o,
}, nil
}
@@ -1464,6 +1588,10 @@ func (c *AsPathLengthCondition) Set() DefinedSet {
func (c *AsPathLengthCondition) Name() string { return "" }
+func (c *AsPathLengthCondition) String() string {
+ return fmt.Sprintf("%s%d", c.operator, c.length)
+}
+
func NewAsPathLengthCondition(c config.AsPathLength) (*AsPathLengthCondition, error) {
if c.Value == 0 && c.Operator == "" {
return nil, nil
@@ -1500,6 +1628,10 @@ func (c *RpkiValidationCondition) Set() DefinedSet {
func (c *RpkiValidationCondition) Name() string { return "" }
+func (c *RpkiValidationCondition) String() string {
+ return string(c.result)
+}
+
func NewRpkiValidationCondition(c config.RpkiValidationResultType) (*RpkiValidationCondition, error) {
if c == config.RPKI_VALIDATION_RESULT_TYPE_NONE {
return nil, nil
@@ -1535,6 +1667,10 @@ func (c *RouteTypeCondition) Set() DefinedSet {
func (c *RouteTypeCondition) Name() string { return "" }
+func (c *RouteTypeCondition) String() string {
+ return string(c.typ)
+}
+
func NewRouteTypeCondition(c config.RouteType) (*RouteTypeCondition, error) {
if string(c) == "" || c == config.ROUTE_TYPE_NONE {
return nil, nil
@@ -1550,6 +1686,7 @@ func NewRouteTypeCondition(c config.RouteType) (*RouteTypeCondition, error) {
type Action interface {
Type() ActionType
Apply(*Path, *PolicyOptions) *Path
+ String() string
}
type RoutingAction struct {
@@ -1567,6 +1704,14 @@ func (a *RoutingAction) Apply(path *Path, _ *PolicyOptions) *Path {
return nil
}
+func (a *RoutingAction) String() string {
+ action := "reject"
+ if a.AcceptRoute {
+ action = "accept"
+ }
+ return action
+}
+
func NewRoutingAction(c config.RouteDisposition) (*RoutingAction, error) {
if c.AcceptRoute == c.RejectRoute && c.AcceptRoute {
return nil, fmt.Errorf("invalid route disposition")
@@ -1680,6 +1825,17 @@ func (a *CommunityAction) ToConfig() *config.SetCommunity {
}
}
+func (a *CommunityAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
+func (a *CommunityAction) String() string {
+ list := a.ToConfig().SetCommunityMethod.CommunitiesList
+ exp := regexp.MustCompile("[\\^\\$]")
+ l := exp.ReplaceAllString(strings.Join(list, ", "), "")
+ return fmt.Sprintf("%s[%s]", a.action, l)
+}
+
func NewCommunityAction(c config.SetCommunity) (*CommunityAction, error) {
a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)]
if !ok {
@@ -1768,6 +1924,17 @@ func (a *ExtCommunityAction) ToConfig() *config.SetExtCommunity {
}
}
+func (a *ExtCommunityAction) String() string {
+ list := a.ToConfig().SetExtCommunityMethod.CommunitiesList
+ exp := regexp.MustCompile("[\\^\\$]")
+ l := exp.ReplaceAllString(strings.Join(list, ", "), "")
+ return fmt.Sprintf("%s[%s]", a.action, l)
+}
+
+func (a *ExtCommunityAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error) {
a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)]
if !ok {
@@ -1846,6 +2013,17 @@ func (a *LargeCommunityAction) ToConfig() *config.SetLargeCommunity {
}
}
+func (a *LargeCommunityAction) String() string {
+ list := a.ToConfig().SetLargeCommunityMethod.CommunitiesList
+ exp := regexp.MustCompile("[\\^\\$]")
+ l := exp.ReplaceAllString(strings.Join(list, ", "), "")
+ return fmt.Sprintf("%s[%s]", a.action, l)
+}
+
+func (a *LargeCommunityAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
func NewLargeCommunityAction(c config.SetLargeCommunity) (*LargeCommunityAction, error) {
a, ok := CommunityOptionValueMap[strings.ToLower(string(c.Options))]
if !ok {
@@ -1919,6 +2097,14 @@ func (a *MedAction) ToConfig() config.BgpSetMedType {
return config.BgpSetMedType(fmt.Sprintf("%d", a.value))
}
+func (a *MedAction) String() string {
+ return string(a.ToConfig())
+}
+
+func (a *MedAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
func NewMedAction(c config.BgpSetMedType) (*MedAction, error) {
if string(c) == "" {
return nil, nil
@@ -1961,6 +2147,14 @@ func (a *LocalPrefAction) ToConfig() uint32 {
return a.value
}
+func (a *LocalPrefAction) String() string {
+ return fmt.Sprintf("%d", a.value)
+}
+
+func (a *LocalPrefAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
func NewLocalPrefAction(value uint32) (*LocalPrefAction, error) {
if value == 0 {
return nil, nil
@@ -2020,6 +2214,15 @@ func (a *AsPathPrependAction) ToConfig() *config.SetAsPathPrepend {
}
}
+func (a *AsPathPrependAction) String() string {
+ c := a.ToConfig()
+ return fmt.Sprintf("prepend %s %d times", c.As, c.RepeatN)
+}
+
+func (a *AsPathPrependAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
// NewAsPathPrependAction creates AsPathPrependAction object.
// If ASN cannot be parsed, nil will be returned.
func NewAsPathPrependAction(action config.SetAsPathPrepend) (*AsPathPrependAction, error) {
@@ -2071,8 +2274,16 @@ func (a *NexthopAction) ToConfig() config.BgpNextHopType {
return config.BgpNextHopType(a.value.String())
}
+func (a *NexthopAction) String() string {
+ return string(a.ToConfig())
+}
+
+func (a *NexthopAction) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.ToConfig())
+}
+
func NewNexthopAction(c config.BgpNextHopType) (*NexthopAction, error) {
- switch string(c) {
+ switch strings.ToLower(string(c)) {
case "":
return nil, nil
case "self":
@@ -2201,6 +2412,10 @@ func (s *Statement) ToConfig() *config.Statement {
}
}
+func (s *Statement) MarshalJSON() ([]byte, error) {
+ return json.Marshal(s.ToConfig())
+}
+
type opType int
const (
@@ -2483,6 +2698,10 @@ func (lhs *Policy) Replace(rhs *Policy) error {
return nil
}
+func (p *Policy) MarshalJSON() ([]byte, error) {
+ return json.Marshal(p.ToConfig())
+}
+
func NewPolicy(c config.PolicyDefinition) (*Policy, error) {
if c.Name == "" {
return nil, fmt.Errorf("empty policy name")
@@ -2508,6 +2727,20 @@ func NewPolicy(c config.PolicyDefinition) (*Policy, error) {
}, nil
}
+type Policies []*Policy
+
+func (p Policies) Len() int {
+ return len(p)
+}
+
+func (p Policies) Swap(i, j int) {
+ p[i], p[j] = p[j], p[i]
+}
+
+func (p Policies) Less(i, j int) bool {
+ return p[i].Name < p[j].Name
+}
+
type Assignment struct {
inPolicies []*Policy
defaultInPolicy RouteType
@@ -3362,3 +3595,10 @@ func CanImportToVrf(v *Vrf, path *Path) bool {
c.set = set
return c.Evaluate(path, nil)
}
+
+type PolicyAssignment struct {
+ Name string
+ Type PolicyDirection
+ Policies []*Policy
+ Default RouteType
+}