diff options
-rw-r--r-- | api/gobgp.pb.go | 156 | ||||
-rw-r--r-- | api/gobgp.proto | 81 | ||||
-rw-r--r-- | gobgp/cmd/common.go | 56 | ||||
-rw-r--r-- | gobgp/cmd/neighbor.go | 8 | ||||
-rw-r--r-- | gobgp/cmd/policy.go | 569 | ||||
-rw-r--r-- | packet/bgp.go | 14 | ||||
-rw-r--r-- | server/grpc_server.go | 6 | ||||
-rw-r--r-- | server/peer.go | 9 | ||||
-rw-r--r-- | server/server.go | 264 | ||||
-rw-r--r-- | table/path.go | 11 | ||||
-rw-r--r-- | table/policy.go | 2796 | ||||
-rw-r--r-- | table/policy_test.go | 503 | ||||
-rw-r--r-- | test/scenario_test/route_server_policy_test.py | 8 |
13 files changed, 1964 insertions, 2517 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 80a4d789..819be3ad 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -22,15 +22,12 @@ It has these top-level messages: Peer Prefix PrefixSet - Neighbor - NeighborSet AsPathLength - AsPathSet - CommunitySet - ExtCommunitySet + MatchSet Conditions CommunityAction AsPrependAction + MedAction Actions Statement PolicyDefinition @@ -399,144 +396,100 @@ func (m *Prefix) String() string { return proto.CompactTextString(m) } func (*Prefix) ProtoMessage() {} type PrefixSet struct { - PrefixSetName string `protobuf:"bytes,1,opt,name=prefix_set_name" json:"prefix_set_name,omitempty"` - PrefixList []*Prefix `protobuf:"bytes,2,rep,name=prefix_list" json:"prefix_list,omitempty"` - MatchSetOptions string `protobuf:"bytes,3,opt,name=match_set_options" json:"match_set_options,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + List []*Prefix `protobuf:"bytes,2,rep,name=list" json:"list,omitempty"` + Option int32 `protobuf:"varint,3,opt,name=option" json:"option,omitempty"` } func (m *PrefixSet) Reset() { *m = PrefixSet{} } func (m *PrefixSet) String() string { return proto.CompactTextString(m) } func (*PrefixSet) ProtoMessage() {} -func (m *PrefixSet) GetPrefixList() []*Prefix { +func (m *PrefixSet) GetList() []*Prefix { if m != nil { - return m.PrefixList - } - return nil -} - -type Neighbor struct { - Address string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` -} - -func (m *Neighbor) Reset() { *m = Neighbor{} } -func (m *Neighbor) String() string { return proto.CompactTextString(m) } -func (*Neighbor) ProtoMessage() {} - -type NeighborSet struct { - NeighborSetName string `protobuf:"bytes,1,opt,name=neighbor_set_name" json:"neighbor_set_name,omitempty"` - NeighborList []*Neighbor `protobuf:"bytes,2,rep,name=neighbor_list" json:"neighbor_list,omitempty"` - MatchSetOptions string `protobuf:"bytes,3,opt,name=match_set_options" json:"match_set_options,omitempty"` -} - -func (m *NeighborSet) Reset() { *m = NeighborSet{} } -func (m *NeighborSet) String() string { return proto.CompactTextString(m) } -func (*NeighborSet) ProtoMessage() {} - -func (m *NeighborSet) GetNeighborList() []*Neighbor { - if m != nil { - return m.NeighborList + return m.List } return nil } type AsPathLength struct { - Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` - Operator string `protobuf:"bytes,2,opt,name=operator" json:"operator,omitempty"` + Length uint32 `protobuf:"varint,1,opt,name=length" json:"length,omitempty"` + Type int32 `protobuf:"varint,2,opt,name=type" json:"type,omitempty"` } func (m *AsPathLength) Reset() { *m = AsPathLength{} } func (m *AsPathLength) String() string { return proto.CompactTextString(m) } func (*AsPathLength) ProtoMessage() {} -type AsPathSet struct { - AsPathSetName string `protobuf:"bytes,1,opt,name=as_path_set_name" json:"as_path_set_name,omitempty"` - AsPathMembers []string `protobuf:"bytes,2,rep,name=as_path_members" json:"as_path_members,omitempty"` - MatchSetOptions string `protobuf:"bytes,3,opt,name=match_set_options" json:"match_set_options,omitempty"` -} - -func (m *AsPathSet) Reset() { *m = AsPathSet{} } -func (m *AsPathSet) String() string { return proto.CompactTextString(m) } -func (*AsPathSet) ProtoMessage() {} - -type CommunitySet struct { - CommunitySetName string `protobuf:"bytes,1,opt,name=community_set_name" json:"community_set_name,omitempty"` - CommunityMembers []string `protobuf:"bytes,2,rep,name=community_members" json:"community_members,omitempty"` - MatchSetOptions string `protobuf:"bytes,3,opt,name=match_set_options" json:"match_set_options,omitempty"` +type MatchSet struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + List []string `protobuf:"bytes,2,rep,name=list" json:"list,omitempty"` + Option int32 `protobuf:"varint,3,opt,name=option" json:"option,omitempty"` } -func (m *CommunitySet) Reset() { *m = CommunitySet{} } -func (m *CommunitySet) String() string { return proto.CompactTextString(m) } -func (*CommunitySet) ProtoMessage() {} - -type ExtCommunitySet struct { - ExtCommunitySetName string `protobuf:"bytes,1,opt,name=ext_community_set_name" json:"ext_community_set_name,omitempty"` - ExtCommunityMembers []string `protobuf:"bytes,2,rep,name=ext_community_members" json:"ext_community_members,omitempty"` - MatchSetOptions string `protobuf:"bytes,3,opt,name=match_set_options" json:"match_set_options,omitempty"` -} - -func (m *ExtCommunitySet) Reset() { *m = ExtCommunitySet{} } -func (m *ExtCommunitySet) String() string { return proto.CompactTextString(m) } -func (*ExtCommunitySet) ProtoMessage() {} +func (m *MatchSet) Reset() { *m = MatchSet{} } +func (m *MatchSet) String() string { return proto.CompactTextString(m) } +func (*MatchSet) ProtoMessage() {} type Conditions struct { - MatchPrefixSet *PrefixSet `protobuf:"bytes,1,opt,name=match_prefix_set" json:"match_prefix_set,omitempty"` - MatchNeighborSet *NeighborSet `protobuf:"bytes,2,opt,name=match_neighbor_set" json:"match_neighbor_set,omitempty"` - MatchAsPathLength *AsPathLength `protobuf:"bytes,3,opt,name=match_as_path_length" json:"match_as_path_length,omitempty"` - MatchAsPathSet *AsPathSet `protobuf:"bytes,4,opt,name=match_as_path_set" json:"match_as_path_set,omitempty"` - MatchCommunitySet *CommunitySet `protobuf:"bytes,5,opt,name=match_community_set" json:"match_community_set,omitempty"` - MatchExtCommunitySet *ExtCommunitySet `protobuf:"bytes,6,opt,name=match_ext_community_set" json:"match_ext_community_set,omitempty"` + PrefixSet *PrefixSet `protobuf:"bytes,1,opt,name=prefix_set" json:"prefix_set,omitempty"` + NeighborSet *MatchSet `protobuf:"bytes,2,opt,name=neighbor_set" json:"neighbor_set,omitempty"` + AsPathLength *AsPathLength `protobuf:"bytes,3,opt,name=as_path_length" json:"as_path_length,omitempty"` + AsPathSet *MatchSet `protobuf:"bytes,4,opt,name=as_path_set" json:"as_path_set,omitempty"` + CommunitySet *MatchSet `protobuf:"bytes,5,opt,name=community_set" json:"community_set,omitempty"` + ExtCommunitySet *MatchSet `protobuf:"bytes,6,opt,name=ext_community_set" json:"ext_community_set,omitempty"` + RpkiResult int32 `protobuf:"varint,7,opt,name=rpki_result" json:"rpki_result,omitempty"` } func (m *Conditions) Reset() { *m = Conditions{} } func (m *Conditions) String() string { return proto.CompactTextString(m) } func (*Conditions) ProtoMessage() {} -func (m *Conditions) GetMatchPrefixSet() *PrefixSet { +func (m *Conditions) GetPrefixSet() *PrefixSet { if m != nil { - return m.MatchPrefixSet + return m.PrefixSet } return nil } -func (m *Conditions) GetMatchNeighborSet() *NeighborSet { +func (m *Conditions) GetNeighborSet() *MatchSet { if m != nil { - return m.MatchNeighborSet + return m.NeighborSet } return nil } -func (m *Conditions) GetMatchAsPathLength() *AsPathLength { +func (m *Conditions) GetAsPathLength() *AsPathLength { if m != nil { - return m.MatchAsPathLength + return m.AsPathLength } return nil } -func (m *Conditions) GetMatchAsPathSet() *AsPathSet { +func (m *Conditions) GetAsPathSet() *MatchSet { if m != nil { - return m.MatchAsPathSet + return m.AsPathSet } return nil } -func (m *Conditions) GetMatchCommunitySet() *CommunitySet { +func (m *Conditions) GetCommunitySet() *MatchSet { if m != nil { - return m.MatchCommunitySet + return m.CommunitySet } return nil } -func (m *Conditions) GetMatchExtCommunitySet() *ExtCommunitySet { +func (m *Conditions) GetExtCommunitySet() *MatchSet { if m != nil { - return m.MatchExtCommunitySet + return m.ExtCommunitySet } return nil } type CommunityAction struct { Communities []string `protobuf:"bytes,1,rep,name=communities" json:"communities,omitempty"` - Options string `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + Option int32 `protobuf:"varint,2,opt,name=option" json:"option,omitempty"` } func (m *CommunityAction) Reset() { *m = CommunityAction{} } @@ -544,18 +497,28 @@ func (m *CommunityAction) String() string { return proto.CompactTextString(m) } func (*CommunityAction) ProtoMessage() {} type AsPrependAction struct { - As string `protobuf:"bytes,1,opt,name=as" json:"as,omitempty"` - Repeatn uint32 `protobuf:"varint,2,opt,name=repeatn" json:"repeatn,omitempty"` + Asn uint32 `protobuf:"varint,1,opt,name=asn" json:"asn,omitempty"` + Repeat uint32 `protobuf:"varint,2,opt,name=repeat" json:"repeat,omitempty"` + UseLeftMost bool `protobuf:"varint,3,opt,name=use_left_most" json:"use_left_most,omitempty"` } func (m *AsPrependAction) Reset() { *m = AsPrependAction{} } func (m *AsPrependAction) String() string { return proto.CompactTextString(m) } func (*AsPrependAction) ProtoMessage() {} +type MedAction struct { + Type int32 `protobuf:"varint,1,opt,name=type" json:"type,omitempty"` + Value int64 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"` +} + +func (m *MedAction) Reset() { *m = MedAction{} } +func (m *MedAction) String() string { return proto.CompactTextString(m) } +func (*MedAction) ProtoMessage() {} + type Actions struct { RouteAction RouteAction `protobuf:"varint,1,opt,name=route_action,enum=gobgpapi.RouteAction" json:"route_action,omitempty"` Community *CommunityAction `protobuf:"bytes,2,opt,name=community" json:"community,omitempty"` - Med string `protobuf:"bytes,3,opt,name=med" json:"med,omitempty"` + Med *MedAction `protobuf:"bytes,3,opt,name=med" json:"med,omitempty"` AsPrepend *AsPrependAction `protobuf:"bytes,4,opt,name=as_prepend" json:"as_prepend,omitempty"` ExtCommunity *CommunityAction `protobuf:"bytes,5,opt,name=ext_community" json:"ext_community,omitempty"` } @@ -571,6 +534,13 @@ func (m *Actions) GetCommunity() *CommunityAction { return nil } +func (m *Actions) GetMed() *MedAction { + if m != nil { + return m.Med + } + return nil +} + func (m *Actions) GetAsPrepend() *AsPrependAction { if m != nil { return m.AsPrepend @@ -586,9 +556,9 @@ func (m *Actions) GetExtCommunity() *CommunityAction { } type Statement struct { - StatementNeme string `protobuf:"bytes,1,opt,name=statement_neme" json:"statement_neme,omitempty"` - Conditions *Conditions `protobuf:"bytes,2,opt,name=conditions" json:"conditions,omitempty"` - Actions *Actions `protobuf:"bytes,3,opt,name=actions" json:"actions,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Conditions *Conditions `protobuf:"bytes,2,opt,name=conditions" json:"conditions,omitempty"` + Actions *Actions `protobuf:"bytes,3,opt,name=actions" json:"actions,omitempty"` } func (m *Statement) Reset() { *m = Statement{} } @@ -610,17 +580,17 @@ func (m *Statement) GetActions() *Actions { } type PolicyDefinition struct { - PolicyDefinitionName string `protobuf:"bytes,1,opt,name=policy_definition_name" json:"policy_definition_name,omitempty"` - StatementList []*Statement `protobuf:"bytes,2,rep,name=statement_list" json:"statement_list,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Statements []*Statement `protobuf:"bytes,2,rep,name=statements" json:"statements,omitempty"` } func (m *PolicyDefinition) Reset() { *m = PolicyDefinition{} } func (m *PolicyDefinition) String() string { return proto.CompactTextString(m) } func (*PolicyDefinition) ProtoMessage() {} -func (m *PolicyDefinition) GetStatementList() []*Statement { +func (m *PolicyDefinition) GetStatements() []*Statement { if m != nil { - return m.StatementList + return m.Statements } return nil } diff --git a/api/gobgp.proto b/api/gobgp.proto index f575d139..c3f36061 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -177,86 +177,71 @@ message Prefix { } message PrefixSet { - string prefix_set_name = 1; - repeated Prefix prefix_list = 2; - string match_set_options = 3; -} - -message Neighbor { - string address = 1; -} - -message NeighborSet { - string neighbor_set_name = 1; - repeated Neighbor neighbor_list = 2; - string match_set_options = 3; + string name = 1; + repeated Prefix list = 2; + int32 option = 3; } message AsPathLength { - string value = 1; - string operator = 2; + uint32 length = 1; + int32 type = 2; } -message AsPathSet { - string as_path_set_name = 1; - repeated string as_path_members = 2; - string match_set_options = 3; -} - -message CommunitySet { - string community_set_name = 1; - repeated string community_members = 2; - string match_set_options = 3; +message MatchSet { + string name = 1; + repeated string list = 2; + int32 option = 3; } -message ExtCommunitySet { - string ext_community_set_name = 1; - repeated string ext_community_members = 2; - string match_set_options = 3; +message Conditions { + PrefixSet prefix_set = 1; + MatchSet neighbor_set = 2; + AsPathLength as_path_length = 3; + MatchSet as_path_set = 4; + MatchSet community_set = 5; + MatchSet ext_community_set = 6; + int32 rpki_result = 7; } -message Conditions { - PrefixSet match_prefix_set = 1; - NeighborSet match_neighbor_set = 2; - AsPathLength match_as_path_length = 3; - AsPathSet match_as_path_set = 4; - CommunitySet match_community_set = 5; - ExtCommunitySet match_ext_community_set = 6; +enum RouteAction { + NONE = 0; + ACCEPT = 1; + REJECT = 2; } message CommunityAction { repeated string communities = 1; - string options = 2; + int32 option = 2; } -message AsPrependAction { - string as = 1; - uint32 repeatn = 2; +message MedAction { + int32 type = 1; + int64 value = 2; } -enum RouteAction { - NONE = 0; - ACCEPT = 1; - REJECT = 2; +message AsPrependAction { + uint32 asn = 1; + uint32 repeat = 2; + bool use_left_most = 3; } message Actions { RouteAction route_action = 1; CommunityAction community = 2; - string med = 3; + MedAction med = 3; AsPrependAction as_prepend = 4; CommunityAction ext_community = 5; } message Statement { - string statement_neme = 1; + string name = 1; Conditions conditions = 2; Actions actions = 3; } message PolicyDefinition { - string policy_definition_name = 1; - repeated Statement statement_list = 2; + string name = 1; + repeated Statement statements = 2; } enum PolicyType { diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go index bbe26ea5..197b58cf 100644 --- a/gobgp/cmd/common.go +++ b/gobgp/cmd/common.go @@ -321,63 +321,21 @@ func (p prefixes) Swap(i, j int) { } func (p prefixes) Less(i, j int) bool { - return p[i].PrefixSetName < p[j].PrefixSetName + return p[i].Name < p[j].Name } -type neighbors []*gobgpapi.NeighborSet +type sets []*gobgpapi.MatchSet -func (n neighbors) Len() int { +func (n sets) Len() int { return len(n) } -func (n neighbors) Swap(i, j int) { +func (n sets) Swap(i, j int) { n[i], n[j] = n[j], n[i] } -func (n neighbors) Less(i, j int) bool { - return n[i].NeighborSetName < n[j].NeighborSetName -} - -type aspaths []*gobgpapi.AsPathSet - -func (a aspaths) Len() int { - return len(a) -} - -func (a aspaths) Swap(i, j int) { - a[i], a[j] = a[j], a[i] -} - -func (a aspaths) Less(i, j int) bool { - return a[i].AsPathSetName < a[j].AsPathSetName -} - -type communities []*gobgpapi.CommunitySet - -func (c communities) Len() int { - return len(c) -} - -func (c communities) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -func (c communities) Less(i, j int) bool { - return c[i].CommunitySetName < c[j].CommunitySetName -} - -type extcommunities []*gobgpapi.ExtCommunitySet - -func (e extcommunities) Len() int { - return len(e) -} - -func (e extcommunities) Swap(i, j int) { - e[i], e[j] = e[j], e[i] -} - -func (e extcommunities) Less(i, j int) bool { - return e[i].ExtCommunitySetName < e[j].ExtCommunitySetName +func (n sets) Less(i, j int) bool { + return n[i].Name < n[j].Name } type policyDefinitions []*gobgpapi.PolicyDefinition @@ -391,7 +349,7 @@ func (p policyDefinitions) Swap(i, j int) { } func (p policyDefinitions) Less(i, j int) bool { - return p[i].PolicyDefinitionName < p[j].PolicyDefinitionName + return p[i].Name < p[j].Name } type roas []*gobgpapi.ROA diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go index ca3640fd..0efa6840 100644 --- a/gobgp/cmd/neighbor.go +++ b/gobgp/cmd/neighbor.go @@ -641,9 +641,9 @@ func showNeighborPolicy(remoteIP net.IP, policyType string) error { } fmt.Printf("Default: %s\n", ap.Default) - for _, inPolicy := range ap.Policies { - fmt.Printf(" PolicyName %s:\n", inPolicy.PolicyDefinitionName) - showPolicyStatement(2, inPolicy) + for _, p := range ap.Policies { + fmt.Printf(" PolicyName %s:\n", p.Name) + showPolicyStatement(2, p) } return nil } @@ -654,7 +654,7 @@ func parsePolicy(pNames string) []*api.PolicyDefinition { for _, p := range pList { if p != "" { policy := &api.PolicyDefinition{ - PolicyDefinitionName: p, + Name: p, } policyList = append(policyList, policy) } diff --git a/gobgp/cmd/policy.go b/gobgp/cmd/policy.go index 6445b9d6..4f9d1f0f 100644 --- a/gobgp/cmd/policy.go +++ b/gobgp/cmd/policy.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" api "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/table" "github.com/spf13/cobra" "golang.org/x/net/context" @@ -38,10 +39,10 @@ func formatPolicyPrefix(head bool, indent int, psl []*api.PrefixSet) string { maxPrefixLen := 0 maxRangeLen := 0 for _, ps := range psl { - if len(ps.PrefixSetName) > maxNameLen { - maxNameLen = len(ps.PrefixSetName) + if len(ps.Name) > maxNameLen { + maxNameLen = len(ps.Name) } - for _, p := range ps.PrefixList { + for _, p := range ps.List { if len(p.IpPrefix) > maxPrefixLen { maxPrefixLen = len(p.IpPrefix) } @@ -68,10 +69,10 @@ func formatPolicyPrefix(head bool, indent int, psl []*api.PrefixSet) string { buff.WriteString(fmt.Sprintf(format, "Name", "Address", "MaskRange")) } for _, ps := range psl { - for i, p := range ps.PrefixList { + for i, p := range ps.List { prefix := fmt.Sprintf("%s", p.IpPrefix) if i == 0 { - buff.WriteString(fmt.Sprintf(format, ps.PrefixSetName, prefix, p.MaskLengthRange)) + buff.WriteString(fmt.Sprintf(format, ps.Name, prefix, p.MaskLengthRange)) } else { buff.WriteString(fmt.Sprintf(sIndent)) buff.WriteString(fmt.Sprintf(format, "", prefix, p.MaskLengthRange)) @@ -97,7 +98,7 @@ func showPolicyPrefixes() error { } else if e != nil { return e } - m = append(m, p.StatementList[0].Conditions.MatchPrefixSet) + m = append(m, p.Statements[0].Conditions.PrefixSet) } if globalOpts.Json { @@ -108,7 +109,7 @@ func showPolicyPrefixes() error { if globalOpts.Quiet { for _, p := range m { - fmt.Println(p.PrefixSetName) + fmt.Println(p.Name) } return nil } @@ -129,14 +130,14 @@ func showPolicyPrefix(args []string) error { if e != nil { return e } - ps := pd.StatementList[0].Conditions.MatchPrefixSet + ps := pd.Statements[0].Conditions.PrefixSet if globalOpts.Json { j, _ := json.Marshal(ps) fmt.Println(string(j)) return nil } if globalOpts.Quiet { - for _, p := range ps.PrefixList { + for _, p := range ps.List { fmt.Printf("%s %s\n", p.IpPrefix, p.MaskLengthRange) } return nil @@ -189,8 +190,8 @@ func parsePrefixSet(eArgs []string) (*api.PrefixSet, error) { } prefixList := []*api.Prefix{prefix} prefixSet := &api.PrefixSet{ - PrefixSetName: eArgs[0], - PrefixList: prefixList, + Name: eArgs[0], + List: prefixList, } return prefixSet, nil } @@ -200,17 +201,17 @@ func modPolicy(resource api.Resource, op api.Operation, data interface{}) error co := &api.Conditions{} switch resource { case api.Resource_POLICY_PREFIX: - co.MatchPrefixSet = data.(*api.PrefixSet) + co.PrefixSet = data.(*api.PrefixSet) case api.Resource_POLICY_NEIGHBOR: - co.MatchNeighborSet = data.(*api.NeighborSet) + co.NeighborSet = data.(*api.MatchSet) case api.Resource_POLICY_ASPATH: - co.MatchAsPathSet = data.(*api.AsPathSet) + co.AsPathSet = data.(*api.MatchSet) case api.Resource_POLICY_COMMUNITY: - co.MatchCommunitySet = data.(*api.CommunitySet) + co.CommunitySet = data.(*api.MatchSet) case api.Resource_POLICY_EXTCOMMUNITY: - co.MatchExtCommunitySet = data.(*api.ExtCommunitySet) + co.ExtCommunitySet = data.(*api.MatchSet) } - pd.StatementList = []*api.Statement{{Conditions: co}} + pd.Statements = []*api.Statement{{Conditions: co}} } else { pd = data.(*api.PolicyDefinition) } @@ -258,8 +259,7 @@ func modPolicyPrefix(modtype string, eArgs []string) error { return fmt.Errorf("usage: policy prefix del <prefix set name> [<prefix> [<mask length renge>]]") } else if len(eArgs) == 1 { prefixSet = &api.PrefixSet{ - PrefixSetName: eArgs[0], - PrefixList: nil, + Name: eArgs[0], } } else { if prefixSet, e = parsePrefixSet(eArgs); e != nil { @@ -281,18 +281,18 @@ func modPolicyPrefix(modtype string, eArgs []string) error { return nil } -func formatPolicyNeighbor(head bool, indent int, nsl []*api.NeighborSet) string { +func formatPolicyNeighbor(head bool, indent int, nsl []*api.MatchSet) string { buff := bytes.NewBuffer(make([]byte, 0, 64)) sIndent := strings.Repeat(" ", indent) maxNameLen := 0 maxAddressLen := 0 for _, ns := range nsl { - if len(ns.NeighborSetName) > maxNameLen { - maxNameLen = len(ns.NeighborSetName) + if len(ns.Name) > maxNameLen { + maxNameLen = len(ns.Name) } - for _, n := range ns.NeighborList { - if len(n.Address) > maxAddressLen { - maxAddressLen = len(n.Address) + for _, n := range ns.List { + if len(n) > maxAddressLen { + maxAddressLen = len(n) } } } @@ -311,12 +311,12 @@ func formatPolicyNeighbor(head bool, indent int, nsl []*api.NeighborSet) string buff.WriteString(fmt.Sprintf(format, "Name", "Address")) } for _, ns := range nsl { - for i, n := range ns.NeighborList { + for i, n := range ns.List { if i == 0 { - buff.WriteString(fmt.Sprintf(format, ns.NeighborSetName, n.Address)) + buff.WriteString(fmt.Sprintf(format, ns.Name, n)) } else { buff.WriteString(fmt.Sprintf(sIndent)) - buff.WriteString(fmt.Sprintf(format, "", n.Address)) + buff.WriteString(fmt.Sprintf(format, "", n)) } } } @@ -331,7 +331,7 @@ func showPolicyNeighbors() error { if e != nil { return e } - m := neighbors{} + m := sets{} for { p, e := stream.Recv() if e == io.EOF { @@ -339,7 +339,7 @@ func showPolicyNeighbors() error { } else if e != nil { return e } - m = append(m, p.StatementList[0].Conditions.MatchNeighborSet) + m = append(m, p.Statements[0].Conditions.NeighborSet) } if globalOpts.Json { @@ -350,7 +350,7 @@ func showPolicyNeighbors() error { if globalOpts.Quiet { for _, n := range m { - fmt.Println(n.NeighborSetName) + fmt.Println(n.Name) } return nil } @@ -370,24 +370,24 @@ func showPolicyNeighbor(args []string) error { if e != nil { return e } - ns := pd.StatementList[0].Conditions.MatchNeighborSet + ns := pd.Statements[0].Conditions.NeighborSet if globalOpts.Json { j, _ := json.Marshal(ns) fmt.Println(string(j)) return nil } if globalOpts.Quiet { - for _, n := range ns.NeighborList { - fmt.Println(n.Address) + for _, n := range ns.List { + fmt.Println(n) } return nil } - output := formatPolicyNeighbor(true, 0, []*api.NeighborSet{ns}) + output := formatPolicyNeighbor(true, 0, []*api.MatchSet{ns}) fmt.Print(output) return nil } -func parseNeighborSet(eArgs []string) (*api.NeighborSet, error) { +func parseNeighborSet(eArgs []string) (*api.MatchSet, error) { address := net.ParseIP(eArgs[1]) if address.To4() == nil { if address.To16() == nil { @@ -395,19 +395,15 @@ func parseNeighborSet(eArgs []string) (*api.NeighborSet, error) { } } - neighbor := &api.Neighbor{ - Address: address.String(), - } - neighborList := []*api.Neighbor{neighbor} - neighborSet := &api.NeighborSet{ - NeighborSetName: eArgs[0], - NeighborList: neighborList, + neighborSet := &api.MatchSet{ + Name: eArgs[0], + List: []string{address.String()}, } return neighborSet, nil } func modPolicyNeighbor(modtype string, eArgs []string) error { - neighborSet := &api.NeighborSet{} + neighborSet := &api.MatchSet{} var e error var operation api.Operation @@ -424,9 +420,8 @@ func modPolicyNeighbor(modtype string, eArgs []string) error { if len(eArgs) == 0 { return fmt.Errorf("usage: policy neighbor del <neighbor set name> [<address>]") } else if len(eArgs) == 1 { - neighborSet = &api.NeighborSet{ - NeighborSetName: eArgs[0], - NeighborList: nil, + neighborSet = &api.MatchSet{ + Name: eArgs[0], } } else { if neighborSet, e = parseNeighborSet(eArgs); e != nil { @@ -448,16 +443,16 @@ func modPolicyNeighbor(modtype string, eArgs []string) error { return nil } -func formatPolicyAsPath(haed bool, indent int, apsl []*api.AsPathSet) string { +func formatPolicyAsPath(haed bool, indent int, apsl []*api.MatchSet) string { buff := bytes.NewBuffer(make([]byte, 0, 64)) sIndent := strings.Repeat(" ", indent) maxNameLen := 0 maxPathLen := 0 for _, aps := range apsl { - if len(aps.AsPathSetName) > maxNameLen { - maxNameLen = len(aps.AsPathSetName) + if len(aps.Name) > maxNameLen { + maxNameLen = len(aps.Name) } - for _, m := range aps.AsPathMembers { + for _, m := range aps.List { if len(m) > maxPathLen { maxPathLen = len(m) } @@ -478,9 +473,9 @@ func formatPolicyAsPath(haed bool, indent int, apsl []*api.AsPathSet) string { buff.WriteString(fmt.Sprintf(format, "Name", "AsPath")) } for _, aps := range apsl { - for i, a := range aps.AsPathMembers { + for i, a := range aps.List { if i == 0 { - buff.WriteString(fmt.Sprintf(format, aps.AsPathSetName, a)) + buff.WriteString(fmt.Sprintf(format, aps.Name, a)) } else { buff.WriteString(fmt.Sprintf(sIndent)) buff.WriteString(fmt.Sprintf(format, "", a)) @@ -498,7 +493,7 @@ func showPolicyAsPaths() error { if e != nil { return e } - m := aspaths{} + m := sets{} for { a, e := stream.Recv() if e == io.EOF { @@ -506,7 +501,7 @@ func showPolicyAsPaths() error { } else if e != nil { return e } - m = append(m, a.StatementList[0].Conditions.MatchAsPathSet) + m = append(m, a.Statements[0].Conditions.AsPathSet) } if globalOpts.Json { j, _ := json.Marshal(m) @@ -515,7 +510,7 @@ func showPolicyAsPaths() error { } if globalOpts.Quiet { for _, a := range m { - fmt.Println(a.AsPathSetName) + fmt.Println(a.Name) } return nil } @@ -535,24 +530,24 @@ func showPolicyAsPath(args []string) error { if e != nil { return e } - as := pd.StatementList[0].Conditions.MatchAsPathSet + as := pd.Statements[0].Conditions.AsPathSet if globalOpts.Json { j, _ := json.Marshal(as) fmt.Println(string(j)) return nil } if globalOpts.Quiet { - for _, a := range as.AsPathMembers { + for _, a := range as.List { fmt.Println(a) } return nil } - output := formatPolicyAsPath(true, 0, []*api.AsPathSet{as}) + output := formatPolicyAsPath(true, 0, []*api.MatchSet{as}) fmt.Print(output) return nil } -func parseAsPathSet(eArgs []string) (*api.AsPathSet, error) { +func parseAsPathSet(eArgs []string) (*api.MatchSet, error) { as := eArgs[1] isTop := as[:1] == "^" if isTop { @@ -573,15 +568,15 @@ func parseAsPathSet(eArgs []string) (*api.AsPathSet, error) { "can not comple aspath values to regular expressions.", eArgs[1]) } } - asPathSet := &api.AsPathSet{ - AsPathSetName: eArgs[0], - AsPathMembers: []string{eArgs[1]}, + asPathSet := &api.MatchSet{ + Name: eArgs[0], + List: []string{eArgs[1]}, } return asPathSet, nil } func modPolicyAsPath(modtype string, eArgs []string) error { - asPathSet := &api.AsPathSet{} + asPathSet := &api.MatchSet{} var e error var operation api.Operation @@ -598,9 +593,8 @@ func modPolicyAsPath(modtype string, eArgs []string) error { if len(eArgs) == 0 { return fmt.Errorf("usage: policy aspath del <aspath set name> [<aspath>]") } else if len(eArgs) == 1 { - asPathSet = &api.AsPathSet{ - AsPathSetName: eArgs[0], - AsPathMembers: nil, + asPathSet = &api.MatchSet{ + Name: eArgs[0], } } else { if asPathSet, e = parseAsPathSet(eArgs); e != nil { @@ -622,16 +616,16 @@ func modPolicyAsPath(modtype string, eArgs []string) error { return nil } -func formatPolicyCommunity(head bool, indent int, csl []*api.CommunitySet) string { +func formatPolicyCommunity(head bool, indent int, csl []*api.MatchSet) string { buff := bytes.NewBuffer(make([]byte, 0, 64)) sIndent := strings.Repeat(" ", indent) maxNameLen := 0 maxCommunityLen := 0 for _, cs := range csl { - if len(cs.CommunitySetName) > maxNameLen { - maxNameLen = len(cs.CommunitySetName) + if len(cs.Name) > maxNameLen { + maxNameLen = len(cs.Name) } - for _, m := range cs.CommunityMembers { + for _, m := range cs.List { if len(m) > maxCommunityLen { maxCommunityLen = len(m) } @@ -652,9 +646,9 @@ func formatPolicyCommunity(head bool, indent int, csl []*api.CommunitySet) strin buff.WriteString(fmt.Sprintf(format, "Name", "Community")) } for _, cs := range csl { - for i, c := range cs.CommunityMembers { + for i, c := range cs.List { if i == 0 { - buff.WriteString(fmt.Sprintf(format, cs.CommunitySetName, c)) + buff.WriteString(fmt.Sprintf(format, cs.Name, c)) } else { buff.WriteString(fmt.Sprintf(sIndent)) buff.WriteString(fmt.Sprintf(format, "", c)) @@ -672,7 +666,7 @@ func showPolicyCommunities() error { if e != nil { return e } - m := communities{} + m := sets{} for { a, e := stream.Recv() if e == io.EOF { @@ -680,7 +674,7 @@ func showPolicyCommunities() error { } else if e != nil { return e } - m = append(m, a.StatementList[0].Conditions.MatchCommunitySet) + m = append(m, a.Statements[0].Conditions.CommunitySet) } if globalOpts.Json { j, _ := json.Marshal(m) @@ -689,7 +683,7 @@ func showPolicyCommunities() error { } if globalOpts.Quiet { for _, c := range m { - fmt.Println(c.CommunitySetName) + fmt.Println(c.Name) } return nil } @@ -709,53 +703,46 @@ func showPolicyCommunity(args []string) error { if e != nil { return e } - cs := pd.StatementList[0].Conditions.GetMatchCommunitySet() + cs := pd.Statements[0].Conditions.GetCommunitySet() if globalOpts.Json { j, _ := json.Marshal(cs) fmt.Println(string(j)) return nil } if globalOpts.Quiet { - for _, c := range cs.CommunityMembers { + for _, c := range cs.List { fmt.Println(c) } return nil } - output := formatPolicyCommunity(true, 0, []*api.CommunitySet{cs}) + output := formatPolicyCommunity(true, 0, []*api.MatchSet{cs}) fmt.Print(output) return nil } func checkCommunityFormat(comStr string) bool { - // community regexp - regUint, _ := regexp.Compile("^([0-9]+)$") - regString, _ := regexp.Compile("([0-9]+):([0-9]+)") - regWellKnown, _ := regexp.Compile("^(" + - table.COMMUNITY_INTERNET + "|" + - table.COMMUNITY_NO_EXPORT + "|" + - table.COMMUNITY_NO_ADVERTISE + "|" + - table.COMMUNITY_NO_EXPORT_SUBCONFED + ")$") - if regUint.MatchString(comStr) || regString.MatchString(comStr) || regWellKnown.MatchString(comStr) { + _, e := table.ParseCommunity(comStr) + if e == nil { return true } return false } -func parseCommunitySet(eArgs []string) (*api.CommunitySet, error) { +func parseCommunitySet(eArgs []string) (*api.MatchSet, error) { if !checkCommunityFormat(eArgs[1]) { if _, err := regexp.Compile(eArgs[1]); err != nil { return nil, fmt.Errorf("invalid community: %s\nplease enter community format", eArgs[1]) } } - communitySet := &api.CommunitySet{ - CommunitySetName: eArgs[0], - CommunityMembers: []string{eArgs[1]}, + communitySet := &api.MatchSet{ + Name: eArgs[0], + List: []string{eArgs[1]}, } return communitySet, nil } func modPolicyCommunity(modtype string, eArgs []string) error { - communitySet := &api.CommunitySet{} + communitySet := &api.MatchSet{} var e error var operation api.Operation @@ -772,9 +759,8 @@ func modPolicyCommunity(modtype string, eArgs []string) error { if len(eArgs) == 0 { return fmt.Errorf("usage: policy community add <community set name> [<community>]") } else if len(eArgs) == 1 { - communitySet = &api.CommunitySet{ - CommunitySetName: eArgs[0], - CommunityMembers: nil, + communitySet = &api.MatchSet{ + Name: eArgs[0], } } else { if communitySet, e = parseCommunitySet(eArgs); e != nil { @@ -796,16 +782,16 @@ func modPolicyCommunity(modtype string, eArgs []string) error { return nil } -func formatPolicyExtCommunity(head bool, indent int, ecsl []*api.ExtCommunitySet) string { +func formatPolicyExtCommunity(head bool, indent int, ecsl []*api.MatchSet) string { buff := bytes.NewBuffer(make([]byte, 0, 64)) sIndent := strings.Repeat(" ", indent) maxNameLen := 0 maxCommunityLen := 0 for _, es := range ecsl { - if len(es.ExtCommunitySetName) > maxNameLen { - maxNameLen = len(es.ExtCommunitySetName) + if len(es.Name) > maxNameLen { + maxNameLen = len(es.Name) } - for _, m := range es.ExtCommunityMembers { + for _, m := range es.List { if len(m) > maxCommunityLen { maxCommunityLen = len(m) } @@ -826,9 +812,9 @@ func formatPolicyExtCommunity(head bool, indent int, ecsl []*api.ExtCommunitySet buff.WriteString(fmt.Sprintf(format, "Name", "ExtCommunity")) } for _, ecs := range ecsl { - for i, ec := range ecs.ExtCommunityMembers { + for i, ec := range ecs.List { if i == 0 { - buff.WriteString(fmt.Sprintf(format, ecs.ExtCommunitySetName, ec)) + buff.WriteString(fmt.Sprintf(format, ecs.Name, ec)) } else { buff.WriteString(fmt.Sprintf(sIndent)) buff.WriteString(fmt.Sprintf(format, "", ec)) @@ -846,7 +832,7 @@ func showPolicyExtCommunities() error { if e != nil { return e } - m := extcommunities{} + m := sets{} for { a, e := stream.Recv() if e == io.EOF { @@ -854,7 +840,7 @@ func showPolicyExtCommunities() error { } else if e != nil { return e } - m = append(m, a.StatementList[0].Conditions.MatchExtCommunitySet) + m = append(m, a.Statements[0].Conditions.ExtCommunitySet) } if globalOpts.Json { j, _ := json.Marshal(m) @@ -863,7 +849,7 @@ func showPolicyExtCommunities() error { } if globalOpts.Quiet { for _, e := range m { - fmt.Println(e.ExtCommunitySetName) + fmt.Println(e.Name) } return nil } @@ -883,19 +869,19 @@ func showPolicyExtCommunity(args []string) error { if e != nil { return e } - ecs := pd.StatementList[0].Conditions.GetMatchExtCommunitySet() + ecs := pd.Statements[0].Conditions.GetExtCommunitySet() if globalOpts.Json { j, _ := json.Marshal(ecs) fmt.Println(string(j)) return nil } if globalOpts.Quiet { - for _, ec := range ecs.ExtCommunityMembers { + for _, ec := range ecs.List { fmt.Println(ec) } return nil } - output := formatPolicyExtCommunity(true, 0, []*api.ExtCommunitySet{ecs}) + output := formatPolicyExtCommunity(true, 0, []*api.MatchSet{ecs}) fmt.Print(output) return nil } @@ -945,19 +931,18 @@ func checkExtCommunityFormat(eComStr string) bool { return false } -func parseExtCommunitySet(eArgs []string) (*api.ExtCommunitySet, error) { +func parseExtCommunitySet(eArgs []string) (*api.MatchSet, error) { if !checkExtCommunityFormat(eArgs[1]) { return nil, fmt.Errorf("invalid extended community: %s\nplease enter extended community format", eArgs[1]) } - extCommunitySet := &api.ExtCommunitySet{ - ExtCommunitySetName: eArgs[0], - ExtCommunityMembers: []string{eArgs[1]}, - } - return extCommunitySet, nil + return &api.MatchSet{ + Name: eArgs[0], + List: []string{eArgs[1]}, + }, nil } func modPolicyExtCommunity(modtype string, eArgs []string) error { - extCommunitySet := &api.ExtCommunitySet{} + extCommunitySet := &api.MatchSet{} var e error var operation api.Operation @@ -974,9 +959,8 @@ func modPolicyExtCommunity(modtype string, eArgs []string) error { if len(eArgs) == 0 { return fmt.Errorf("usage: policy extcommunity add <community set name> [<community>]") } else if len(eArgs) == 1 { - extCommunitySet = &api.ExtCommunitySet{ - ExtCommunitySetName: eArgs[0], - ExtCommunityMembers: nil, + extCommunitySet = &api.MatchSet{ + Name: eArgs[0], } } else { if extCommunitySet, e = parseExtCommunitySet(eArgs); e != nil { @@ -1003,73 +987,93 @@ func showPolicyStatement(indent int, pd *api.PolicyDefinition) { return strings.Repeat(" ", indent) } baseIndent := 28 - for _, st := range pd.StatementList { - fmt.Printf("%sStatementName %s:\n", sIndent(indent), st.StatementNeme) + for _, st := range pd.Statements { + fmt.Printf("%sStatementName %s:\n", sIndent(indent), st.Name) fmt.Printf("%sConditions:\n", sIndent(indent+2)) - ps := st.Conditions.MatchPrefixSet - fmt.Printf("%sPrefixSet: %-6s ", sIndent(indent+4), ps.MatchSetOptions) - if out := formatPolicyPrefix(false, baseIndent+indent, []*api.PrefixSet{ps}); out != "" { - fmt.Print(out) - } else { - fmt.Printf("\n") + ps := st.Conditions.PrefixSet + if ps != nil { + fmt.Printf("%sPrefixSet: %-6s ", sIndent(indent+4), table.MatchOption(ps.Option)) + if out := formatPolicyPrefix(false, baseIndent+indent, []*api.PrefixSet{ps}); out != "" { + fmt.Print(out) + } else { + fmt.Printf("\n") + } } - ns := st.Conditions.MatchNeighborSet - fmt.Printf("%sNeighborSet: %-6s ", sIndent(indent+4), ns.MatchSetOptions) - if out := formatPolicyNeighbor(false, baseIndent+indent, []*api.NeighborSet{ns}); out != "" { - fmt.Print(out) - } else { - fmt.Printf("\n") + ns := st.Conditions.NeighborSet + if ns != nil { + fmt.Printf("%sNeighborSet: %-6s ", sIndent(indent+4), table.MatchOption(ns.Option)) + if out := formatPolicyNeighbor(false, baseIndent+indent, []*api.MatchSet{ns}); out != "" { + fmt.Print(out) + } else { + fmt.Printf("\n") + } } - aps := st.Conditions.MatchAsPathSet - fmt.Printf("%sAsPathSet: %-6s ", sIndent(indent+4), aps.MatchSetOptions) - if out := formatPolicyAsPath(false, baseIndent+indent, []*api.AsPathSet{aps}); out != "" { - fmt.Print(out) - } else { - fmt.Printf("\n") + aps := st.Conditions.AsPathSet + if aps != nil { + fmt.Printf("%sAsPathSet: %-6s ", sIndent(indent+4), aps.Option) + if out := formatPolicyAsPath(false, baseIndent+indent, []*api.MatchSet{aps}); out != "" { + fmt.Print(out) + } else { + fmt.Printf("\n") + } } - cs := st.Conditions.MatchCommunitySet - fmt.Printf("%sCommunitySet: %-6s ", sIndent(indent+4), cs.MatchSetOptions) - if out := formatPolicyCommunity(false, baseIndent+indent, []*api.CommunitySet{cs}); out != "" { - fmt.Print(out) - } else { - fmt.Printf("\n") + cs := st.Conditions.CommunitySet + if cs != nil { + fmt.Printf("%sCommunitySet: %-6s ", sIndent(indent+4), cs.Option) + if out := formatPolicyCommunity(false, baseIndent+indent, []*api.MatchSet{cs}); out != "" { + fmt.Print(out) + } else { + fmt.Printf("\n") + } } - ecs := st.Conditions.MatchExtCommunitySet - fmt.Printf("%sExtCommunitySet: %-6s ", sIndent(indent+4), ecs.MatchSetOptions) - if out := formatPolicyExtCommunity(false, baseIndent+indent, []*api.ExtCommunitySet{ecs}); out != "" { - fmt.Print(out) - } else { - fmt.Printf("\n") + ecs := st.Conditions.ExtCommunitySet + if ecs != nil { + fmt.Printf("%sExtCommunitySet: %-6s ", sIndent(indent+4), ecs.Option) + if out := formatPolicyExtCommunity(false, baseIndent+indent, []*api.MatchSet{ecs}); out != "" { + fmt.Print(out) + } else { + fmt.Printf("\n") + } } - asPathLentgh := st.Conditions.MatchAsPathLength - fmt.Printf("%sAsPathLength: %-6s %s\n", sIndent(indent+4), asPathLentgh.Operator, asPathLentgh.Value) + asPathLentgh := st.Conditions.AsPathLength + if asPathLentgh != nil { + fmt.Printf("%sAsPathLength: %-6s %s\n", sIndent(indent+4), asPathLentgh.Type, asPathLentgh.Length) + } fmt.Printf("%sActions:\n", sIndent(indent+2)) formatComAction := func(c *api.CommunityAction) string { - communityAction := c.Options - if len(c.Communities) != 0 || c.Options == "NULL" { + option := table.CommunityOptionNameMap[config.BgpSetCommunityOptionType(c.Option)] + if len(c.Communities) != 0 { communities := strings.Join(c.Communities, ",") - communityAction = fmt.Sprintf("%s[%s]", c.Options, communities) + option = fmt.Sprintf("%s[%s]", option, communities) } - return communityAction + return option + } + if st.Actions.Community != nil { + fmt.Printf("%sCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.Community)) } - fmt.Printf("%sCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.Community)) - fmt.Printf("%sExtCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.ExtCommunity)) - fmt.Printf("%sMed: %s\n", sIndent(indent+4), st.Actions.Med) + if st.Actions.ExtCommunity != nil { + fmt.Printf("%sExtCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.ExtCommunity)) + } + if st.Actions.Med != nil { + fmt.Printf("%sMed: %s\n", sIndent(indent+4), st.Actions.Med.Value) + } + if st.Actions.AsPrepend != nil { + var asn string + if st.Actions.AsPrepend.UseLeftMost { + asn = "left-most" + } else { + asn = fmt.Sprintf("%d", st.Actions.AsPrepend.Asn) + } - asn := "" - repeat := "" - if st.Actions.AsPrepend.As != "" { - asn = st.Actions.AsPrepend.As - repeat = fmt.Sprintf("%d", st.Actions.AsPrepend.Repeatn) + fmt.Printf("%sAsPrepend: %s %d\n", sIndent(indent+4), asn, st.Actions.AsPrepend.Repeat) } - fmt.Printf("%sAsPrepend: %s %s\n", sIndent(indent+4), asn, repeat) fmt.Printf("%s%s\n", sIndent(indent+4), st.Actions.RouteAction) } @@ -1101,14 +1105,14 @@ func showPolicyRoutePolicies() error { } if globalOpts.Quiet { for _, p := range m { - fmt.Println(p.PolicyDefinitionName) + fmt.Println(p.Name) } return nil } sort.Sort(m) for _, pd := range m { - fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) + fmt.Printf("PolicyName %s:\n", pd.Name) showPolicyStatement(4, pd) } return nil @@ -1131,102 +1135,120 @@ func showPolicyRoutePolicy(args []string) error { } if globalOpts.Quiet { - for _, st := range pd.StatementList { - fmt.Println(st.StatementNeme) + for _, st := range pd.Statements { + fmt.Println(st.Name) } return nil } - fmt.Printf("PolicyName %s:\n", pd.PolicyDefinitionName) + fmt.Printf("PolicyName %s:\n", pd.Name) showPolicyStatement(2, pd) return nil } func parseConditions() (*api.Conditions, error) { - checkFormat := func(option string, isRestricted bool) ([]string, error) { + checkFormat := func(option string, isRestricted bool) (int32, string, error) { regStr, _ := regexp.Compile("^(.*)\\[(.*)\\]$") isMatched := regStr.MatchString(option) + var op int32 + var name string if !isMatched { - return nil, fmt.Errorf("Please enter the <match option>[condition name]") + return op, name, fmt.Errorf("Please enter the <match option>[condition name]") } group := regStr.FindStringSubmatch(option) - if isRestricted { - if group[1] != "ANY" && group[1] != "INVERT" { - return nil, fmt.Errorf("Please enter the <ANY|INVERT>[condition name]") - } - } else { - if group[1] != "ANY" && group[1] != "ALL" && group[1] != "INVERT" { - return nil, fmt.Errorf("Please enter the <ANY|ALL|INVERT>[condition name]") + switch strings.ToLower(group[1]) { + case "any": + op = int32(table.MATCH_OPTION_ANY) + case "invert": + op = int32(table.MATCH_OPTION_INVERT) + case "all": + if isRestricted { + return op, name, fmt.Errorf("can't use 'all' for the condition option") } + op = int32(table.MATCH_OPTION_ALL) + default: + return op, name, fmt.Errorf("unknown condition option") } - return group, nil + name = group[2] + return op, name, nil } conditions := &api.Conditions{} if conditionOpts.Prefix != "" { - op, err := checkFormat(conditionOpts.Prefix, true) + op, name, err := checkFormat(conditionOpts.Prefix, true) if err != nil { return nil, fmt.Errorf("invalid prefix option format\n%s", err) } - conditions.MatchPrefixSet = &api.PrefixSet{ - PrefixSetName: op[2], - MatchSetOptions: op[1], + conditions.PrefixSet = &api.PrefixSet{ + Name: name, + Option: op, } } if conditionOpts.Neighbor != "" { - op, err := checkFormat(conditionOpts.Neighbor, true) + op, name, err := checkFormat(conditionOpts.Neighbor, true) if err != nil { return nil, fmt.Errorf("invalid neighbor option format\n%s", err) } - conditions.MatchNeighborSet = &api.NeighborSet{ - NeighborSetName: op[2], - MatchSetOptions: op[1], + conditions.NeighborSet = &api.MatchSet{ + Name: name, + Option: op, } } if conditionOpts.AsPath != "" { - op, err := checkFormat(conditionOpts.AsPath, false) + op, name, err := checkFormat(conditionOpts.AsPath, false) if err != nil { return nil, fmt.Errorf("invalid aspath option format\n%s", err) } - conditions.MatchAsPathSet = &api.AsPathSet{ - AsPathSetName: op[2], - MatchSetOptions: op[1], + conditions.AsPathSet = &api.MatchSet{ + Name: name, + Option: op, } } if conditionOpts.Community != "" { - op, err := checkFormat(conditionOpts.Community, false) + op, name, err := checkFormat(conditionOpts.Community, false) if err != nil { return nil, fmt.Errorf("invalid community option format\n%s", err) } - conditions.MatchCommunitySet = &api.CommunitySet{ - CommunitySetName: op[2], - MatchSetOptions: op[1], + conditions.CommunitySet = &api.MatchSet{ + Name: name, + Option: op, } } if conditionOpts.ExtCommunity != "" { - op, err := checkFormat(conditionOpts.ExtCommunity, false) + op, name, err := checkFormat(conditionOpts.ExtCommunity, false) if err != nil { return nil, fmt.Errorf("invalid extended community option format\n%s", err) } - conditions.MatchExtCommunitySet = &api.ExtCommunitySet{ - ExtCommunitySetName: op[2], - MatchSetOptions: op[1], + conditions.ExtCommunitySet = &api.MatchSet{ + Name: name, + Option: op, } } if conditionOpts.AsPathLength != "" { asPathLen := conditionOpts.AsPathLength - idx := strings.Index(asPathLen, ",") - if idx == -1 { + elems := strings.Split(asPathLen, ",") + if len(elems) != 2 { return nil, fmt.Errorf("invalid as path length: %s\nPlease enter the <value>,<operator>", asPathLen) } - operator := asPathLen[:idx] - value := asPathLen[idx+1:] - if _, err := strconv.ParseUint(value, 10, 32); err != nil { - return nil, fmt.Errorf("invalid as path length: %s\nPlease enter a numeric", value) + var typ int32 + switch strings.ToLower(elems[0]) { + case "eq": + typ = int32(table.ATTRIBUTE_EQ) + case "ge": + typ = int32(table.ATTRIBUTE_GE) + case "le": + typ = int32(table.ATTRIBUTE_LE) + default: + return nil, fmt.Errorf("invalid aspath length action type") + + } + length, err := strconv.Atoi(elems[1]) + if err != nil { + return nil, fmt.Errorf("invalid as path length: %s\nPlease enter a numeric", elems[1]) } - conditions.MatchAsPathLength = &api.AsPathLength{ - Value: value, - Operator: operator, + conditions.AsPathLength = &api.AsPathLength{ + Type: typ, + Length: uint32(length), } } return conditions, nil @@ -1245,84 +1267,68 @@ func parseRouteAction(rType string) (api.RouteAction, error) { } func parseCommunityAction(communityStr string) (*api.CommunityAction, error) { - regStr, _ := regexp.Compile("^(.*)\\[(.*)\\]$") - var communities, option string - communityList := make([]string, 0) - if regStr.MatchString(communityStr) { - group := regStr.FindStringSubmatch(communityStr) - option = group[1] - communities = group[2] - - // check options - communityActionTypes := table.COMMUNITY_ACTION_ADD + "|" + - table.COMMUNITY_ACTION_REPLACE + "|" + - table.COMMUNITY_ACTION_REMOVE + "|" + - table.COMMUNITY_ACTION_NULL - regOption, _ := regexp.Compile(fmt.Sprintf("^(%s)$", communityActionTypes)) - if !regOption.MatchString(option) { - e := fmt.Sprintf("invalid Option: %s\n", option) - e += fmt.Sprintf("please enter the (%s)", communityActionTypes) - return nil, fmt.Errorf("%s", e) - } - // check the relationship between the community and the option - if option == "NULL" && communities != "" { - e := "invalid relationship between community and option\n" - e += "When the option is NULL, community should not be input" - return nil, fmt.Errorf("%s", e) - } else if !(communities == "" && option == "NULL") { - // check communities - communityList = strings.Split(communities, ",") - for _, community := range communityList { - if !checkCommunityFormat(community) { - return nil, fmt.Errorf("invalid Community %s:", community) - } - } - } - } else { + exp := regexp.MustCompile("^(.*)\\[(.*)\\]$") + elems := exp.FindStringSubmatch(communityStr) + if len(elems) != 3 { e := fmt.Sprintf("invalid format: %s\n", communityStr) e += "please enter the <option>[<comunity>,<comunity>,...]" return nil, fmt.Errorf("%s", e) } - communityAction := &api.CommunityAction{ - Communities: communityList, - Options: option, + + var op int32 + switch strings.ToLower(elems[1]) { + case "add": + op = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD) + case "remove": + op = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE) + case "replace": + op = int32(config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE) + default: + return nil, fmt.Errorf("invalid community action option") } - return communityAction, nil + return &api.CommunityAction{ + Communities: strings.Split(elems[2], ","), + Option: op, + }, nil } func parseAsPrependAction(communityStr string) (*api.AsPrependAction, error) { - regStr, _ := regexp.Compile("^([0-9]+|last-as),([0-9]+)$") - group := regStr.FindStringSubmatch(communityStr) - - as := group[1] - if as != "last-as" { - _, e := strconv.ParseUint(as, 10, 32) - if e != nil { - return nil, fmt.Errorf("%s", "invalid as number") - } + exp := regexp.MustCompile("^([0-9]+|last-as),([0-9]+)$") + elems := exp.FindStringSubmatch(communityStr) + if len(elems) != 3 { + return nil, fmt.Errorf("invalid asprepend action format") } - - repeatn, e := strconv.ParseUint(group[2], 10, 8) - if e != nil { - return nil, fmt.Errorf("%s", "invalid repeat count") + asn, err := strconv.Atoi(elems[1]) + var lastAs bool + if err != nil { + lastAs = true } - - asprependAction := &api.AsPrependAction{ - As: as, - Repeatn: uint32(repeatn), + repeat, err := strconv.Atoi(elems[2]) + if err != nil { + return nil, fmt.Errorf("%s", "invalid repeat count") } - - return asprependAction, nil + return &api.AsPrependAction{ + Asn: uint32(asn), + Repeat: uint32(repeat), + UseLeftMost: lastAs, + }, nil } -func checkMedAction(medStr string) error { - regMed, _ := regexp.Compile("^(\\+|\\-)?([0-9]+)$") - if !regMed.MatchString(medStr) { - e := fmt.Sprintf("invalid format: %s\n", medStr) - e += "please enter the [+|-]<med>" - return fmt.Errorf("%s", e) - } - return nil +func parseMedAction(arg string) (*api.MedAction, error) { + exp := regexp.MustCompile("^(\\+|\\-)?([0-9]+)$") + elems := exp.FindStringSubmatch(arg) + if len(elems) != 3 { + return nil, fmt.Errorf("invalid med action format") + } + typ := int32(table.MED_ACTION_MOD) + if elems[1] == "" { + typ = int32(table.MED_ACTION_REPLACE) + } + value, _ := strconv.Atoi(elems[2]) + return &api.MedAction{ + Type: typ, + Value: int64(value), + }, nil } func checkAsPrependAction(asStr string) error { @@ -1349,15 +1355,14 @@ func parseActions() (*api.Actions, error) { if e != nil { return nil, e } - actions.Community = community } if actionOpts.MedAction != "" { - e := checkMedAction(actionOpts.MedAction) + med, e := parseMedAction(actionOpts.MedAction) if e != nil { return nil, e } - actions.Med = actionOpts.MedAction + actions.Med = med } if actionOpts.AsPathPrependAction != "" { @@ -1380,7 +1385,7 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { var operation api.Operation pd := &api.PolicyDefinition{} if len(eArgs) > 0 { - pd.PolicyDefinitionName = eArgs[0] + pd.Name = eArgs[0] } switch modtype { @@ -1389,7 +1394,7 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { return fmt.Errorf("usage: gobgp policy routepoilcy add <route policy name> <statement name>") } stmt := &api.Statement{ - StatementNeme: eArgs[1], + Name: eArgs[1], } conditions, err := parseConditions() if err != nil { @@ -1402,7 +1407,7 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { stmt.Conditions = conditions stmt.Actions = actions - pd.StatementList = []*api.Statement{stmt} + pd.Statements = []*api.Statement{stmt} operation = api.Operation_ADD case CMD_DEL: @@ -1412,9 +1417,9 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { operation = api.Operation_DEL } else if len(eArgs) == 2 { stmt := &api.Statement{ - StatementNeme: eArgs[1], + Name: eArgs[1], } - pd.StatementList = []*api.Statement{stmt} + pd.Statements = []*api.Statement{stmt} operation = api.Operation_DEL } case CMD_ALL: diff --git a/packet/bgp.go b/packet/bgp.go index 3687d817..2d049543 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -4473,8 +4473,8 @@ func NewFourOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uin } } -func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { - elems, err := parseRdAndRt(rt) +func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (ExtendedCommunityInterface, error) { + elems, err := parseRdAndRt(com) if err != nil { return nil, err } @@ -4483,18 +4483,22 @@ func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { isTransitive := true switch { case ip.To4() != nil: - return NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, elems[1], uint16(localAdmin), isTransitive), nil + return NewIPv4AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil case elems[6] == "" && elems[7] == "": asn, _ := strconv.Atoi(elems[8]) - return NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, uint16(asn), uint32(localAdmin), isTransitive), nil + return NewTwoOctetAsSpecificExtended(subtype, uint16(asn), uint32(localAdmin), isTransitive), nil default: fst, _ := strconv.Atoi(elems[7]) snd, _ := strconv.Atoi(elems[8]) asn := fst<<16 | snd - return NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, uint32(asn), uint16(localAdmin), isTransitive), nil + return NewFourOctetAsSpecificExtended(subtype, uint32(asn), uint16(localAdmin), isTransitive), nil } } +func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { + return ParseExtendedCommunity(EC_SUBTYPE_ROUTE_TARGET, rt) +} + type OpaqueExtendedValueInterface interface { Serialize() ([]byte, error) String() string diff --git a/server/grpc_server.go b/server/grpc_server.go index 59d1819c..16b501ec 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -269,7 +269,7 @@ func (s *Server) GetNeighborPolicy(ctx context.Context, arg *api.PolicyArguments switch arg.Resource { case api.Resource_GLOBAL: r = REQ_GLOBAL_POLICY - case api.Resource_POLICY_NEIGHBOR: + case api.Resource_LOCAL: r = REQ_NEIGHBOR_POLICY default: return nil, fmt.Errorf("unsupported resource: %s", arg.Resource) @@ -421,7 +421,7 @@ func (s *Server) GetPolicyRoutePolicies(arg *api.PolicyArguments, stream api.Gob default: return fmt.Errorf("unsupported resource type: %v", arg.Resource) } - req := NewGrpcRequest(reqType, "", rf, nil) + req := NewGrpcRequest(reqType, "", rf, arg) s.bgpServerCh <- req return handleMultipleResponses(req, func(res *GrpcResponse) error { return stream.Send(res.Data.(*api.PolicyDefinition)) @@ -447,7 +447,7 @@ func (s *Server) GetPolicyRoutePolicy(ctx context.Context, arg *api.PolicyArgume default: return nil, fmt.Errorf("unsupported resource type: %v", arg.Resource) } - req := NewGrpcRequest(reqType, "", rf, arg.Name) + req := NewGrpcRequest(reqType, "", rf, arg) s.bgpServerCh <- req res := <-req.ResponseCh diff --git a/server/peer.go b/server/peer.go index dde83b6c..71d07c25 100644 --- a/server/peer.go +++ b/server/peer.go @@ -381,7 +381,7 @@ func (peer *Peer) ToApiStruct() *api.Peer { } } -func (peer *Peer) setPolicy(policyMap map[string]*table.Policy) { +func (peer *Peer) setPolicy(policy map[string]*table.Policy) { policyConf := peer.conf.ApplyPolicy inPolicies := make([]*table.Policy, 0) for _, policyName := range policyConf.ApplyPolicyConfig.InPolicy { @@ -390,15 +390,16 @@ func (peer *Peer) setPolicy(policyMap map[string]*table.Policy) { "Key": peer.conf.NeighborConfig.NeighborAddress, "PolicyName": policyName, }).Info("in-policy installed") - if pol, ok := policyMap[policyName]; ok { + if pol, ok := policy[policyName]; ok { log.Debug("in policy : ", pol) inPolicies = append(inPolicies, pol) } } peer.inPolicies = inPolicies peer.defaultInPolicy = policyConf.ApplyPolicyConfig.DefaultInPolicy - - peer.localRib.SetPolicy(policyConf, policyMap) + if peer.localRib != nil { + peer.localRib.SetPolicy(policyConf, policy) + } } func (peer *Peer) GetPolicy(d table.PolicyDirection) []*table.Policy { diff --git a/server/server.go b/server/server.go index d09d0da1..9f9b70d8 100644 --- a/server/server.go +++ b/server/server.go @@ -87,8 +87,7 @@ type BgpServer struct { GrpcReqCh chan *GrpcRequest listenPort int policyUpdateCh chan config.RoutingPolicy - policyMap map[string]*table.Policy - routingPolicy config.RoutingPolicy + policy *table.RoutingPolicy broadcastReqs []*GrpcRequest broadcastMsgs []broadcastMsg neighborMap map[string]*Peer @@ -354,7 +353,6 @@ func (server *BgpServer) Serve() { peer := NewPeer(g, config) if peer.isRouteServerClient() { - peer.setPolicy(server.policyMap) pathList := make([]*table.Path, 0) rfList := peer.configuredRFlist() for _, p := range server.neighborMap { @@ -400,7 +398,7 @@ func (server *BgpServer) Serve() { peer := server.neighborMap[addr] if peer.isRouteServerClient() { peer.conf.ApplyPolicy = config.ApplyPolicy - peer.setPolicy(server.policyMap) + peer.setPolicy(server.policy.PolicyMap) } case e := <-incoming: peer, found := server.neighborMap[e.MsgSrc] @@ -865,15 +863,19 @@ func (server *BgpServer) UpdatePolicy(policy config.RoutingPolicy) { server.policyUpdateCh <- policy } -func (server *BgpServer) SetPolicy(pl config.RoutingPolicy) { - pMap := make(map[string]*table.Policy) - df := pl.DefinedSets - for _, p := range pl.PolicyDefinitions.PolicyDefinitionList { - pMap[p.Name] = table.NewPolicy(p, df) +func (server *BgpServer) SetPolicy(pl config.RoutingPolicy) error { + p, err := table.NewRoutingPolicy(pl) + if err != nil { + log.WithFields(log.Fields{ + "Topic": "Policy", + }).Debugf("failed to create routing policy: %s", err) + return err } - server.policyMap = pMap - server.routingPolicy = pl - server.globalRib.SetPolicy(server.bgpConfig.Global.ApplyPolicy, server.policyMap) + server.policy = p + if server.globalRib != nil { + server.globalRib.SetPolicy(server.bgpConfig.Global.ApplyPolicy, server.policy.PolicyMap) + } + return nil } func (server *BgpServer) handlePolicy(pl config.RoutingPolicy) { @@ -883,7 +885,7 @@ func (server *BgpServer) handlePolicy(pl config.RoutingPolicy) { "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, }).Info("call set policy") - peer.setPolicy(server.policyMap) + peer.setPolicy(server.policy.PolicyMap) } } @@ -1555,12 +1557,11 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { case REQ_NEIGHBOR_POLICY: peer, err := server.checkNeighborRequest(grpcReq) if err != nil { - break + return msgs } applyPolicy = peer.conf.ApplyPolicy case REQ_GLOBAL_RIB: applyPolicy = server.bgpConfig.Global.ApplyPolicy - default: } switch arg.ApplyPolicy.Type { case api.PolicyType_IMPORT: @@ -1580,21 +1581,16 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } } policies := make([]*api.PolicyDefinition, 0, len(names)) - - pdList := server.routingPolicy.PolicyDefinitions.PolicyDefinitionList - df := server.routingPolicy.DefinedSets for _, name := range names { - match := false - for _, pd := range pdList { - if name == pd.Name { - match = true - policies = append(policies, table.PolicyDefinitionToApiStruct(pd, df)) - break - } - } - if !match { - policies = append(policies, &api.PolicyDefinition{PolicyDefinitionName: name}) + p, ok := server.policy.PolicyMap[name] + if !ok { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Name": name, + }).Error("can't find policy which is applied") + continue } + policies = append(policies, p.ToApiStruct()) } result := &GrpcResponse{ @@ -1613,7 +1609,6 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } result := &GrpcResponse{} arg := grpcReq.Data.(*api.PolicyArguments) - reqPolicyMap := server.policyMap applyPolicy := peer.conf.ApplyPolicy.ApplyPolicyConfig def := config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE switch arg.Operation { @@ -1645,15 +1640,14 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { applyPolicy.InPolicy = []string{} } } - peer.setPolicy(reqPolicyMap) + peer.setPolicy(server.policy.PolicyMap) grpcReq.ResponseCh <- result close(grpcReq.ResponseCh) case REQ_POLICY_PREFIXES, REQ_POLICY_NEIGHBORS, REQ_POLICY_ASPATHS, - REQ_POLICY_COMMUNITIES, REQ_POLICY_EXTCOMMUNITIES, REQ_POLICY_ROUTEPOLICIES: - server.handleGrpcShowPolicies(grpcReq) - case REQ_POLICY_PREFIX, REQ_POLICY_NEIGHBOR, REQ_POLICY_ASPATH, + REQ_POLICY_COMMUNITIES, REQ_POLICY_EXTCOMMUNITIES, REQ_POLICY_ROUTEPOLICIES, + REQ_POLICY_PREFIX, REQ_POLICY_NEIGHBOR, REQ_POLICY_ASPATH, REQ_POLICY_COMMUNITY, REQ_POLICY_EXTCOMMUNITY, REQ_POLICY_ROUTEPOLICY: server.handleGrpcShowPolicy(grpcReq) case REQ_MONITOR_GLOBAL_BEST_CHANGED, REQ_MONITOR_NEIGHBOR_PEER_STATE: @@ -1678,100 +1672,137 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { return msgs } -func (server *BgpServer) handleGrpcShowPolicies(grpcReq *GrpcRequest) { +func (server *BgpServer) handleGrpcShowPolicy(grpcReq *GrpcRequest) { result := &GrpcResponse{} - switch grpcReq.RequestType { - case REQ_POLICY_PREFIXES: - info := server.routingPolicy.DefinedSets.PrefixSets.PrefixSetList + typ := grpcReq.RequestType + arg := grpcReq.Data.(*api.PolicyArguments) + switch typ { + case REQ_POLICY_PREFIX, REQ_POLICY_PREFIXES: + info := server.policy.DefinedSetMap[table.DEFINED_TYPE_PREFIX] if len(info) > 0 { for _, ps := range info { - resPrefixSet := table.PrefixSetToApiStruct(ps) + if typ == REQ_POLICY_PREFIX && ps.Name() != arg.Name { + continue + } + resPrefixSet := ps.(*table.PrefixSet).ToApiStruct() pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchPrefixSet: resPrefixSet}}} + pd.Statements = []*api.Statement{{Conditions: &api.Conditions{PrefixSet: resPrefixSet}}} result = &GrpcResponse{ Data: pd, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_PREFIX { + break + } } } else { result.ResponseErr = fmt.Errorf("Policy prefix doesn't exist.") grpcReq.ResponseCh <- result } - case REQ_POLICY_NEIGHBORS: - info := server.routingPolicy.DefinedSets.NeighborSets.NeighborSetList + case REQ_POLICY_NEIGHBOR, REQ_POLICY_NEIGHBORS: + info := server.policy.DefinedSetMap[table.DEFINED_TYPE_NEIGHBOR] if len(info) > 0 { for _, ns := range info { - resNeighborSet := table.NeighborSetToApiStruct(ns) + if typ == REQ_POLICY_NEIGHBOR && ns.Name() != arg.Name { + continue + } + resNeighborSet := ns.(*table.NeighborSet).ToApiStruct() pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchNeighborSet: resNeighborSet}}} + pd.Statements = []*api.Statement{{Conditions: &api.Conditions{NeighborSet: resNeighborSet}}} result = &GrpcResponse{ Data: pd, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_NEIGHBOR { + break + } } } else { result.ResponseErr = fmt.Errorf("Policy neighbor doesn't exist.") grpcReq.ResponseCh <- result } - case REQ_POLICY_ASPATHS: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.AsPathSets.AsPathSetList + case REQ_POLICY_ASPATH, REQ_POLICY_ASPATHS: + info := server.policy.DefinedSetMap[table.DEFINED_TYPE_AS_PATH] if len(info) > 0 { for _, as := range info { - resAsPathSet := table.AsPathSetToApiStruct(as) + if typ == REQ_POLICY_ASPATH && as.Name() != arg.Name { + continue + } + resAsPathSet := as.(*table.AsPathSet).ToApiStruct() pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchAsPathSet: resAsPathSet}}} + pd.Statements = []*api.Statement{{Conditions: &api.Conditions{AsPathSet: resAsPathSet}}} result = &GrpcResponse{ Data: pd, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_ASPATH { + break + } } } else { result.ResponseErr = fmt.Errorf("Policy aspath doesn't exist.") grpcReq.ResponseCh <- result } - case REQ_POLICY_COMMUNITIES: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySets.CommunitySetList + case REQ_POLICY_COMMUNITY, REQ_POLICY_COMMUNITIES: + info := server.policy.DefinedSetMap[table.DEFINED_TYPE_COMMUNITY] if len(info) > 0 { for _, cs := range info { - resCommunitySet := table.CommunitySetToApiStruct(cs) + if typ == REQ_POLICY_COMMUNITY && cs.Name() != arg.Name { + continue + } + resCommunitySet := cs.(*table.CommunitySet).ToApiStruct() pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchCommunitySet: resCommunitySet}}} + pd.Statements = []*api.Statement{{Conditions: &api.Conditions{CommunitySet: resCommunitySet}}} result = &GrpcResponse{ Data: pd, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_COMMUNITY { + break + } } } else { result.ResponseErr = fmt.Errorf("Policy community doesn't exist.") grpcReq.ResponseCh <- result } - case REQ_POLICY_EXTCOMMUNITIES: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.ExtCommunitySets.ExtCommunitySetList + case REQ_POLICY_EXTCOMMUNITY, REQ_POLICY_EXTCOMMUNITIES: + info := server.policy.DefinedSetMap[table.DEFINED_TYPE_EXT_COMMUNITY] if len(info) > 0 { for _, es := range info { - resExtcommunitySet := table.ExtCommunitySetToApiStruct(es) + if typ == REQ_POLICY_EXTCOMMUNITY && es.Name() != arg.Name { + continue + } + resExtcommunitySet := es.(*table.ExtCommunitySet).ToApiStruct() pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchExtCommunitySet: resExtcommunitySet}}} + pd.Statements = []*api.Statement{{Conditions: &api.Conditions{ExtCommunitySet: resExtcommunitySet}}} result = &GrpcResponse{ Data: pd, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_EXTCOMMUNITY { + break + } } } else { result.ResponseErr = fmt.Errorf("Policy extended community doesn't exist.") grpcReq.ResponseCh <- result } - case REQ_POLICY_ROUTEPOLICIES: - info := server.routingPolicy.PolicyDefinitions.PolicyDefinitionList - df := server.routingPolicy.DefinedSets + case REQ_POLICY_ROUTEPOLICY, REQ_POLICY_ROUTEPOLICIES: + info := server.policy.PolicyMap result := &GrpcResponse{} if len(info) > 0 { for _, pd := range info { - resPolicyDefinition := table.PolicyDefinitionToApiStruct(pd, df) + if typ == REQ_POLICY_ROUTEPOLICY && pd.Name() != arg.Name { + continue + } + resPolicyDefinition := pd.ToApiStruct() result = &GrpcResponse{ Data: resPolicyDefinition, } grpcReq.ResponseCh <- result + if typ == REQ_POLICY_ROUTEPOLICY { + break + } } } else { result.ResponseErr = fmt.Errorf("Route Policy doesn't exist.") @@ -1780,121 +1811,6 @@ func (server *BgpServer) handleGrpcShowPolicies(grpcReq *GrpcRequest) { } close(grpcReq.ResponseCh) } -func (server *BgpServer) handleGrpcShowPolicy(grpcReq *GrpcRequest) { - name := grpcReq.Data.(string) - result := &GrpcResponse{} - switch grpcReq.RequestType { - case REQ_POLICY_PREFIX: - info := server.routingPolicy.DefinedSets.PrefixSets.PrefixSetList - resPrefixSet := &api.PrefixSet{} - for _, ps := range info { - if ps.PrefixSetName == name { - resPrefixSet = table.PrefixSetToApiStruct(ps) - break - } - } - if len(resPrefixSet.PrefixList) > 0 { - pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchPrefixSet: resPrefixSet}}} - result = &GrpcResponse{ - Data: pd, - } - } else { - result.ResponseErr = fmt.Errorf("policy prefix that has %v doesn't exist.", name) - } - case REQ_POLICY_NEIGHBOR: - info := server.routingPolicy.DefinedSets.NeighborSets.NeighborSetList - resNeighborSet := &api.NeighborSet{} - for _, ns := range info { - if ns.NeighborSetName == name { - resNeighborSet = table.NeighborSetToApiStruct(ns) - break - } - } - if len(resNeighborSet.NeighborList) > 0 { - pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchNeighborSet: resNeighborSet}}} - result = &GrpcResponse{ - Data: pd, - } - } else { - result.ResponseErr = fmt.Errorf("policy neighbor that has %v doesn't exist.", name) - } - case REQ_POLICY_ASPATH: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.AsPathSets.AsPathSetList - resAsPathSet := &api.AsPathSet{} - for _, as := range info { - if as.AsPathSetName == name { - resAsPathSet = table.AsPathSetToApiStruct(as) - break - } - } - if len(resAsPathSet.AsPathMembers) > 0 { - pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchAsPathSet: resAsPathSet}}} - result = &GrpcResponse{ - Data: pd, - } - } else { - result.ResponseErr = fmt.Errorf("policy aspath that has %v doesn't exist.", name) - } - case REQ_POLICY_COMMUNITY: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySets.CommunitySetList - resCommunitySet := &api.CommunitySet{} - for _, cs := range info { - if cs.CommunitySetName == name { - resCommunitySet = table.CommunitySetToApiStruct(cs) - break - } - } - if len(resCommunitySet.CommunityMembers) > 0 { - pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchCommunitySet: resCommunitySet}}} - result = &GrpcResponse{ - Data: pd, - } - } else { - result.ResponseErr = fmt.Errorf("policy community that has %v doesn't exist.", name) - } - case REQ_POLICY_EXTCOMMUNITY: - info := server.routingPolicy.DefinedSets.BgpDefinedSets.ExtCommunitySets.ExtCommunitySetList - resExtCommunitySet := &api.ExtCommunitySet{} - for _, es := range info { - if es.ExtCommunitySetName == name { - resExtCommunitySet = table.ExtCommunitySetToApiStruct(es) - break - } - } - if len(resExtCommunitySet.ExtCommunityMembers) > 0 { - pd := &api.PolicyDefinition{} - pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchExtCommunitySet: resExtCommunitySet}}} - result = &GrpcResponse{ - Data: pd, - } - } else { - result.ResponseErr = fmt.Errorf("policy extended community that has %v doesn't exist.", name) - } - case REQ_POLICY_ROUTEPOLICY: - info := server.routingPolicy.PolicyDefinitions.PolicyDefinitionList - df := server.routingPolicy.DefinedSets - resPolicyDefinition := &api.PolicyDefinition{} - for _, pd := range info { - if pd.Name == name { - resPolicyDefinition = table.PolicyDefinitionToApiStruct(pd, df) - break - } - } - if len(resPolicyDefinition.StatementList) > 0 { - result = &GrpcResponse{ - Data: resPolicyDefinition, - } - } else { - result.ResponseErr = fmt.Errorf("Route Policy that has %v doesn't exist.", name) - } - } - grpcReq.ResponseCh <- result - close(grpcReq.ResponseCh) -} func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) { now := uint32(time.Now().Unix()) diff --git a/table/path.go b/table/path.go index b45b7f68..bcf5b4ce 100644 --- a/table/path.go +++ b/table/path.go @@ -556,16 +556,7 @@ func (path *Path) GetExtCommunities() []bgp.ExtendedCommunityInterface { return eCommunityList } -func (path *Path) SetExtCommunities(values []byte, doReplace bool) { - exts := []bgp.ExtendedCommunityInterface{} - for len(values) >= 8 { - e := &bgp.UnknownExtended{ - Type: bgp.BGPAttrType(values[0]), - Value: values[1:8], - } - exts = append(exts, e) - values = values[8:] - } +func (path *Path) SetExtCommunities(exts []bgp.ExtendedCommunityInterface, doReplace bool) { idx, attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES) if attr != nil { l := attr.(*bgp.PathAttributeExtendedCommunities).Value diff --git a/table/policy.go b/table/policy.go index bec56e07..6d33a35f 100644 --- a/table/policy.go +++ b/table/policy.go @@ -24,11 +24,22 @@ import ( "strings" log "github.com/Sirupsen/logrus" - "github.com/osrg/gobgp/api" + api "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" ) +type DefinedType int + +const ( + DEFINED_TYPE_PREFIX DefinedType = iota + DEFINED_TYPE_NEIGHBOR + DEFINED_TYPE_TAG + DEFINED_TYPE_AS_PATH + DEFINED_TYPE_COMMUNITY + DEFINED_TYPE_EXT_COMMUNITY +) + type RouteType int const ( @@ -37,38 +48,76 @@ const ( ROUTE_TYPE_REJECT ) -func (t RouteType) String() string { - switch t { - case ROUTE_TYPE_NONE: - return "NONE" - case ROUTE_TYPE_ACCEPT: - return "ACCEPT" - case ROUTE_TYPE_REJECT: - return "REJECT" - default: - return fmt.Sprintf("Unknown(%d)", t) - } -} +type PolicyDirection int + +const ( + POLICY_DIRECTION_IMPORT PolicyDirection = iota + POLICY_DIRECTION_EXPORT + POLICY_DIRECTION_IN +) -func (t RouteType) ToApiStruct() gobgpapi.RouteAction { - switch t { - case ROUTE_TYPE_ACCEPT: - return gobgpapi.RouteAction_ACCEPT - case ROUTE_TYPE_REJECT: - return gobgpapi.RouteAction_REJECT +type MatchOption int + +const ( + MATCH_OPTION_ANY MatchOption = iota + MATCH_OPTION_ALL + MATCH_OPTION_INVERT +) + +func (o MatchOption) String() string { + switch o { + case MATCH_OPTION_ANY: + return "any" + case MATCH_OPTION_ALL: + return "all" + case MATCH_OPTION_INVERT: + return "invert" default: - return gobgpapi.RouteAction_NONE + return fmt.Sprintf("MatchOption(%d)", o) } } -type PolicyDirection int +type MedActionType int const ( - POLICY_DIRECTION_IN = iota - POLICY_DIRECTION_IMPORT = iota - POLICY_DIRECTION_EXPORT + MED_ACTION_MOD MedActionType = iota + MED_ACTION_REPLACE ) +var CommunityOptionNameMap = map[config.BgpSetCommunityOptionType]string{ + config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: "add", + config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: "remove", + config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: "replace", +} + +var CommunityOptionValueMap = map[string]config.BgpSetCommunityOptionType{ + CommunityOptionNameMap[config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD]: config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD, + CommunityOptionNameMap[config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE]: config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE, + CommunityOptionNameMap[config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE]: config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE, +} + +func NewMatchOption(c interface{}) (MatchOption, error) { + switch c.(type) { + case config.MatchSetOptionsType: + switch c.(config.MatchSetOptionsType) { + case config.MATCH_SET_OPTIONS_TYPE_ANY: + return MATCH_OPTION_ANY, nil + case config.MATCH_SET_OPTIONS_TYPE_ALL: + return MATCH_OPTION_ALL, nil + case config.MATCH_SET_OPTIONS_TYPE_INVERT: + return MATCH_OPTION_INVERT, nil + } + case config.MatchSetOptionsRestrictedType: + switch c.(config.MatchSetOptionsRestrictedType) { + case config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY: + return MATCH_OPTION_ANY, nil + case config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT: + return MATCH_OPTION_INVERT, nil + } + } + return MATCH_OPTION_ANY, fmt.Errorf("invalid argument to create match option: %v", c) +} + type AttributeComparison int const ( @@ -80,196 +129,411 @@ const ( ATTRIBUTE_LE ) -type Policy struct { - Name string - Statements []*Statement +const ( + ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)" +) + +type DefinedSet interface { + Type() DefinedType + Name() string +} + +type DefinedSetMap map[DefinedType]map[string]DefinedSet + +type Prefix struct { + Prefix *net.IPNet + AddressFamily bgp.RouteFamily + MasklengthRangeMax uint8 + MasklengthRangeMin uint8 } -func NewPolicy(pd config.PolicyDefinition, ds config.DefinedSets) *Policy { - stmtList := pd.Statements.StatementList - st := make([]*Statement, 0) - p := &Policy{ - Name: pd.Name, +func (p *Prefix) Match(path *Path) bool { + rf := path.GetRouteFamily() + if rf != p.AddressFamily { + return false } - for _, statement := range stmtList { - conditions := make([]Condition, 0) + var pAddr net.IP + var pMasklen uint8 + switch rf { + case bgp.RF_IPv4_UC: + pAddr = path.GetNlri().(*bgp.IPAddrPrefix).Prefix + pMasklen = path.GetNlri().(*bgp.IPAddrPrefix).Length + case bgp.RF_IPv6_UC: + pAddr = path.GetNlri().(*bgp.IPv6AddrPrefix).Prefix + pMasklen = path.GetNlri().(*bgp.IPv6AddrPrefix).Length + default: + return false + } - // prefix match - pc := NewPrefixCondition(statement.Conditions.MatchPrefixSet, ds.PrefixSets.PrefixSetList) - if pc != nil { - conditions = append(conditions, pc) - } + return (p.MasklengthRangeMin <= pMasklen && pMasklen <= p.MasklengthRangeMax) && p.Prefix.Contains(pAddr) +} - // neighbor match - nc := NewNeighborCondition(statement.Conditions.MatchNeighborSet, ds.NeighborSets.NeighborSetList) - if nc != nil { - conditions = append(conditions, nc) - } +func (p *Prefix) ToApiStruct() *api.Prefix { + return &api.Prefix{ + IpPrefix: p.Prefix.String(), + MaskLengthRange: fmt.Sprintf("%d..%d", p.MasklengthRangeMin, p.MasklengthRangeMax), + } +} - // AsPathLengthCondition - c := statement.Conditions.BgpConditions.AsPathLength - ac := NewAsPathLengthCondition(c) - if ac != nil { - conditions = append(conditions, ac) - } +func NewPrefix(c config.Prefix) (*Prefix, error) { + addr, prefix, err := net.ParseCIDR(c.IpPrefix) + if err != nil { + return nil, err + } - if statement.Conditions.BgpConditions.RpkiValidationResult != config.RPKI_VALIDATION_RESULT_TYPE_NONE { - conditions = append(conditions, NewRPKIValidationCondition(statement.Conditions.BgpConditions.RpkiValidationResult)) + rf := bgp.RF_IPv4_UC + if addr.To4() == nil { + rf = bgp.RF_IPv6_UC + } + p := &Prefix{ + Prefix: prefix, + AddressFamily: rf, + } + maskRange := c.MasklengthRange + if maskRange == "" { + l, _ := prefix.Mask.Size() + maskLength := uint8(l) + p.MasklengthRangeMax = maskLength + p.MasklengthRangeMin = maskLength + } else { + exp := regexp.MustCompile("(\\d+)\\.\\.(\\d+)") + elems := exp.FindStringSubmatch(maskRange) + if len(elems) != 3 { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Type": "Prefix", + "MaskRangeFormat": maskRange, + }).Warn("mask length range format is invalid.") + return nil, fmt.Errorf("mask length range format is invalid") } + // we've already checked the range is sane by regexp + min, _ := strconv.Atoi(elems[1]) + max, _ := strconv.Atoi(elems[2]) + p.MasklengthRangeMin = uint8(min) + p.MasklengthRangeMax = uint8(max) + } + return p, nil +} - bgpDefset := &ds.BgpDefinedSets - bgpConditions := &statement.Conditions.BgpConditions - // AsPathCondition - asc := NewAsPathCondition(bgpConditions.MatchAsPathSet, bgpDefset.AsPathSets.AsPathSetList) - if asc != nil { - conditions = append(conditions, asc) - } +type PrefixSet struct { + name string + list []*Prefix +} - // CommunityCondition - cc := NewCommunityCondition(bgpConditions.MatchCommunitySet, bgpDefset.CommunitySets.CommunitySetList) - if cc != nil { - conditions = append(conditions, cc) - } +func (s *PrefixSet) Name() string { + return s.name +} - // ExtendedCommunityCondition - ecc := NewExtCommunityCondition(bgpConditions.MatchExtCommunitySet, bgpDefset.ExtCommunitySets.ExtCommunitySetList) - if ecc != nil { - conditions = append(conditions, ecc) - } +func (s *PrefixSet) Type() DefinedType { + return DEFINED_TYPE_PREFIX +} - // routing action - ra := NewRoutingAction(statement.Actions) +func (s *PrefixSet) ToApiStruct() *api.PrefixSet { + list := make([]*api.Prefix, 0, len(s.list)) + for _, p := range s.list { + list = append(list, p.ToApiStruct()) + } + return &api.PrefixSet{ + Name: s.name, + List: list, + } +} - // Community action - mda := make([]Action, 0) - com := NewCommunityAction(statement.Actions.BgpActions.SetCommunity) - if com != nil { - mda = append(mda, com) +func NewPrefixSet(c config.PrefixSet) (*PrefixSet, error) { + name := c.PrefixSetName + if name == "" { + if len(c.PrefixList) == 0 { + return nil, nil } - - ext := NewExtCommunityAction(statement.Actions.BgpActions.SetExtCommunity) - if ext != nil { - mda = append(mda, ext) + return nil, fmt.Errorf("empty prefix set name") + } + list := make([]*Prefix, 0, len(c.PrefixList)) + for _, x := range c.PrefixList { + y, err := NewPrefix(x) + if err != nil { + return nil, err } + list = append(list, y) + } + return &PrefixSet{ + name: name, + list: list, + }, nil +} - // Med Action - med := NewMedAction(statement.Actions.BgpActions.SetMed) - if med != nil { - mda = append(mda, med) - } +type NeighborSet struct { + name string + list []net.IP +} - //AsPathPrependAction - ppa := NewAsPathPrependAction(statement.Actions.BgpActions.SetAsPathPrepend) - if ppa != nil { - mda = append(mda, ppa) - } +func (s *NeighborSet) Name() string { + return s.name +} + +func (s *NeighborSet) Type() DefinedType { + return DEFINED_TYPE_NEIGHBOR +} + +func (s *NeighborSet) ToApiStruct() *api.MatchSet { + list := make([]string, 0, len(s.list)) + for _, n := range s.list { + list = append(list, n.String()) + } + return &api.MatchSet{ + Name: s.name, + List: list, + } +} - s := &Statement{ - Name: statement.Name, - Conditions: conditions, - routingAction: ra, - modificationActions: mda, +func NewNeighborSet(c config.NeighborSet) (*NeighborSet, error) { + name := c.NeighborSetName + if name == "" { + if len(c.NeighborInfoList) == 0 { + return nil, nil } + return nil, fmt.Errorf("empty neighbor set name") + } + list := make([]net.IP, 0, len(c.NeighborInfoList)) + for _, x := range c.NeighborInfoList { + list = append(list, x.Address) + } + return &NeighborSet{ + name: name, + list: list, + }, nil +} - st = append(st, s) +type regExpSet struct { + name string + list []*regexp.Regexp +} + +func (s *regExpSet) Name() string { + return s.name +} + +func (s *regExpSet) ToApiStruct() *api.MatchSet { + list := make([]string, 0, len(s.list)) + for _, exp := range s.list { + list = append(list, exp.String()) + } + return &api.MatchSet{ + Name: s.name, + List: list, } - p.Statements = st - return p } -type Statement struct { - Name string - Conditions []Condition - routingAction *RoutingAction - modificationActions []Action +type AsPathSet struct { + regExpSet } -// evaluate each condition in the statement according to MatchSetOptions -func (s *Statement) evaluate(p *Path) bool { +func (s *AsPathSet) Type() DefinedType { + return DEFINED_TYPE_AS_PATH +} - for _, condition := range s.Conditions { - r := condition.evaluate(p) - if !r { - return false +func NewAsPathSet(c config.AsPathSet) (*AsPathSet, error) { + name := c.AsPathSetName + if name == "" { + if len(c.AsPathList) == 0 { + return nil, nil } + return nil, fmt.Errorf("empty as-path set name") } - return true + list := make([]*regexp.Regexp, 0, len(c.AsPathList)) + for _, x := range c.AsPathList { + exp, err := regexp.Compile(strings.Replace(x.AsPath, "_", ASPATH_REGEXP_MAGIC, -1)) + if err != nil { + return nil, fmt.Errorf("invalid regular expression: %s", x) + } + list = append(list, exp) + } + return &AsPathSet{ + regExpSet: regExpSet{ + name: name, + list: list, + }, + }, nil } -type Condition interface { - evaluate(*Path) bool +type CommunitySet struct { + regExpSet +} + +func (s *CommunitySet) Type() DefinedType { + return DEFINED_TYPE_COMMUNITY } -type DefaultCondition struct { - CallPolicy string +func ParseCommunity(arg string) (uint32, error) { + i, err := strconv.Atoi(arg) + if err == nil { + return uint32(i), nil + } + exp := regexp.MustCompile("(\\d+):(\\d+)") + elems := exp.FindStringSubmatch(arg) + if len(elems) == 3 { + fst, _ := strconv.Atoi(elems[1]) + snd, _ := strconv.Atoi(elems[2]) + return uint32(fst<<16 | snd), nil + } + for i, v := range bgp.WellKnownCommunityNameMap { + if arg == v { + return uint32(i), nil + } + } + return 0, fmt.Errorf("failed to parse %s as community", arg) } -func (c *DefaultCondition) evaluate(path *Path) bool { - return false +func parseExtCommunity(arg string) (bgp.ExtendedCommunityInterface, error) { + var subtype bgp.ExtendedCommunityAttrSubType + elems := strings.SplitN(arg, ":", 2) + if len(elems) < 2 { + return nil, fmt.Errorf("invalid ext-community format([rt|soo]:<value>)") + } + switch strings.ToLower(elems[0]) { + case "rt": + subtype = bgp.EC_SUBTYPE_ROUTE_TARGET + case "soo": + subtype = bgp.EC_SUBTYPE_ROUTE_ORIGIN + default: + return nil, fmt.Errorf("unknown ext-community subtype. rt, soo is supported") + } + return bgp.ParseExtendedCommunity(subtype, elems[1]) } -type PrefixCondition struct { - DefaultCondition - PrefixConditionName string - PrefixList []Prefix - MatchOption config.MatchSetOptionsRestrictedType -} - -func NewPrefixCondition(matchPref config.MatchPrefixSet, defPrefixList []config.PrefixSet) *PrefixCondition { - - prefixSetName := matchPref.PrefixSet - options := matchPref.MatchSetOptions - - prefixList := make([]Prefix, 0) - for _, ps := range defPrefixList { - if ps.PrefixSetName == prefixSetName { - for _, prefix := range ps.PrefixList { - prefix, e := NewPrefix(prefix.IpPrefix, prefix.MasklengthRange) - if e != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "prefix": prefix, - "msg": e, - }).Error("failed to generate a NewPrefix from configration.") - } else { - prefixList = append(prefixList, prefix) - } - } +func parseCommunityRegexp(arg string) (*regexp.Regexp, error) { + i, err := strconv.Atoi(arg) + if err == nil { + return regexp.MustCompile(fmt.Sprintf("^%d:%d$", i>>16, i&0x0000ffff)), nil + } + if regexp.MustCompile("(\\d+.)*\\d+:\\d+").MatchString(arg) { + return regexp.MustCompile(fmt.Sprintf("^%s$", arg)), nil + } + for i, v := range bgp.WellKnownCommunityNameMap { + if strings.Replace(strings.ToLower(arg), "_", "-", -1) == v { + return regexp.MustCompile(fmt.Sprintf("^%d:%d$", i>>16, i&0x0000ffff)), nil } } + exp, err := regexp.Compile(arg) + if err != nil { + return nil, fmt.Errorf("invalid community format: %s", arg) + } + return exp, nil +} + +func parseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *regexp.Regexp, error) { + var subtype bgp.ExtendedCommunityAttrSubType + elems := strings.SplitN(arg, ":", 2) + if len(elems) < 2 { + return subtype, nil, fmt.Errorf("invalid ext-community format([rt|soo]:<value>)") + } + switch strings.ToLower(elems[0]) { + case "rt": + subtype = bgp.EC_SUBTYPE_ROUTE_TARGET + case "soo": + subtype = bgp.EC_SUBTYPE_ROUTE_ORIGIN + default: + return subtype, nil, fmt.Errorf("unknown ext-community subtype. rt, soo is supported") + } + exp, err := parseCommunityRegexp(elems[1]) + return subtype, exp, err +} - if len(prefixList) == 0 { - return nil +func NewCommunitySet(c config.CommunitySet) (*CommunitySet, error) { + name := c.CommunitySetName + if name == "" { + if len(c.CommunityList) == 0 { + return nil, nil + } + return nil, fmt.Errorf("empty community set name") } + list := make([]*regexp.Regexp, 0, len(c.CommunityList)) + for _, x := range c.CommunityList { + exp, err := parseCommunityRegexp(x.Community) + if err != nil { + return nil, err + } + list = append(list, exp) + } + return &CommunitySet{ + regExpSet: regExpSet{ + name: name, + list: list, + }, + }, nil +} + +type ExtCommunitySet struct { + regExpSet + subtypeList []bgp.ExtendedCommunityAttrSubType +} - pc := &PrefixCondition{ - PrefixConditionName: prefixSetName, - PrefixList: prefixList, - MatchOption: options, +func (s *ExtCommunitySet) Type() DefinedType { + return DEFINED_TYPE_EXT_COMMUNITY +} + +func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) { + name := c.ExtCommunitySetName + if name == "" { + if len(c.ExtCommunityList) == 0 { + return nil, nil + } + return nil, fmt.Errorf("empty ext-community set name") + } + list := make([]*regexp.Regexp, 0, len(c.ExtCommunityList)) + subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(c.ExtCommunityList)) + for _, x := range c.ExtCommunityList { + subtype, exp, err := parseExtCommunityRegexp(x.ExtCommunity) + if err != nil { + return nil, err + } + list = append(list, exp) + subtypeList = append(subtypeList, subtype) } + return &ExtCommunitySet{ + regExpSet: regExpSet{ + name: name, + list: list, + }, + subtypeList: subtypeList, + }, nil +} + +type Condition interface { + Evaluate(*Path) bool +} + +type PrefixCondition struct { + set *PrefixSet + option MatchOption +} + +func (c *PrefixCondition) Set() DefinedSet { + return c.set +} - return pc +func (c *PrefixCondition) Option() MatchOption { + return c.option } // compare prefixes in this condition and nlri of path and // subsequent comparison is skipped if that matches the conditions. // If PrefixList's length is zero, return true. -func (c *PrefixCondition) evaluate(path *Path) bool { +func (c *PrefixCondition) Evaluate(path *Path) bool { - if len(c.PrefixList) == 0 { + if len(c.set.list) == 0 { log.Debug("PrefixList doesn't have elements") return true } result := false - for _, cp := range c.PrefixList { - if ipPrefixCalculate(path, cp) { + for _, p := range c.set.list { + if p.Match(path) { result = true break } } - if c.MatchOption == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT { + if c.option == MATCH_OPTION_INVERT { result = !result } @@ -278,51 +542,58 @@ func (c *PrefixCondition) evaluate(path *Path) bool { "Condition": "prefix", "Path": path, "Matched": result, - }).Debug("evaluate prefix") + }).Debug("evaluation result") return result } -type NeighborCondition struct { - DefaultCondition - NeighborConditionName string - NeighborList []net.IP - MatchOption config.MatchSetOptionsRestrictedType +func (c *PrefixCondition) ToApiStruct() *api.PrefixSet { + s := c.set.ToApiStruct() + s.Option = int32(c.option) + return s } -func NewNeighborCondition(matchNeighborSet config.MatchNeighborSet, defNeighborSetList []config.NeighborSet) *NeighborCondition { - - neighborSetName := matchNeighborSet.NeighborSet - options := matchNeighborSet.MatchSetOptions - - neighborList := make([]net.IP, 0) - for _, neighborSet := range defNeighborSetList { - if neighborSet.NeighborSetName == neighborSetName { - for _, nl := range neighborSet.NeighborInfoList { - neighborList = append(neighborList, nl.Address) - } - } +func NewPrefixCondition(c config.MatchPrefixSet, m map[string]DefinedSet) (*PrefixCondition, error) { + if c.PrefixSet == "" { + return nil, nil } - - if len(neighborList) == 0 { - return nil + i, ok := m[c.PrefixSet] + if !ok { + return nil, fmt.Errorf("not found prefix set %s", c.PrefixSet) } - - nc := &NeighborCondition{ - NeighborConditionName: neighborSetName, - NeighborList: neighborList, - MatchOption: options, + s, ok := i.(*PrefixSet) + if !ok { + return nil, fmt.Errorf("type assert from DefinedSet to *PrefixSet failed") + } + o, err := NewMatchOption(c.MatchSetOptions) + if err != nil { + return nil, err } + return &PrefixCondition{ + set: s, + option: o, + }, nil +} + +type NeighborCondition struct { + set *NeighborSet + option MatchOption +} + +func (c *NeighborCondition) Set() DefinedSet { + return c.set +} - return nc +func (c *NeighborCondition) Option() MatchOption { + return c.option } // compare neighbor ipaddress of this condition and source address of path // and, subsequent comparisons are skipped if that matches the conditions. // If NeighborList's length is zero, return true. -func (c *NeighborCondition) evaluate(path *Path) bool { +func (c *NeighborCondition) Evaluate(path *Path) bool { - if len(c.NeighborList) == 0 { + if len(c.set.list) == 0 { log.Debug("NeighborList doesn't have elements") return true } @@ -331,14 +602,14 @@ func (c *NeighborCondition) evaluate(path *Path) bool { return false } result := false - for _, neighbor := range c.NeighborList { - if path.Owner.Equal(neighbor) { + for _, n := range c.set.list { + if path.Owner.Equal(n) { result = true break } } - if c.MatchOption == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT { + if c.option == MATCH_OPTION_INVERT { result = !result } @@ -347,774 +618,370 @@ func (c *NeighborCondition) evaluate(path *Path) bool { "Condition": "neighbor", "NeighborAddress": path.Owner, "Matched": result, - }).Debug("evaluate neighbor") + }).Debug("evaluation result") return result } -type AsPathLengthCondition struct { - DefaultCondition - Value uint32 - Operator AttributeComparison +func (c *NeighborCondition) ToApiStruct() *api.MatchSet { + s := c.set.ToApiStruct() + s.Option = int32(c.option) + return s } -// create AsPathLengthCondition object -func NewAsPathLengthCondition(defAsPathLength config.AsPathLength) *AsPathLengthCondition { - - value := defAsPathLength.Value - var op AttributeComparison - - switch defAsPathLength.Operator { - case "eq": - op = ATTRIBUTE_EQ - - case "ge": - op = ATTRIBUTE_GE - - case "le": - op = ATTRIBUTE_LE - default: - return nil +func NewNeighborCondition(c config.MatchNeighborSet, m map[string]DefinedSet) (*NeighborCondition, error) { + if c.NeighborSet == "" { + return nil, nil } - - ac := &AsPathLengthCondition{ - Value: value, - Operator: op, + i, ok := m[c.NeighborSet] + if !ok { + return nil, fmt.Errorf("not found neighbor set %s", c.NeighborSet) } - - return ac -} - -// compare AS_PATH length in the message's AS_PATH attribute with -// the one in condition. -func (c *AsPathLengthCondition) evaluate(path *Path) bool { - - length := uint32(path.GetAsPathLen()) - result := false - - switch c.Operator { - case ATTRIBUTE_EQ: - result = c.Value == length - - case ATTRIBUTE_GE: - result = c.Value <= length - - case ATTRIBUTE_LE: - result = c.Value >= length - default: - result = false + s, ok := i.(*NeighborSet) + if !ok { + return nil, fmt.Errorf("type assert from DefinedSet to *NeighborSet failed") } - - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "aspath length", - "Reason": c.Operator, - "Matched": result, - }).Debug("evaluate aspath length") - - return result + o, err := NewMatchOption(c.MatchSetOptions) + if err != nil { + return nil, err + } + return &NeighborCondition{ + set: s, + option: o, + }, nil } type AsPathCondition struct { - DefaultCondition - AsRegExpList []*regexp.Regexp - MatchOption config.MatchSetOptionsType + set *AsPathSet + option MatchOption } -const ( - ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)" -) - -func NewAsPathCondition(matchSet config.MatchAsPathSet, defAsPathSetList []config.AsPathSet) *AsPathCondition { - asPathSetName := matchSet.AsPathSet - options := matchSet.MatchSetOptions - - asRegExpList := make([]*regexp.Regexp, 0) - for _, asPathSet := range defAsPathSetList { - if asPathSet.AsPathSetName == asPathSetName { - for _, aspath := range asPathSet.AsPathList { - a := aspath.AsPath - if len(a) != 0 { - r, err := regexp.Compile(strings.Replace(a, "_", ASPATH_REGEXP_MAGIC, -1)) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "AsPath Condition", - "Value": aspath.AsPath, - "Error": err, - }).Error("can not comple AS_PATH values to Regular expressions.") - return nil - } - - asRegExpList = append(asRegExpList, r) - } else { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "AsPath Condition", - }).Error("does not parse AS_PATH condition value.") - return nil - } - } - c := &AsPathCondition{ - AsRegExpList: asRegExpList, - MatchOption: options, - } - return c - } - } - return nil +func (c *AsPathCondition) Set() *AsPathSet { + return c.set } -func (c *AsPathCondition) checkMembers(aspathStr string, checkAll bool) bool { - for _, r := range c.AsRegExpList { - if r.MatchString(aspathStr) { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "aspath length", - "AS": aspathStr, - "ASN": r, - }).Debug("aspath condition matched") - - if !checkAll { - return true - } - } else { - if checkAll { - return false - } - } - } - return checkAll +func (c *AsPathCondition) Option() MatchOption { + return c.option } -// compare AS_PATH in the message's AS_PATH attribute with -// the one in condition. -func (c *AsPathCondition) evaluate(path *Path) bool { - - aspathStr := path.GetAsString() +func (c *AsPathCondition) ToApiStruct() *api.MatchSet { + s := c.set.ToApiStruct() + s.Option = int32(c.option) + return s +} +func (c *AsPathCondition) Evaluate(path *Path) bool { + aspath := path.GetAsString() result := false - if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL { - result = c.checkMembers(aspathStr, true) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY { - result = c.checkMembers(aspathStr, false) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT { - result = !c.checkMembers(aspathStr, false) + for _, r := range c.set.list { + result = false + if r.MatchString(aspath) { + result = true + } + if c.option == MATCH_OPTION_ALL && !result { + break + } + if c.option == MATCH_OPTION_ANY && result { + break + } + } + if c.option == MATCH_OPTION_INVERT { + result = !result } - log.WithFields(log.Fields{ "Topic": "Policy", "Condition": "aspath", - "MatchOption": c.MatchOption, + "MatchOption": c.option, "Matched": result, - }).Debug("evaluate aspath") - + }).Debug("evaluation result") return result } -type CommunityCondition struct { - DefaultCondition - CommunityList []*CommunityElement - MatchOption config.MatchSetOptionsType +func NewAsPathCondition(c config.MatchAsPathSet, m map[string]DefinedSet) (*AsPathCondition, error) { + if c.AsPathSet == "" { + return nil, nil + } + i, ok := m[c.AsPathSet] + if !ok { + return nil, fmt.Errorf("not found as path set %s", c.AsPathSet) + } + s, ok := i.(*AsPathSet) + if !ok { + return nil, fmt.Errorf("type assert from DefinedSet to *AsPathSet failed") + } + o, err := NewMatchOption(c.MatchSetOptions) + if err != nil { + return nil, err + } + return &AsPathCondition{ + set: s, + option: o, + }, nil } -const ( - COMMUNITY_INTERNET string = "INTERNET" - COMMUNITY_NO_EXPORT string = "NO_EXPORT" - COMMUNITY_NO_ADVERTISE string = "NO_ADVERTISE" - COMMUNITY_NO_EXPORT_SUBCONFED string = "NO_EXPORT_SUBCONFED" -) +type CommunityCondition struct { + set *CommunitySet + option MatchOption +} -const ( - COMMUNITY_INTERNET_VAL uint32 = 0x00000000 - COMMUNITY_NO_EXPORT_VAL = 0xFFFFFF01 - COMMUNITY_NO_ADVERTISE_VAL = 0xFFFFFF02 - COMMUNITY_NO_EXPORT_SUBCONFED_VAL = 0xFFFFFF03 -) +func (c *CommunityCondition) Set() *CommunitySet { + return c.set +} -type CommunityElement struct { - community uint32 - communityStr string - isRegExp bool - communityRegExp *regexp.Regexp -} - -// create CommunityCondition object -// CommunityCondition supports uint and string like 65000:100 -// and also supports regular expressions that are available in golang. -// if GoBGP can't parse the regular expression, it return nil and an error message is logged. -func NewCommunityCondition(matchSet config.MatchCommunitySet, defCommunitySetList []config.CommunitySet) *CommunityCondition { - - communitySetName := matchSet.CommunitySet - options := matchSet.MatchSetOptions - - communityList := make([]*CommunityElement, 0) - for _, communitySet := range defCommunitySetList { - if communitySet.CommunitySetName == communitySetName { - for _, community := range communitySet.CommunityList { - c := community.Community - e := &CommunityElement{ - isRegExp: false, - communityStr: c, - } - - if matched, v := getCommunityValue(c); matched { - e.community = v - } else { - // specified by regular expression - e.isRegExp = true - reg, err := regexp.Compile(c) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Condition", - }).Error("Regular expression can't be compiled.") - return nil - } - e.communityRegExp = reg - } - communityList = append(communityList, e) - } +func (c *CommunityCondition) Option() MatchOption { + return c.option +} - c := &CommunityCondition{ - CommunityList: communityList, - MatchOption: options, - } - return c - } - } - return nil +func (c *CommunityCondition) ToApiStruct() *api.MatchSet { + s := c.set.ToApiStruct() + s.Option = int32(c.option) + return s } -// getCommunityValue returns uint32 community value converted from the string. -// if the string doesn't match a number or string like "65000:1000" or well known -// community name, it returns false and 0, otherwise returns true and its uint32 value. -func getCommunityValue(comStr string) (bool, uint32) { - // community regexp - regUint, _ := regexp.Compile("^([0-9]+)$") - regString, _ := regexp.Compile("([0-9]+):([0-9]+)") - regWellKnown, _ := regexp.Compile("^(" + - COMMUNITY_INTERNET + "|" + - COMMUNITY_NO_EXPORT + "|" + - COMMUNITY_NO_ADVERTISE + "|" + - COMMUNITY_NO_EXPORT_SUBCONFED + ")$") - - if regUint.MatchString(comStr) { - // specified by Uint - community, err := strconv.ParseUint(comStr, 10, 32) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Condition", - }).Error("failed to parse the community value.") +func (c *CommunityCondition) Evaluate(path *Path) bool { + cs := path.GetCommunities() + result := false + for _, x := range cs { + result = false + for _, y := range c.set.list { + if y.MatchString(fmt.Sprintf("%d:%d", x>>16, x&0x0000ffff)) { + result = true + break + } } - return true, uint32(community) - - } else if regString.MatchString(comStr) { - // specified by string containing ":" - group := regString.FindStringSubmatch(comStr) - asn, errAsn := strconv.ParseUint(group[1], 10, 16) - val, errVal := strconv.ParseUint(group[2], 10, 16) - - if errAsn != nil || errVal != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Condition", - }).Error("failed to parser as number or community value.") + if c.option == MATCH_OPTION_ALL && !result { + break } - community := uint32(asn<<16 | val) - return true, community - - } else if regWellKnown.MatchString(comStr) { - // specified by well known community name - var community uint32 - switch comStr { - case COMMUNITY_INTERNET: - community = COMMUNITY_INTERNET_VAL - case COMMUNITY_NO_EXPORT: - community = COMMUNITY_NO_EXPORT_VAL - case COMMUNITY_NO_ADVERTISE: - community = COMMUNITY_NO_ADVERTISE_VAL - case COMMUNITY_NO_EXPORT_SUBCONFED: - community = COMMUNITY_NO_EXPORT_SUBCONFED_VAL + if c.option == MATCH_OPTION_ANY && result { + break } - return true, community } - return false, 0 + if c.option == MATCH_OPTION_INVERT { + result = !result + } + log.WithFields(log.Fields{ + "Topic": "Policy", + "Condition": "community", + "MatchOption": c.option, + "Matched": result, + }).Debug("evaluation result") + return result } -func (c *CommunityCondition) checkMembers(communities []uint32, checkAll bool) bool { - - result := false - if checkAll { - result = true +func NewCommunityCondition(c config.MatchCommunitySet, m map[string]DefinedSet) (*CommunityCondition, error) { + if c.CommunitySet == "" { + return nil, nil } - - makeStr := func(c uint32) string { - upper := strconv.FormatUint(uint64(c&0xFFFF0000>>16), 10) - lower := strconv.FormatUint(uint64(c&0x0000FFFF), 10) - return upper + ":" + lower + i, ok := m[c.CommunitySet] + if !ok { + return nil, fmt.Errorf("not found community set %s", c.CommunitySet) } + s, ok := i.(*CommunitySet) + if !ok { + return nil, fmt.Errorf("type assert from DefinedSet to *CommunitySet failed") + } + o, err := NewMatchOption(c.MatchSetOptions) + if err != nil { + return nil, err + } + return &CommunityCondition{ + set: s, + option: o, + }, nil +} - var strCommunities []string = nil - matched := false - idx := -1 - for _, member := range c.CommunityList { - if member.isRegExp { - - if strCommunities == nil { - // create community string. - strCommunities = make([]string, len(communities)) - for i, c := range communities { - strCommunities[i] = makeStr(c) - } - } +type ExtCommunityCondition struct { + set *ExtCommunitySet + option MatchOption +} - for i, c := range strCommunities { - if member.communityRegExp.MatchString(c) { - matched = true - idx = i - log.WithFields(log.Fields{ - "Topic": "Policy", - "RegExp": member.communityRegExp.String(), - }).Debug("community regexp used") - break - } - } +func (c *ExtCommunityCondition) Set() *ExtCommunitySet { + return c.set +} - } else { - for i, c := range communities { - if c == member.community { - matched = true - idx = i - break - } - } - } +func (c *ExtCommunityCondition) Option() MatchOption { + return c.option +} - if matched { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "Community", - "Community": makeStr(communities[idx]), - }).Debug("condition matched") +func (c *ExtCommunityCondition) ToApiStruct() *api.MatchSet { + s := c.set.ToApiStruct() + s.Option = int32(c.option) + return s +} - if !checkAll { +func (c *ExtCommunityCondition) Evaluate(path *Path) bool { + es := path.GetExtCommunities() + result := false + for _, x := range es { + result = false + typ, subtype := x.GetTypes() + // match only with transitive community. see RFC7153 + if typ >= 0x3f { + continue + } + for idx, y := range c.set.list { + if subtype == c.set.subtypeList[idx] && y.MatchString(x.String()) { result = true break } - - } else { - if checkAll { - result = false - break - } + } + if c.option == MATCH_OPTION_ALL && !result { + break + } + if c.option == MATCH_OPTION_ANY && result { + break } } - - return result - -} - -// compare community in the message's attribute with -// the one in the condition. -func (c *CommunityCondition) evaluate(path *Path) bool { - - communities := path.GetCommunities() - - if len(communities) == 0 { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "community", - "MatchOption": c.MatchOption, - "Matched": false, - }).Debug("community length is zero") - return false - } - - result := false - if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL { - result = c.checkMembers(communities, true) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY { - result = c.checkMembers(communities, false) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT { - result = !c.checkMembers(communities, false) + if c.option == MATCH_OPTION_INVERT { + result = !result } log.WithFields(log.Fields{ "Topic": "Policy", "Condition": "community", - "MatchOption": c.MatchOption, + "MatchOption": c.option, "Matched": result, - }).Debug("evaluate community") - + }).Debug("evaluation result") return result } -type ExtCommunityCondition struct { - DefaultCondition - ExtCommunityList []*ExtCommunityElement - MatchOption config.MatchSetOptionsType -} - -type ExtCommunityElement struct { - ecType bgp.ExtendedCommunityAttrType - ecSubType bgp.ExtendedCommunityAttrSubType - globalAdmin interface{} - localAdmin uint32 - comStr string - isRegExp bool - regExp *regexp.Regexp -} - -func NewExtCommunityCondition(matchSet config.MatchExtCommunitySet, defExtComSetList []config.ExtCommunitySet) *ExtCommunityCondition { - - extComSetName := matchSet.ExtCommunitySet - option := matchSet.MatchSetOptions - - extCommunityElemList := make([]*ExtCommunityElement, 0) - for _, extComSet := range defExtComSetList { - if extComSet.ExtCommunitySetName == extComSetName { - for _, ecommunity := range extComSet.ExtCommunityList { - matchAll := false - ec := ecommunity.ExtCommunity - e := &ExtCommunityElement{ - isRegExp: false, - comStr: ec, - } - matchType, val := getECommunitySubType(ec) - if !matchType { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Extended Community Condition", - }).Error("failed to parse the sub type %s.", ec) - return nil - } - switch val[1] { - case "RT": - e.ecSubType = bgp.EC_SUBTYPE_ROUTE_TARGET - case "SoO": - e.ecSubType = bgp.EC_SUBTYPE_ROUTE_ORIGIN - default: - e.ecSubType = bgp.ExtendedCommunityAttrSubType(0xFF) - } - - if matchVal, elem := getECommunityValue(val[2]); matchVal { - if matchElem, ecType, gAdmin := getECommunityElem(elem[1]); matchElem { - e.ecType = ecType - e.globalAdmin = gAdmin - lAdmin, err := strconv.ParseUint(elem[2], 10, 32) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Extended Community Condition", - }).Errorf("failed to parse the local administrator %d.", elem[2]) - return nil - } - e.localAdmin = uint32(lAdmin) - matchAll = true - } - } - if !matchAll { - e.isRegExp = true - reg, err := regexp.Compile(ec) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Extended Community Condition", - }).Errorf("Regular expression can't be compiled %s.", val[2]) - return nil - } - e.regExp = reg - } - extCommunityElemList = append(extCommunityElemList, e) - } - ce := &ExtCommunityCondition{ - ExtCommunityList: extCommunityElemList, - MatchOption: option, - } - return ce - } +func NewExtCommunityCondition(c config.MatchExtCommunitySet, m map[string]DefinedSet) (*ExtCommunityCondition, error) { + if c.ExtCommunitySet == "" { + return nil, nil } - return nil -} - -func getECommunitySubType(eComStr string) (bool, []string) { - regSubType, _ := regexp.Compile("^(RT|SoO):(.*)$") - if regSubType.MatchString(eComStr) { - eComVal := regSubType.FindStringSubmatch(eComStr) - return true, eComVal + i, ok := m[c.ExtCommunitySet] + if !ok { + return nil, fmt.Errorf("not found ext-community set %s", c.ExtCommunitySet) } - return false, nil -} - -func getECommunityValue(eComVal string) (bool, []string) { - regVal, _ := regexp.Compile("^([0-9\\.]+):([0-9]+)$") - if regVal.MatchString(eComVal) { - eComElem := regVal.FindStringSubmatch(eComVal) - return true, eComElem + s, ok := i.(*ExtCommunitySet) + if !ok { + return nil, fmt.Errorf("type assert from DefinedSet to *ExtCommunitySet failed") } - return false, nil + o, err := NewMatchOption(c.MatchSetOptions) + if err != nil { + return nil, err + } + return &ExtCommunityCondition{ + set: s, + option: o, + }, nil } -func getECommunityElem(gAdmin string) (bool, bgp.ExtendedCommunityAttrType, interface{}) { - addr := net.ParseIP(gAdmin) - if addr.To4() != nil { - return true, bgp.EC_TYPE_TRANSITIVE_IP4_SPECIFIC, addr - } - regAs, _ := regexp.Compile("^([0-9]+)$") - if regAs.MatchString(gAdmin) { - as, err := strconv.ParseUint(gAdmin, 10, 16) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Extended Community Condition", - }).Errorf("failed to parse the global administrator %d.", gAdmin) - } - return true, bgp.EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC, uint16(as) - } - regAs4, _ := regexp.Compile("^([0-9]+).([0-9]+)$") - if regAs4.MatchString(gAdmin) { - as4Elem := regAs4.FindStringSubmatch(gAdmin) - highAs, errHigh := strconv.ParseUint(as4Elem[1], 10, 16) - lowAs, errLow := strconv.ParseUint(as4Elem[2], 10, 16) - if errHigh != nil || errLow != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Extended Community Condition", - }).Errorf("failed to parse the global administrator %d.", gAdmin) - } - return true, bgp.EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC, uint32(highAs<<16 | lowAs) - } - return false, bgp.ExtendedCommunityAttrType(0xFF), nil +type AsPathLengthCondition struct { + length uint32 + operator AttributeComparison } -func (c *ExtCommunityCondition) checkMembers(eCommunities []bgp.ExtendedCommunityInterface, checkAll bool) bool { +// compare AS_PATH length in the message's AS_PATH attribute with +// the one in condition. +func (c *AsPathLengthCondition) Evaluate(path *Path) bool { + length := uint32(path.GetAsPathLen()) result := false - if checkAll { - result = true - } - - makeAs4Str := func(ec *ExtCommunityElement) string { - t := ec.ecType - str := fmt.Sprintf("%d", ec.localAdmin) - switch t { - case bgp.EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: - str = fmt.Sprintf("%d:%s", ec.globalAdmin.(uint16), str) - case bgp.EC_TYPE_TRANSITIVE_IP4_SPECIFIC: - str = fmt.Sprintf("%s:%s", ec.globalAdmin.(net.IP).String(), str) - case bgp.EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: - ga := ec.globalAdmin.(uint32) - upper := strconv.FormatUint(uint64(ga&0xFFFF0000>>16), 10) - lower := strconv.FormatUint(uint64(ga&0x0000FFFF), 10) - str = fmt.Sprintf("%s.%s:%s", upper, lower, str) - } - return str + switch c.operator { + case ATTRIBUTE_EQ: + result = c.length == length + case ATTRIBUTE_GE: + result = c.length <= length + case ATTRIBUTE_LE: + result = c.length >= length } - makeTypeSubStr := func(st bgp.ExtendedCommunityAttrSubType) string { - subStr := "" - switch st { - case bgp.EC_SUBTYPE_ROUTE_TARGET: - subStr = "RT" - case bgp.EC_SUBTYPE_ROUTE_ORIGIN: - subStr = "SoO" - } - return subStr - } - - matched := false - matchStr := "" - for _, member := range c.ExtCommunityList { - for _, ec := range eCommunities { - t, st := ec.GetTypes() - if member.isRegExp { - ecString := fmt.Sprintf("%s:%s", makeTypeSubStr(st), ec.String()) - if member.regExp.MatchString(ecString) { - matched = true - log.WithFields(log.Fields{ - "Topic": "Policy", - "RegExp": member.regExp.String(), - }).Debug("extended community regexp used") - matchStr = ec.String() - break - } - } else if member.ecType == t && member.ecSubType == st { - if makeAs4Str(member) == ec.String() { - matched = true - matchStr = ec.String() - break - } - - } - } - if matched { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "Extended Community", - "Extended Community": matchStr, - }).Debug("condition matched") - - if !checkAll { - result = true - break - } + log.WithFields(log.Fields{ + "Topic": "Policy", + "Condition": "aspath length", + "Reason": c.operator, + "Matched": result, + }).Debug("evaluation result") - } else { - if checkAll { - result = false - break - } - } - } return result } -// compare extended community in the message's attribute with -// the one in the condition. -func (c *ExtCommunityCondition) evaluate(path *Path) bool { - - eCommunities := path.GetExtCommunities() - if len(eCommunities) == 0 { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "extended community", - "Matched": false, - "Path": path, - }).Debug("extended community length is zero") - return false +func (c *AsPathLengthCondition) ToApiStruct() *api.AsPathLength { + return &api.AsPathLength{ + Length: c.length, + Type: int32(c.operator), } +} - result := false - if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ALL { - result = c.checkMembers(eCommunities, true) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_ANY { - result = c.checkMembers(eCommunities, false) - } else if c.MatchOption == config.MATCH_SET_OPTIONS_TYPE_INVERT { - result = !c.checkMembers(eCommunities, false) +func NewAsPathLengthCondition(c config.AsPathLength) (*AsPathLengthCondition, error) { + if c.Value == 0 && c.Operator == "" { + return nil, nil } - - log.WithFields(log.Fields{ - "Topic": "Policy", - "Condition": "extended community", - "MatchOption": c.MatchOption, - "Matched": result, - "Path": path, - }).Debug("evaluate extended community") - - return result + var op AttributeComparison + switch strings.ToLower(c.Operator) { + case "eq": + op = ATTRIBUTE_EQ + case "ge": + op = ATTRIBUTE_GE + case "le": + op = ATTRIBUTE_LE + default: + return nil, fmt.Errorf("invalid as path length operator: %s", c.Operator) + } + return &AsPathLengthCondition{ + length: c.Value, + operator: op, + }, nil } -type RPKIValidationCondition struct { +type RpkiValidationCondition struct { result config.RpkiValidationResultType } -func NewRPKIValidationCondition(result config.RpkiValidationResultType) *RPKIValidationCondition { - return &RPKIValidationCondition{ - result: result, - } +func (c *RpkiValidationCondition) Evaluate(path *Path) bool { + return c.result == path.Validation } -func (c *RPKIValidationCondition) evaluate(path *Path) bool { - return c.result == path.Validation +func NewRpkiValidationCondition(c config.RpkiValidationResultType) (*RpkiValidationCondition, error) { + if c == config.RPKI_VALIDATION_RESULT_TYPE_NONE { + return nil, nil + } + return &RpkiValidationCondition{ + result: c, + }, nil } type Action interface { - apply(*Path) *Path + Apply(*Path) *Path } type RoutingAction struct { AcceptRoute bool } -func NewRoutingAction(action config.Actions) *RoutingAction { - return &RoutingAction{ - AcceptRoute: action.RouteDisposition.AcceptRoute, - } -} - -func (r *RoutingAction) apply(path *Path) *Path { - if r.AcceptRoute { +func (a *RoutingAction) Apply(path *Path) *Path { + if a.AcceptRoute { return path } return nil } -type CommunityAction struct { - Values []uint32 - ext []byte - action config.BgpSetCommunityOptionType - RegexpValues []*regexp.Regexp -} - -const ( - COMMUNITY_ACTION_ADD string = "ADD" - COMMUNITY_ACTION_REPLACE = "REPLACE" - COMMUNITY_ACTION_REMOVE = "REMOVE" - COMMUNITY_ACTION_NULL = "NULL" -) - -// NewCommunityAction creates CommunityAction object. -// If it cannot parse community string, then return nil. -// Similarly, if option string is invalid, return nil. -func NewCommunityAction(action config.SetCommunity) *CommunityAction { - - m := &CommunityAction{} - communities := action.SetCommunityMethod.Communities - if len(communities) == 0 && action.Options != COMMUNITY_ACTION_REPLACE { - return nil +func (a *RoutingAction) ToApiStruct() api.RouteAction { + if a.AcceptRoute { + return api.RouteAction_ACCEPT + } else { + return api.RouteAction_REJECT } +} - values := make([]uint32, 0, len(communities)) - regexpValues := make([]*regexp.Regexp, 0, len(communities)) - - for _, com := range communities { - matched, value := getCommunityValue(com) - if matched { - values = append(values, value) - continue - } - - exp, err := regexp.Compile(com) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Action", - }).Errorf("community string invalid") - return nil - } - regexpValues = append(regexpValues, exp) +func NewRoutingAction(c config.RouteDisposition) (*RoutingAction, error) { + if c.AcceptRoute == c.RejectRoute && c.AcceptRoute { + return nil, fmt.Errorf("invalid route disposition") } - if len(values) > 0 { - m.Values = values - } - if len(regexpValues) > 0 { - if action.Options != COMMUNITY_ACTION_REMOVE { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Action", - }).Error("regexp values can only be used for remove action") - return nil - } - m.RegexpValues = regexpValues + accept := false + if c.AcceptRoute && !c.RejectRoute { + accept = true } + return &RoutingAction{ + AcceptRoute: accept, + }, nil +} - switch action.Options { - case COMMUNITY_ACTION_ADD: - m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD - case COMMUNITY_ACTION_REMOVE: - m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE - case COMMUNITY_ACTION_REPLACE: - m.action = config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE - default: - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Community Action", - }).Error("action string should be ADD or REMOVE or REPLACE or NULL.") - return nil - } - return m +type CommunityAction struct { + action config.BgpSetCommunityOptionType + list []uint32 + removeList []*regexp.Regexp } func RegexpRemoveCommunities(path *Path, exps []*regexp.Regexp) { @@ -1136,150 +1003,198 @@ func RegexpRemoveCommunities(path *Path, exps []*regexp.Regexp) { path.SetCommunities(newComms, true) } -func (a *CommunityAction) apply(path *Path) *Path { - if len(a.ext) > 0 { - return a.extApply(path) +func RegexpRemoveExtCommunities(path *Path, exps []*regexp.Regexp, subtypes []bgp.ExtendedCommunityAttrSubType) { + comms := path.GetExtCommunities() + newComms := make([]bgp.ExtendedCommunityInterface, 0, len(comms)) + for _, comm := range comms { + match := false + typ, subtype := comm.GetTypes() + // match only with transitive community. see RFC7153 + if typ >= 0x3f { + continue + } + for idx, exp := range exps { + if subtype == subtypes[idx] && exp.MatchString(comm.String()) { + match = true + break + } + } + if match == false { + newComms = append(newComms, comm) + } } - list := a.Values + path.SetExtCommunities(newComms, true) +} + +func (a *CommunityAction) Apply(path *Path) *Path { switch a.action { case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: - path.SetCommunities(list, false) + path.SetCommunities(a.list, false) case config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: - path.RemoveCommunities(list) - if len(a.RegexpValues) > 0 { - RegexpRemoveCommunities(path, a.RegexpValues) - } + RegexpRemoveCommunities(path, a.removeList) case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: - path.SetCommunities(list, true) + path.SetCommunities(a.list, true) } - log.WithFields(log.Fields{ "Topic": "Policy", "Action": "community", - "Values": list, + "Values": a.list, "Method": a.action, }).Debug("community action applied") - - return path -} - -func (a *CommunityAction) extApply(path *Path) *Path { - path.SetExtCommunities(a.ext, false) - - log.WithFields(log.Fields{ - "Topic": "Policy", - "Action": "extended community", - "Values": a.ext, - "Method": a.action, - }).Debug("extended community action applied") - return path } -func NewExtCommunityAction(action config.SetExtCommunity) *CommunityAction { - communities := action.SetExtCommunityMethod.Communities - if len(communities) == 0 { - return nil +func (a *CommunityAction) ToApiStruct() *api.CommunityAction { + cs := make([]string, 0, len(a.list)+len(a.removeList)) + for _, comm := range a.list { + c := fmt.Sprintf("%d:%d", comm>>16, comm&0x0000ffff) + cs = append(cs, c) } + for _, exp := range a.removeList { + cs = append(cs, exp.String()) + } + return &api.CommunityAction{ + Communities: cs, + Option: int32(a.action), + } +} - b := make([]byte, len(communities)*8) - for i, c := range communities { - l := strings.Split(c, ":") - if len(l) != 8 { - goto E +func NewCommunityAction(c config.SetCommunity) (*CommunityAction, error) { + a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] + if !ok { + if len(c.SetCommunityMethod.Communities) == 0 { + return nil, nil } - for j, v := range l { - v, err := strconv.ParseInt(v, 0, 32) + return nil, fmt.Errorf("invalid option name: %s", c.Options) + } + var list []uint32 + var removeList []*regexp.Regexp + if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { + removeList = make([]*regexp.Regexp, 0, len(c.SetCommunityMethod.Communities)) + } else { + list = make([]uint32, 0, len(c.SetCommunityMethod.Communities)) + } + for _, x := range c.SetCommunityMethod.Communities { + if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { + exp, err := parseCommunityRegexp(x) if err != nil { - goto E + return nil, err } - b[j+i*8] = uint8(v) + removeList = append(removeList, exp) + } else { + comm, err := ParseCommunity(x) + if err != nil { + return nil, err + } + list = append(list, comm) } } return &CommunityAction{ - ext: b, - } -E: - log.WithFields(log.Fields{ - "Topic": "Policy", - "Action": "ExtCommunity", - "Values": communities, - }).Error("invalid extended community action") - return nil + action: a, + list: list, + removeList: removeList, + }, nil } -type ActionType int - -type MedAction struct { - Value int64 - action ActionType +type ExtCommunityAction struct { + action config.BgpSetCommunityOptionType + list []bgp.ExtendedCommunityInterface + removeList []*regexp.Regexp + subtypeList []bgp.ExtendedCommunityAttrSubType } -const ( - MED_ACTION_NONE ActionType = iota - MED_ACTION_REPLACE - MED_ACTION_ADD - MED_ACTION_SUB -) - -// NewMedAction creates MedAction object. -// If it cannot parse med string, then return nil. -func NewMedAction(med config.BgpSetMedType) *MedAction { - - if med == "" { - return nil +func (a *ExtCommunityAction) Apply(path *Path) *Path { + switch a.action { + case config.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: + path.SetExtCommunities(a.list, false) + case config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: + RegexpRemoveExtCommunities(path, a.removeList, a.subtypeList) + case config.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: + path.SetExtCommunities(a.list, true) } + return path +} - m := &MedAction{} +func (a *ExtCommunityAction) ToApiStruct() *api.CommunityAction { + cs := make([]string, 0, len(a.list)+len(a.removeList)) + f := func(idx int, arg string) string { + switch a.subtypeList[idx] { + case bgp.EC_SUBTYPE_ROUTE_TARGET: + return fmt.Sprintf("rt:%s", arg) + case bgp.EC_SUBTYPE_ROUTE_ORIGIN: + return fmt.Sprintf("soo:%s", arg) + default: + return fmt.Sprintf("%d:%s", a.subtypeList[idx]) + } + } + for idx, c := range a.list { + cs = append(cs, f(idx, c.String())) + } + for idx, exp := range a.removeList { + cs = append(cs, f(idx, exp.String())) + } + return &api.CommunityAction{ + Communities: cs, + Option: int32(a.action), + } +} - matched, value, action := getMedValue(fmt.Sprintf("%s", 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, -// it returns false and 0. -func getMedValue(medStr string) (bool, int64, ActionType) { - regMed, _ := regexp.Compile("^(\\+|\\-)?([0-9]+)$") - if regMed.MatchString(medStr) { - group := regMed.FindStringSubmatch(medStr) - action := MED_ACTION_REPLACE - if group[1] == "+" { - action = MED_ACTION_ADD - } else if group[1] == "-" { - action = MED_ACTION_SUB +func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error) { + a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] + if !ok { + if len(c.SetExtCommunityMethod.Communities) == 0 { + return nil, nil } - val, err := strconv.ParseInt(medStr, 10, 64) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Med Action", - }).Error("failed to parser as number or med value.") + return nil, fmt.Errorf("invalid option name: %s", c.Options) + } + var list []bgp.ExtendedCommunityInterface + var removeList []*regexp.Regexp + subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(c.SetExtCommunityMethod.Communities)) + if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { + removeList = make([]*regexp.Regexp, 0, len(c.SetExtCommunityMethod.Communities)) + } else { + list = make([]bgp.ExtendedCommunityInterface, 0, len(c.SetExtCommunityMethod.Communities)) + } + for _, x := range c.SetExtCommunityMethod.Communities { + if a == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { + subtype, exp, err := parseExtCommunityRegexp(x) + if err != nil { + return nil, err + } + removeList = append(removeList, exp) + subtypeList = append(subtypeList, subtype) + } else { + comm, err := parseExtCommunity(x) + if err != nil { + return nil, err + } + list = append(list, comm) + _, subtype := comm.GetTypes() + subtypeList = append(subtypeList, subtype) } - return true, int64(val), action } - return false, int64(0), MED_ACTION_NONE + return &ExtCommunityAction{ + action: a, + list: list, + removeList: removeList, + subtypeList: subtypeList, + }, nil } -func (a *MedAction) apply(path *Path) *Path { +type MedAction struct { + value int + action MedActionType +} + +func (a *MedAction) Apply(path *Path) *Path { var err error switch a.action { + case MED_ACTION_MOD: + err = path.SetMed(int64(a.value), false) case MED_ACTION_REPLACE: - err = path.SetMed(a.Value, true) - case MED_ACTION_ADD: - err = path.SetMed(a.Value, false) - case MED_ACTION_SUB: - err = path.SetMed(a.Value, false) + err = path.SetMed(int64(a.value), true) } + if err != nil { log.WithFields(log.Fields{ "Topic": "Policy", @@ -1289,7 +1204,7 @@ func (a *MedAction) apply(path *Path) *Path { log.WithFields(log.Fields{ "Topic": "Policy", "Action": "med", - "Value": a.Value, + "Value": a.value, "ActionType": a.action, }).Debug("med action applied") } @@ -1297,43 +1212,41 @@ func (a *MedAction) apply(path *Path) *Path { return path } -type AsPathPrependAction struct { - asn uint32 - useLeftMost bool - repeat uint8 +func (a *MedAction) ToApiStruct() *api.MedAction { + return &api.MedAction{ + Type: int32(a.action), + Value: int64(a.value), + } } -// NewAsPathPrependAction creates AsPathPrependAction object. -// If ASN cannot be parsed, nil will be returned. -func NewAsPathPrependAction(action config.SetAsPathPrepend) *AsPathPrependAction { - - a := &AsPathPrependAction{} - - if action.As == "" { - return nil +func NewMedAction(c config.BgpSetMedType) (*MedAction, error) { + if string(c) == "" { + return nil, nil } - - if action.As == "last-as" { - a.useLeftMost = true - } else { - asn, err := strconv.ParseUint(action.As, 10, 32) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "AsPathPrepend Action", - "Value": action.As, - }).Error("As number string invalid.") - return nil - } - a.asn = uint32(asn) + exp := regexp.MustCompile("^(\\+|\\-)?(\\d+)$") + elems := exp.FindStringSubmatch(string(c)) + if len(elems) != 3 { + return nil, fmt.Errorf("invalid med action format") } - a.repeat = action.RepeatN - - return a + action := MED_ACTION_REPLACE + switch elems[1] { + case "+", "-": + action = MED_ACTION_MOD + } + value, _ := strconv.Atoi(string(c)) + return &MedAction{ + value: value, + action: action, + }, nil } -func (a *AsPathPrependAction) apply(path *Path) *Path { +type AsPathPrependAction struct { + asn uint32 + useLeftMost bool + repeat uint8 +} +func (a *AsPathPrependAction) Apply(path *Path) *Path { var asn uint32 if a.useLeftMost { asns := path.GetAsSeqList() @@ -1341,7 +1254,7 @@ func (a *AsPathPrependAction) apply(path *Path) *Path { log.WithFields(log.Fields{ "Topic": "Policy", "Type": "AsPathPrepend Action", - }).Error("aspath length is zero.") + }).Errorf("aspath length is zero.") return path } asn = asns[0] @@ -1367,680 +1280,324 @@ func (a *AsPathPrependAction) apply(path *Path) *Path { return path } -type Prefix struct { - Prefix *net.IPNet - AddressFamily bgp.RouteFamily - MasklengthRangeMax uint8 - MasklengthRangeMin uint8 -} - -func NewPrefix(prefixStr string, maskRange string) (Prefix, error) { - p := Prefix{} - addr, ipPref, e := net.ParseCIDR(prefixStr) - if e != nil { - return p, e +func (a *AsPathPrependAction) ToApiStruct() *api.AsPrependAction { + return &api.AsPrependAction{ + Asn: a.asn, + Repeat: uint32(a.repeat), + UseLeftMost: a.useLeftMost, } - - if ipv4Family := addr.To4(); ipv4Family != nil { - p.AddressFamily, _ = bgp.GetRouteFamily("ipv4-unicast") - } else if ipv6Family := addr.To16(); ipv6Family != nil { - p.AddressFamily, _ = bgp.GetRouteFamily("ipv6-unicast") - } else { - return p, fmt.Errorf("can not determine the address family.") - } - - p.Prefix = ipPref - - if maskRange == "" { - l, _ := ipPref.Mask.Size() - maskLength := uint8(l) - p.MasklengthRangeMax = maskLength - p.MasklengthRangeMin = maskLength - } else { - exp := regexp.MustCompile("(\\d+)\\.\\.(\\d+)") - elems := exp.FindStringSubmatch(maskRange) - if len(elems) != 3 { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "Prefix", - "MaskRangeFormat": maskRange, - }).Warn("mask length range format is invalid.") - return p, fmt.Errorf("mask length range format is invalid") - } - // we've already checked the range is sane by regexp - min, _ := strconv.Atoi(elems[1]) - max, _ := strconv.Atoi(elems[2]) - p.MasklengthRangeMin = uint8(min) - p.MasklengthRangeMax = uint8(max) - } - return p, nil -} - -// Compare path with a policy's condition in stored order in the policy. -// If a condition match, then this function stops evaluation and -// subsequent conditions are skipped. -func (p *Policy) Apply(path *Path) (RouteType, *Path) { - for _, statement := range p.Statements { - - result := statement.evaluate(path) - log.WithFields(log.Fields{ - "Topic": "Policy", - "Path": path, - "PolicyName": p.Name, - }).Debug("statement evaluate : ", result) - - if result { - //Routing action - p := statement.routingAction.apply(path) - if p == nil { - return ROUTE_TYPE_REJECT, path - } - if len(statement.modificationActions) == 0 { - return ROUTE_TYPE_ACCEPT, path - } - // apply all modification actions - cloned := path.Clone(p.Owner, p.IsWithdraw) - for _, action := range statement.modificationActions { - cloned = action.apply(cloned) - } - return ROUTE_TYPE_ACCEPT, cloned - } - } - return ROUTE_TYPE_NONE, path -} - -func ipPrefixCalculate(path *Path, cPrefix Prefix) bool { - rf := path.GetRouteFamily() - log.Debug("path routefamily : ", rf.String()) - var pAddr net.IP - var pMasklen uint8 - - if rf != cPrefix.AddressFamily { - return false - } - - switch rf { - case bgp.RF_IPv4_UC: - pAddr = path.GetNlri().(*bgp.IPAddrPrefix).Prefix - pMasklen = path.GetNlri().(*bgp.IPAddrPrefix).Length - case bgp.RF_IPv6_UC: - pAddr = path.GetNlri().(*bgp.IPv6AddrPrefix).Prefix - pMasklen = path.GetNlri().(*bgp.IPv6AddrPrefix).Length - default: - return false - } - - return (cPrefix.MasklengthRangeMin <= pMasklen && pMasklen <= cPrefix.MasklengthRangeMax) && cPrefix.Prefix.Contains(pAddr) -} - -const ( - OPTIONS_ANY string = "ANY" - OPTIONS_ALL = "ALL" - OPTIONS_INVERT = "INVERT" -) - -func MatchSetOptionToString(option config.MatchSetOptionsType) string { - op := OPTIONS_ANY - switch option { - case config.MATCH_SET_OPTIONS_TYPE_ALL: - op = OPTIONS_ALL - case config.MATCH_SET_OPTIONS_TYPE_INVERT: - op = OPTIONS_INVERT - } - return op -} - -func MatchSetOptionsRestrictedToString(option config.MatchSetOptionsRestrictedType) string { - op := OPTIONS_ANY - if option == config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT { - op = OPTIONS_INVERT - } - return op -} - -func MatchSetOptionsToType(option string) config.MatchSetOptionsType { - op := config.MATCH_SET_OPTIONS_TYPE_ANY - switch option { - case OPTIONS_ALL: - op = config.MATCH_SET_OPTIONS_TYPE_ALL - case OPTIONS_INVERT: - op = config.MATCH_SET_OPTIONS_TYPE_INVERT - } - return op -} - -func MatchSetOptionsRestrictedToType(option string) config.MatchSetOptionsRestrictedType { - op := config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY - if option == OPTIONS_INVERT { - op = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT - } - return op -} - -// find index PrefixSet of request from PrefixSet of configuration file. -// Return the idxPrefixSet of the location where the name of PrefixSet matches, -// and idxPrefix of the location where element of PrefixSet matches -func IndexOfPrefixSet(conPrefixSetList []config.PrefixSet, reqPrefixSet config.PrefixSet) (int, int) { - idxPrefixSet := -1 - idxPrefix := -1 - for i, conPrefixSet := range conPrefixSetList { - if conPrefixSet.PrefixSetName == reqPrefixSet.PrefixSetName { - idxPrefixSet = i - if reqPrefixSet.PrefixList == nil { - return idxPrefixSet, idxPrefix - } - for j, conPrefix := range conPrefixSet.PrefixList { - if reflect.DeepEqual(conPrefix.IpPrefix, reqPrefixSet.PrefixList[0].IpPrefix) && - conPrefix.MasklengthRange == reqPrefixSet.PrefixList[0].MasklengthRange { - idxPrefix = j - return idxPrefixSet, idxPrefix - } - } - } - } - return idxPrefixSet, idxPrefix } -// find index NeighborSet of request from NeighborSet of configuration file. -// Return the idxNeighborSet of the location where the name of NeighborSet matches, -// and idxNeighbor of the location where element of NeighborSet matches -func IndexOfNeighborSet(conNeighborSetList []config.NeighborSet, reqNeighborSet config.NeighborSet) (int, int) { - idxNeighborSet := -1 - idxNeighbor := -1 - for i, conNeighborSet := range conNeighborSetList { - if conNeighborSet.NeighborSetName == reqNeighborSet.NeighborSetName { - idxNeighborSet = i - if reqNeighborSet.NeighborInfoList == nil { - return idxNeighborSet, idxNeighbor - } - for j, conNeighbor := range conNeighborSet.NeighborInfoList { - if reflect.DeepEqual(conNeighbor.Address, reqNeighborSet.NeighborInfoList[0].Address) { - idxNeighbor = j - return idxNeighborSet, idxNeighbor - } - } - } +// NewAsPathPrependAction creates AsPathPrependAction object. +// If ASN cannot be parsed, nil will be returned. +func NewAsPathPrependAction(action config.SetAsPathPrepend) (*AsPathPrependAction, error) { + a := &AsPathPrependAction{ + repeat: action.RepeatN, } - return idxNeighborSet, idxNeighbor -} - -// find index AsPathSet of request from AsPathSet of configuration file. -// Return the idxAsPathSet of the location where the name of AsPathSet matches, -// and idxAsPath of the location where element of AsPathSet matches -func IndexOfAsPathSet(conAsPathSetList []config.AsPathSet, reqAsPathSet config.AsPathSet) (int, int) { - idxAsPathSet := -1 - idxAsPath := -1 - for i, conAsPathSet := range conAsPathSetList { - if conAsPathSet.AsPathSetName == reqAsPathSet.AsPathSetName { - idxAsPathSet = i - if len(reqAsPathSet.AsPathList) == 0 { - return idxAsPathSet, idxAsPath - } - for j, conAsPath := range conAsPathSet.AsPathList { - if conAsPath == reqAsPathSet.AsPathList[0] { - idxAsPath = j - return idxAsPathSet, idxAsPath - } - } + switch action.As { + case "": + if a.repeat == 0 { + return nil, nil } - } - return idxAsPathSet, idxAsPath -} - -// find index CommunitySet of request from CommunitySet of configuration file. -// Return the idxCommunitySet of the location where the name of CommunitySet matches, -// and idxCommunity of the location where element of CommunitySet matches -func IndexOfCommunitySet(conCommunitySetList []config.CommunitySet, reqCommunitySet config.CommunitySet) (int, int) { - idxCommunitySet := -1 - idxCommunity := -1 - for i, conCommunitySet := range conCommunitySetList { - if conCommunitySet.CommunitySetName == reqCommunitySet.CommunitySetName { - idxCommunitySet = i - if len(reqCommunitySet.CommunityList) == 0 { - return idxCommunitySet, idxCommunity - } - for j, conCommunity := range conCommunitySet.CommunityList { - if conCommunity == reqCommunitySet.CommunityList[0] { - idxCommunity = j - return idxCommunitySet, idxCommunity - } - } + return nil, fmt.Errorf("specify as to prepend") + case "last-as": + a.useLeftMost = true + default: + asn, err := strconv.Atoi(action.As) + if err != nil { + return nil, fmt.Errorf("As number string invalid") } + a.asn = uint32(asn) } - return idxCommunitySet, idxCommunity + return a, nil } -// find index ExtCommunitySet of request from ExtCommunitySet of configuration file. -// Return the idxExtCommunitySet of the location where the name of ExtCommunitySet matches, -// and idxExtCommunity of the location where element of ExtCommunitySet matches -func IndexOfExtCommunitySet(conExtCommunitySetList []config.ExtCommunitySet, reqExtCommunitySet config.ExtCommunitySet) (int, int) { - idxExtCommunitySet := -1 - idxExtCommunity := -1 - for i, conExtCommunitySet := range conExtCommunitySetList { - if conExtCommunitySet.ExtCommunitySetName == reqExtCommunitySet.ExtCommunitySetName { - idxExtCommunitySet = i - if len(reqExtCommunitySet.ExtCommunityList) == 0 { - return idxExtCommunitySet, idxExtCommunity - } - for j, conExtCommunity := range conExtCommunitySet.ExtCommunityList { - if conExtCommunity == reqExtCommunitySet.ExtCommunityList[0] { - idxExtCommunity = j - return idxExtCommunitySet, idxExtCommunity - } - } - } - } - return idxExtCommunitySet, idxExtCommunity +type Statement struct { + Name string + Conditions []Condition + RouteAction Action + ModActions []Action } -// find index PolicyDefinition of request from PolicyDefinition of configuration file. -// Return the idxPolicyDefinition of the location where the name of PolicyDefinition matches, -// and idxStatement of the location where Statement of PolicyDefinition matches -func IndexOfPolicyDefinition(conPolicyList []config.PolicyDefinition, reqPolicy config.PolicyDefinition) (int, int) { - idxPolicyDefinition := -1 - idxStatement := -1 - for i, conPolicy := range conPolicyList { - if conPolicy.Name == reqPolicy.Name { - idxPolicyDefinition = i - if reqPolicy.Statements.StatementList == nil { - return idxPolicyDefinition, idxStatement - } - for j, conStatement := range conPolicy.Statements.StatementList { - if conStatement.Name == reqPolicy.Statements.StatementList[0].Name { - idxStatement = j - return idxPolicyDefinition, idxStatement - } - } +// evaluate each condition in the statement according to MatchSetOptions +func (s *Statement) Evaluate(p *Path) bool { + for _, c := range s.Conditions { + fmt.Printf("%v, %t\n", c, c) + if !c.Evaluate(p) { + return false } } - return idxPolicyDefinition, idxStatement + return true } -func PrefixSetToApiStruct(ps config.PrefixSet) *gobgpapi.PrefixSet { - resPrefixList := make([]*gobgpapi.Prefix, 0) - for _, p := range ps.PrefixList { - resPrefix := &gobgpapi.Prefix{ - IpPrefix: p.IpPrefix, - MaskLengthRange: p.MasklengthRange, - } - resPrefixList = append(resPrefixList, resPrefix) - } - resPrefixSet := &gobgpapi.PrefixSet{ - PrefixSetName: ps.PrefixSetName, - PrefixList: resPrefixList, +func (s *Statement) Apply(path *Path) (RouteType, *Path) { + result := s.Evaluate(path) + log.WithFields(log.Fields{ + "Topic": "Policy", + "Path": path, + "PolicyName": s.Name, + }).Debug("statement evaluate : ", result) + if result { + //Routing action + p := s.RouteAction.Apply(path) + if p == nil { + return ROUTE_TYPE_REJECT, path + } + if len(s.ModActions) == 0 { + return ROUTE_TYPE_ACCEPT, path + } + // apply all modification actions + cloned := path.Clone(p.Owner, p.IsWithdraw) + for _, action := range s.ModActions { + cloned = action.Apply(cloned) + } + return ROUTE_TYPE_ACCEPT, cloned } - - return resPrefixSet + return ROUTE_TYPE_NONE, path } -func PrefixSetToConfigStruct(reqPrefixSet *gobgpapi.PrefixSet) (bool, config.PrefixSet) { - var prefix config.Prefix - var prefixSet config.PrefixSet - isReqPrefixSet := true - if reqPrefixSet.PrefixList != nil { - prefix = config.Prefix{ - IpPrefix: reqPrefixSet.PrefixList[0].IpPrefix, - MasklengthRange: reqPrefixSet.PrefixList[0].MaskLengthRange, - } - prefixList := []config.Prefix{prefix} - - prefixSet = config.PrefixSet{ - PrefixSetName: reqPrefixSet.PrefixSetName, - PrefixList: prefixList, - } - } else { - isReqPrefixSet = false - prefixSet = config.PrefixSet{ - PrefixSetName: reqPrefixSet.PrefixSetName, - PrefixList: nil, +func (s *Statement) ToApiStruct() *api.Statement { + cs := &api.Conditions{} + for _, c := range s.Conditions { + switch c.(type) { + case *PrefixCondition: + cs.PrefixSet = c.(*PrefixCondition).ToApiStruct() + case *NeighborCondition: + cs.NeighborSet = c.(*NeighborCondition).ToApiStruct() + case *AsPathLengthCondition: + cs.AsPathLength = c.(*AsPathLengthCondition).ToApiStruct() + case *AsPathCondition: + cs.AsPathSet = c.(*AsPathCondition).ToApiStruct() + case *CommunityCondition: + cs.CommunitySet = c.(*CommunityCondition).ToApiStruct() + case *ExtCommunityCondition: + cs.ExtCommunitySet = c.(*ExtCommunityCondition).ToApiStruct() + case *RpkiValidationCondition: + cs.RpkiResult = int32(c.(*RpkiValidationCondition).result) + } + } + as := &api.Actions{} + as.RouteAction = s.RouteAction.(*RoutingAction).ToApiStruct() + for _, a := range s.ModActions { + switch a.(type) { + case *CommunityAction: + as.Community = a.(*CommunityAction).ToApiStruct() + case *MedAction: + as.Med = a.(*MedAction).ToApiStruct() + case *AsPathPrependAction: + as.AsPrepend = a.(*AsPathPrependAction).ToApiStruct() + case *ExtCommunityAction: + as.ExtCommunity = a.(*ExtCommunityAction).ToApiStruct() + } + } + return &api.Statement{ + Name: s.Name, + Conditions: cs, + Actions: as, + } +} + +func NewStatement(c config.Statement, dmap DefinedSetMap) (*Statement, error) { + if c.Name == "" { + return nil, fmt.Errorf("empty statement name") + } + var ra Action + var as []Action + var cs []Condition + var err error + cfs := []func() (Condition, error){ + func() (Condition, error) { + return NewPrefixCondition(c.Conditions.MatchPrefixSet, dmap[DEFINED_TYPE_PREFIX]) + }, + func() (Condition, error) { + return NewNeighborCondition(c.Conditions.MatchNeighborSet, dmap[DEFINED_TYPE_NEIGHBOR]) + }, + func() (Condition, error) { + return NewAsPathLengthCondition(c.Conditions.BgpConditions.AsPathLength) + }, + func() (Condition, error) { + return NewRpkiValidationCondition(c.Conditions.BgpConditions.RpkiValidationResult) + }, + func() (Condition, error) { + return NewAsPathCondition(c.Conditions.BgpConditions.MatchAsPathSet, dmap[DEFINED_TYPE_AS_PATH]) + }, + func() (Condition, error) { + return NewCommunityCondition(c.Conditions.BgpConditions.MatchCommunitySet, dmap[DEFINED_TYPE_COMMUNITY]) + }, + func() (Condition, error) { + return NewExtCommunityCondition(c.Conditions.BgpConditions.MatchExtCommunitySet, dmap[DEFINED_TYPE_EXT_COMMUNITY]) + }, + } + cs = make([]Condition, 0, len(cfs)) + for _, f := range cfs { + c, err := f() + if err != nil { + return nil, err } - } - return isReqPrefixSet, prefixSet -} - -func NeighborSetToApiStruct(ns config.NeighborSet) *gobgpapi.NeighborSet { - resNeighborList := make([]*gobgpapi.Neighbor, 0) - for _, n := range ns.NeighborInfoList { - resNeighbor := &gobgpapi.Neighbor{ - Address: n.Address.String(), + if !reflect.ValueOf(c).IsNil() { + cs = append(cs, c) } - resNeighborList = append(resNeighborList, resNeighbor) - } - resNeighborSet := &gobgpapi.NeighborSet{ - NeighborSetName: ns.NeighborSetName, - NeighborList: resNeighborList, } - return resNeighborSet -} - -func NeighborSetToConfigStruct(reqNeighborSet *gobgpapi.NeighborSet) (bool, config.NeighborSet) { - var neighbor config.NeighborInfo - var neighborSet config.NeighborSet - isReqNeighborSet := true - if reqNeighborSet.NeighborList != nil { - neighbor = config.NeighborInfo{ - Address: net.ParseIP(reqNeighborSet.NeighborList[0].Address), - } - neighborList := []config.NeighborInfo{neighbor} - - neighborSet = config.NeighborSet{ - NeighborSetName: reqNeighborSet.NeighborSetName, - NeighborInfoList: neighborList, + ra, err = NewRoutingAction(c.Actions.RouteDisposition) + if err != nil { + return nil, err + } + afs := []func() (Action, error){ + func() (Action, error) { + return NewCommunityAction(c.Actions.BgpActions.SetCommunity) + }, + func() (Action, error) { + return NewExtCommunityAction(c.Actions.BgpActions.SetExtCommunity) + }, + func() (Action, error) { + return NewMedAction(c.Actions.BgpActions.SetMed) + }, + func() (Action, error) { + return NewAsPathPrependAction(c.Actions.BgpActions.SetAsPathPrepend) + }, + } + as = make([]Action, 0, len(afs)) + for _, f := range afs { + a, err := f() + if err != nil { + return nil, err } - } else { - isReqNeighborSet = false - neighborSet = config.NeighborSet{ - NeighborSetName: reqNeighborSet.NeighborSetName, - NeighborInfoList: nil, + if !reflect.ValueOf(a).IsNil() { + as = append(as, a) } } - return isReqNeighborSet, neighborSet -} - -func AsPathSetToApiStruct(as config.AsPathSet) *gobgpapi.AsPathSet { - resAsPathMembers := make([]string, 0) - for _, a := range as.AsPathList { - resAsPathMembers = append(resAsPathMembers, a.AsPath) - } - resAsPathSet := &gobgpapi.AsPathSet{ - AsPathSetName: as.AsPathSetName, - AsPathMembers: resAsPathMembers, - } - return resAsPathSet -} - -func AsPathSetToConfigStruct(reqAsPathSet *gobgpapi.AsPathSet) (bool, config.AsPathSet) { - isAsPathSetSet := true - if len(reqAsPathSet.AsPathMembers) == 0 { - isAsPathSetSet = false - } - asPathList := make([]config.AsPath, 0) - for _, a := range reqAsPathSet.AsPathMembers { - asPathList = append(asPathList, config.AsPath{AsPath: a}) - } - asPathSet := config.AsPathSet{ - AsPathSetName: reqAsPathSet.AsPathSetName, - AsPathList: asPathList, - } - return isAsPathSetSet, asPathSet -} - -func CommunitySetToApiStruct(cs config.CommunitySet) *gobgpapi.CommunitySet { - resCommunityMembers := make([]string, 0) - for _, c := range cs.CommunityList { - resCommunityMembers = append(resCommunityMembers, c.Community) - } - resCommunitySet := &gobgpapi.CommunitySet{ - CommunitySetName: cs.CommunitySetName, - CommunityMembers: resCommunityMembers, - } - return resCommunitySet -} - -func CommunitySetToConfigStruct(reqCommunitySet *gobgpapi.CommunitySet) (bool, config.CommunitySet) { - isCommunitySet := true - if len(reqCommunitySet.CommunityMembers) == 0 { - isCommunitySet = false - } - communityList := make([]config.Community, 0) - for _, c := range reqCommunitySet.CommunityMembers { - communityList = append(communityList, config.Community{Community: c}) - } - communitySet := config.CommunitySet{ - CommunitySetName: reqCommunitySet.CommunitySetName, - CommunityList: communityList, - } - return isCommunitySet, communitySet -} - -func ExtCommunitySetToApiStruct(es config.ExtCommunitySet) *gobgpapi.ExtCommunitySet { - resExtCommunityMembers := make([]string, 0) - for _, ec := range es.ExtCommunityList { - resExtCommunityMembers = append(resExtCommunityMembers, ec.ExtCommunity) - } - resExtCommunitySet := &gobgpapi.ExtCommunitySet{ - ExtCommunitySetName: es.ExtCommunitySetName, - ExtCommunityMembers: resExtCommunityMembers, - } - return resExtCommunitySet -} - -func ExtCommunitySetToConfigStruct(reqExtCommunitySet *gobgpapi.ExtCommunitySet) (bool, config.ExtCommunitySet) { - isExtCommunitySet := true - if len(reqExtCommunitySet.ExtCommunityMembers) == 0 { - isExtCommunitySet = false - } - extCommunityList := make([]config.ExtCommunity, 0) - for _, ec := range reqExtCommunitySet.ExtCommunityMembers { - extCommunityList = append(extCommunityList, config.ExtCommunity{ExtCommunity: ec}) - } - ExtCommunitySet := config.ExtCommunitySet{ - ExtCommunitySetName: reqExtCommunitySet.ExtCommunitySetName, - ExtCommunityList: extCommunityList, - } - return isExtCommunitySet, ExtCommunitySet + return &Statement{ + Name: c.Name, + Conditions: cs, + RouteAction: ra, + ModActions: as, + }, nil } -func AsPathLengthToApiStruct(asPathLength config.AsPathLength) *gobgpapi.AsPathLength { - value := "" - if asPathLength.Operator != "" { - value = fmt.Sprintf("%d", asPathLength.Value) - } - resAsPathLength := &gobgpapi.AsPathLength{ - Value: value, - Operator: asPathLength.Operator, - } - return resAsPathLength +type Policy struct { + name string + Statements []*Statement } -func AsPathLengthToConfigStruct(reqAsPathLength *gobgpapi.AsPathLength) config.AsPathLength { - operator := reqAsPathLength.Operator - value := reqAsPathLength.Value - valueUint, _ := strconv.ParseUint(value, 10, 32) - asPathLength := config.AsPathLength{ - Operator: operator, - Value: uint32(valueUint), - } - return asPathLength +func (p *Policy) Name() string { + return p.name } -func ConditionsToConfigStruct(reqConditions *gobgpapi.Conditions) config.Conditions { - conditions := config.Conditions{} - if reqConditions == nil { - return conditions - } - if reqConditions.MatchPrefixSet != nil { - conditions.MatchPrefixSet.PrefixSet = reqConditions.MatchPrefixSet.PrefixSetName - conditions.MatchPrefixSet.MatchSetOptions = - MatchSetOptionsRestrictedToType(reqConditions.MatchPrefixSet.MatchSetOptions) - } - if reqConditions.MatchNeighborSet != nil { - conditions.MatchNeighborSet.NeighborSet = reqConditions.MatchNeighborSet.NeighborSetName - conditions.MatchNeighborSet.MatchSetOptions = - MatchSetOptionsRestrictedToType(reqConditions.MatchNeighborSet.MatchSetOptions) - } - if reqConditions.MatchAsPathSet != nil { - conditions.BgpConditions.MatchAsPathSet.AsPathSet = reqConditions.MatchAsPathSet.AsPathSetName - conditions.BgpConditions.MatchAsPathSet.MatchSetOptions = - MatchSetOptionsToType(reqConditions.MatchAsPathSet.MatchSetOptions) - } - if reqConditions.MatchCommunitySet != nil { - conditions.BgpConditions.MatchCommunitySet.CommunitySet = reqConditions.MatchCommunitySet.CommunitySetName - conditions.BgpConditions.MatchCommunitySet.MatchSetOptions = - MatchSetOptionsToType(reqConditions.MatchCommunitySet.MatchSetOptions) - } - if reqConditions.MatchExtCommunitySet != nil { - conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet = reqConditions.MatchExtCommunitySet.ExtCommunitySetName - conditions.BgpConditions.MatchExtCommunitySet.MatchSetOptions = - MatchSetOptionsToType(reqConditions.MatchExtCommunitySet.MatchSetOptions) - } - if reqConditions.MatchAsPathLength != nil { - conditions.BgpConditions.AsPathLength = - AsPathLengthToConfigStruct(reqConditions.MatchAsPathLength) +// Compare path with a policy's condition in stored order in the policy. +// If a condition match, then this function stops evaluation and +// subsequent conditions are skipped. +func (p *Policy) Apply(path *Path) (RouteType, *Path) { + for _, stmt := range p.Statements { + result, path := stmt.Apply(path) + if result != ROUTE_TYPE_NONE { + return result, path + } } - return conditions + return ROUTE_TYPE_NONE, path } -func ActionsToApiStruct(conActions config.Actions) *gobgpapi.Actions { - action := gobgpapi.RouteAction_REJECT - if conActions.RouteDisposition.AcceptRoute { - action = gobgpapi.RouteAction_ACCEPT - } - - //TODO: support CommunitySetRef - communityAction := &gobgpapi.CommunityAction{ - Communities: conActions.BgpActions.SetCommunity.SetCommunityMethod.Communities, - Options: conActions.BgpActions.SetCommunity.Options, - } - medAction := fmt.Sprintf("%s", conActions.BgpActions.SetMed) - asprependAction := &gobgpapi.AsPrependAction{ - conActions.BgpActions.SetAsPathPrepend.As, - uint32(conActions.BgpActions.SetAsPathPrepend.RepeatN), - } - extCommunityAction := &gobgpapi.CommunityAction{ - Communities: conActions.BgpActions.SetExtCommunity.SetExtCommunityMethod.Communities, - Options: conActions.BgpActions.SetExtCommunity.Options, +func (p *Policy) ToApiStruct() *api.PolicyDefinition { + ss := make([]*api.Statement, 0, len(p.Statements)) + for _, s := range p.Statements { + ss = append(ss, s.ToApiStruct()) } - - resActions := &gobgpapi.Actions{ - RouteAction: action, - Community: communityAction, - Med: medAction, - AsPrepend: asprependAction, - ExtCommunity: extCommunityAction, + return &api.PolicyDefinition{ + Name: p.name, + Statements: ss, } - return resActions } -func ActionsToConfigStruct(reqActions *gobgpapi.Actions) config.Actions { - actions := config.Actions{} - if reqActions == nil { - return actions - } - if reqActions.Community != nil { - actions.BgpActions.SetCommunity.SetCommunityMethod.Communities = reqActions.Community.Communities - actions.BgpActions.SetCommunity.Options = reqActions.Community.Options - } - if reqActions.Med != "" { - actions.BgpActions.SetMed = config.BgpSetMedType(reqActions.Med) +func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { + if c.Name == "" { + return nil, fmt.Errorf("empty policy name") } - if reqActions.AsPrepend != nil { - actions.BgpActions.SetAsPathPrepend.As = reqActions.AsPrepend.As - actions.BgpActions.SetAsPathPrepend.RepeatN = uint8(reqActions.AsPrepend.Repeatn) - } - - switch reqActions.RouteAction { - case gobgpapi.RouteAction_ACCEPT: - actions.RouteDisposition.AcceptRoute = true - case gobgpapi.RouteAction_REJECT: - actions.RouteDisposition.RejectRoute = true + var st []*Statement + stmts := c.Statements.StatementList + if len(stmts) != 0 { + st = make([]*Statement, 0, len(stmts)) + for _, stmt := range stmts { + s, err := NewStatement(stmt, dmap) + if err != nil { + return nil, err + } + st = append(st, s) + } } - return actions + return &Policy{ + name: c.Name, + Statements: st, + }, nil } -func StatementToConfigStruct(reqStatement *gobgpapi.Statement) config.Statement { - statement := config.Statement{ - Name: reqStatement.StatementNeme, - Conditions: ConditionsToConfigStruct(reqStatement.Conditions), - Actions: ActionsToConfigStruct(reqStatement.Actions), - } - return statement +type RoutingPolicy struct { + DefinedSetMap DefinedSetMap + PolicyMap map[string]*Policy } -func PolicyDefinitionToConfigStruct(reqPolicy *gobgpapi.PolicyDefinition) (bool, config.PolicyDefinition) { - isReqStatement := true - policy := config.PolicyDefinition{ - Name: reqPolicy.PolicyDefinitionName, - } - if reqPolicy.StatementList != nil { - statement := StatementToConfigStruct(reqPolicy.StatementList[0]) - policy.Statements.StatementList = []config.Statement{statement} - } else { - isReqStatement = false - } - return isReqStatement, policy -} - -func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSets) *gobgpapi.PolicyDefinition { - conPrefixSetList := df.PrefixSets.PrefixSetList - conNeighborSetList := df.NeighborSets.NeighborSetList - conAsPathSetList := df.BgpDefinedSets.AsPathSets.AsPathSetList - conCommunitySetList := df.BgpDefinedSets.CommunitySets.CommunitySetList - conExtCommunitySetList := df.BgpDefinedSets.ExtCommunitySets.ExtCommunitySetList - resStatementList := make([]*gobgpapi.Statement, 0) - for _, st := range pd.Statements.StatementList { - co := st.Conditions - bco := co.BgpConditions - ac := st.Actions - - prefixSet := &gobgpapi.PrefixSet{PrefixSetName: co.MatchPrefixSet.PrefixSet} - conPrefixSet := config.PrefixSet{PrefixSetName: co.MatchPrefixSet.PrefixSet} - idxPrefixSet, _ := IndexOfPrefixSet(conPrefixSetList, conPrefixSet) - if idxPrefixSet != -1 { - prefixSet = PrefixSetToApiStruct(conPrefixSetList[idxPrefixSet]) - prefixSet.MatchSetOptions = MatchSetOptionsRestrictedToString(st.Conditions.MatchPrefixSet.MatchSetOptions) - } - neighborSet := &gobgpapi.NeighborSet{NeighborSetName: co.MatchNeighborSet.NeighborSet} - conNeighborSet := config.NeighborSet{NeighborSetName: co.MatchNeighborSet.NeighborSet} - idxNeighborSet, _ := IndexOfNeighborSet(conNeighborSetList, conNeighborSet) - if idxNeighborSet != -1 { - neighborSet = NeighborSetToApiStruct(conNeighborSetList[idxNeighborSet]) - neighborSet.MatchSetOptions = MatchSetOptionsRestrictedToString(st.Conditions.MatchNeighborSet.MatchSetOptions) - } - - asPathSet := &gobgpapi.AsPathSet{AsPathSetName: bco.MatchAsPathSet.AsPathSet} - conAsPathSet := config.AsPathSet{AsPathSetName: bco.MatchAsPathSet.AsPathSet} - idxAsPathSet, _ := IndexOfAsPathSet(conAsPathSetList, conAsPathSet) - if idxAsPathSet != -1 { - asPathSet = AsPathSetToApiStruct(conAsPathSetList[idxAsPathSet]) - asPathSet.MatchSetOptions = MatchSetOptionToString(bco.MatchAsPathSet.MatchSetOptions) - } - - communitySet := &gobgpapi.CommunitySet{CommunitySetName: bco.MatchCommunitySet.CommunitySet} - conCommunitySet := config.CommunitySet{CommunitySetName: bco.MatchCommunitySet.CommunitySet} - idxCommunitySet, _ := IndexOfCommunitySet(conCommunitySetList, conCommunitySet) - if idxCommunitySet != -1 { - communitySet = CommunitySetToApiStruct(conCommunitySetList[idxCommunitySet]) - communitySet.MatchSetOptions = MatchSetOptionToString(bco.MatchCommunitySet.MatchSetOptions) - } - - extCommunitySet := &gobgpapi.ExtCommunitySet{ExtCommunitySetName: bco.MatchExtCommunitySet.ExtCommunitySet} - conExtCommunitySet := config.ExtCommunitySet{ExtCommunitySetName: bco.MatchExtCommunitySet.ExtCommunitySet} - idxExtCommunitySet, _ := IndexOfExtCommunitySet(conExtCommunitySetList, conExtCommunitySet) - if idxExtCommunitySet != -1 { - extCommunitySet = ExtCommunitySetToApiStruct(conExtCommunitySetList[idxExtCommunitySet]) - extCommunitySet.MatchSetOptions = MatchSetOptionToString(bco.MatchExtCommunitySet.MatchSetOptions) +func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { + dmap := make(map[DefinedType]map[string]DefinedSet) + dmap[DEFINED_TYPE_PREFIX] = make(map[string]DefinedSet) + d := c.DefinedSets + for _, x := range d.PrefixSets.PrefixSetList { + y, err := NewPrefixSet(x) + if err != nil { + return nil, err } - - resConditions := &gobgpapi.Conditions{ - MatchPrefixSet: prefixSet, - MatchNeighborSet: neighborSet, - MatchAsPathSet: asPathSet, - MatchCommunitySet: communitySet, - MatchExtCommunitySet: extCommunitySet, - MatchAsPathLength: AsPathLengthToApiStruct(st.Conditions.BgpConditions.AsPathLength), + dmap[DEFINED_TYPE_PREFIX][y.Name()] = y + } + dmap[DEFINED_TYPE_NEIGHBOR] = make(map[string]DefinedSet) + for _, x := range d.NeighborSets.NeighborSetList { + y, err := NewNeighborSet(x) + if err != nil { + return nil, err + } + dmap[DEFINED_TYPE_NEIGHBOR][y.Name()] = y + } + // dmap[DEFINED_TYPE_TAG] = make(map[string]DefinedSet) + // for _, x := range c.DefinedSets.TagSets.TagSetList { + // y, err := NewTagSet(x) + // if err != nil { + // return nil, err + // } + // dmap[DEFINED_TYPE_TAG][y.Name()] = y + // } + bd := c.DefinedSets.BgpDefinedSets + dmap[DEFINED_TYPE_AS_PATH] = make(map[string]DefinedSet) + for _, x := range bd.AsPathSets.AsPathSetList { + y, err := NewAsPathSet(x) + if err != nil { + return nil, err } - resActions := ActionsToApiStruct(ac) - resStatement := &gobgpapi.Statement{ - StatementNeme: st.Name, - Conditions: resConditions, - Actions: resActions, + dmap[DEFINED_TYPE_AS_PATH][y.Name()] = y + } + dmap[DEFINED_TYPE_COMMUNITY] = make(map[string]DefinedSet) + for _, x := range bd.CommunitySets.CommunitySetList { + y, err := NewCommunitySet(x) + if err != nil { + return nil, err } - resStatementList = append(resStatementList, resStatement) + dmap[DEFINED_TYPE_COMMUNITY][y.Name()] = y } - resPolicyDefinition := &gobgpapi.PolicyDefinition{ - PolicyDefinitionName: pd.Name, - StatementList: resStatementList, + dmap[DEFINED_TYPE_EXT_COMMUNITY] = make(map[string]DefinedSet) + for _, x := range bd.ExtCommunitySets.ExtCommunitySetList { + y, err := NewExtCommunitySet(x) + if err != nil { + return nil, err + } + dmap[DEFINED_TYPE_EXT_COMMUNITY][y.Name()] = y } - return resPolicyDefinition -} - -func PoliciesToString(reqPolicies []*gobgpapi.PolicyDefinition) []string { - policies := make([]string, 0) - for _, reqPolicy := range reqPolicies { - policies = append(policies, reqPolicy.PolicyDefinitionName) + pmap := make(map[string]*Policy) + for _, x := range c.PolicyDefinitions.PolicyDefinitionList { + y, err := NewPolicy(x, dmap) + if err != nil { + return nil, err + } + pmap[y.Name()] = y } - return policies + return &RoutingPolicy{ + DefinedSetMap: dmap, + PolicyMap: pmap, + }, nil } func CanImportToVrf(v *Vrf, path *Path) bool { @@ -2053,13 +1610,22 @@ func CanImportToVrf(v *Vrf, path *Path) bool { } return ret } - set := config.ExtCommunitySet{ + set, _ := NewExtCommunitySet(config.ExtCommunitySet{ ExtCommunitySetName: v.Name, ExtCommunityList: f(v.ImportRt), - } + }) matchSet := config.MatchExtCommunitySet{ ExtCommunitySet: v.Name, MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY, } - return NewExtCommunityCondition(matchSet, []config.ExtCommunitySet{set}).evaluate(path) + c, _ := NewExtCommunityCondition(matchSet, map[string]DefinedSet{v.Name: set}) + return c.Evaluate(path) +} + +func PoliciesToString(ps []*api.PolicyDefinition) []string { + names := make([]string, 0, len(ps)) + for _, p := range ps { + names = append(names, p.Name) + } + return names } diff --git a/table/policy_test.go b/table/policy_test.go index a60c9cc7..9f9e1d17 100644 --- a/table/policy_test.go +++ b/table/policy_test.go @@ -23,7 +23,6 @@ import ( "github.com/stretchr/testify/assert" "math" "net" - "regexp" "strconv" "strings" "testing" @@ -48,14 +47,14 @@ func TestPrefixCalcurateNoRange(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("10.10.0.0/24", "") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"10.10.0.0/24", ""}) + match1 := pl1.Match(path) assert.Equal(t, true, match1) - pl2, _ := NewPrefix("10.10.0.0/23", "") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"10.10.0.0/23", ""}) + match2 := pl2.Match(path) assert.Equal(t, false, match2) - pl3, _ := NewPrefix("10.10.0.0/16", "21..24") - match3 := ipPrefixCalculate(path, pl3) + pl3, _ := NewPrefix(config.Prefix{"10.10.0.0/16", "21..24"}) + match3 := pl3.Match(path) assert.Equal(t, true, match3) } @@ -72,11 +71,11 @@ func TestPrefixCalcurateAddress(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("10.11.0.0/16", "21..24") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"10.11.0.0/16", "21..24"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("10.10.0.0/16", "21..24") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"10.10.0.0/16", "21..24"}) + match2 := pl2.Match(path) assert.Equal(t, true, match2) } @@ -93,11 +92,11 @@ func TestPrefixCalcurateLength(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("10.10.64.0/24", "21..24") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"10.10.64.0/24", "21..24"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("10.10.64.0/16", "21..24") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"10.10.64.0/16", "21..24"}) + match2 := pl2.Match(path) assert.Equal(t, true, match2) } @@ -114,14 +113,14 @@ func TestPrefixCalcurateLengthRange(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("10.10.0.0/16", "21..23") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"10.10.0.0/16", "21..23"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("10.10.0.0/16", "25..26") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"10.10.0.0/16", "25..26"}) + match2 := pl2.Match(path) assert.Equal(t, false, match2) - pl3, _ := NewPrefix("10.10.0.0/16", "21..24") - match3 := ipPrefixCalculate(path, pl3) + pl3, _ := NewPrefix(config.Prefix{"10.10.0.0/16", "21..24"}) + match3 := pl3.Match(path) assert.Equal(t, true, match3) } @@ -139,14 +138,14 @@ func TestPrefixCalcurateNoRangeIPv6(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("2001:123:123::/48", "") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"2001:123:123::/48", ""}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("2001:123:123:1::/64", "") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"2001:123:123:1::/64", ""}) + match2 := pl2.Match(path) assert.Equal(t, true, match2) - pl3, _ := NewPrefix("2001:123:123::/48", "64..80") - match3 := ipPrefixCalculate(path, pl3) + pl3, _ := NewPrefix(config.Prefix{"2001:123:123::/48", "64..80"}) + match3 := pl3.Match(path) assert.Equal(t, true, match3) } @@ -163,11 +162,11 @@ func TestPrefixCalcurateAddressIPv6(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("2001:123:128::/48", "64..80") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"2001:123:128::/48", "64..80"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("2001:123:123::/48", "64..80") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"2001:123:123::/48", "64..80"}) + match2 := pl2.Match(path) assert.Equal(t, true, match2) } @@ -184,11 +183,11 @@ func TestPrefixCalcurateLengthIPv6(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("2001:123:123:64::/64", "64..80") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"2001:123:123:64::/64", "64..80"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("2001:123:123:64::/48", "64..80") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"2001:123:123:64::/48", "64..80"}) + match2 := pl2.Match(path) assert.Equal(t, true, match2) } @@ -205,14 +204,14 @@ func TestPrefixCalcurateLengthRangeIPv6(t *testing.T) { updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nil) path := ProcessMessage(updateMsg, peer)[0] // test - pl1, _ := NewPrefix("2001:123:123::/48", "62..63") - match1 := ipPrefixCalculate(path, pl1) + pl1, _ := NewPrefix(config.Prefix{"2001:123:123::/48", "62..63"}) + match1 := pl1.Match(path) assert.Equal(t, false, match1) - pl2, _ := NewPrefix("2001:123:123::/48", "65..66") - match2 := ipPrefixCalculate(path, pl2) + pl2, _ := NewPrefix(config.Prefix{"2001:123:123::/48", "65..66"}) + match2 := pl2.Match(path) assert.Equal(t, false, match2) - pl3, _ := NewPrefix("2001:123:123::/48", "63..65") - match3 := ipPrefixCalculate(path, pl3) + pl3, _ := NewPrefix(config.Prefix{"2001:123:123::/48", "63..65"}) + match3 := pl3.Match(path) assert.Equal(t, true, match3) } @@ -239,10 +238,9 @@ func TestPolicyNotMatch(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) - //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) - pType, newPath := p.Apply(path) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_NONE, pType) assert.Equal(t, newPath, path) } @@ -270,10 +268,9 @@ func TestPolicyMatchAndReject(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) - //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) - pType, newPath := p.Apply(path) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) } @@ -302,9 +299,9 @@ func TestPolicyMatchAndAccept(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) - pType, newPath := p.Apply(path) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.Equal(t, path, newPath) } @@ -338,13 +335,14 @@ func TestPolicyRejectOnlyPrefixSet(t *testing.T) { ds := config.DefinedSets{} ds.PrefixSets.PrefixSetList = []config.PrefixSet{ps} - s := createStatement("statement1", "ps1", "ns1", false) + s := createStatement("statement1", "ps1", "", false) pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path1) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path1) @@ -383,18 +381,18 @@ func TestPolicyRejectOnlyNeighborSet(t *testing.T) { ds := config.DefinedSets{} ds.NeighborSets.NeighborSetList = []config.NeighborSet{ns} - s := createStatement("statement1", "ps1", "ns1", false) + s := createStatement("statement1", "", "ns1", false) pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) - pType, newPath := p.Apply(path1) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + pType, newPath := r.PolicyMap["pd1"].Apply(path1) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path1) - pType2, newPath2 := p.Apply(path2) + pType2, newPath2 := r.PolicyMap["pd1"].Apply(path2) assert.Equal(t, ROUTE_TYPE_NONE, pType2) assert.Equal(t, newPath2, path2) } @@ -440,8 +438,9 @@ func TestPolicyDifferentRoutefamilyOfPathAndPolicy(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType1, newPath1 := p.Apply(pathIPv4) assert.Equal(t, ROUTE_TYPE_REJECT, pType1) assert.Equal(t, newPath1, pathIPv4) @@ -474,30 +473,30 @@ func TestAsPathLengthConditionEvaluate(t *testing.T) { Operator: "eq", Value: 5, } - c := NewAsPathLengthCondition(asPathLength) + c, _ := NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, true, c.evaluate(path)) + assert.Equal(t, true, c.Evaluate(path)) // create match condition asPathLength = config.AsPathLength{ Operator: "ge", Value: 3, } - c = NewAsPathLengthCondition(asPathLength) + c, _ = NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, true, c.evaluate(path)) + assert.Equal(t, true, c.Evaluate(path)) // create match condition asPathLength = config.AsPathLength{ Operator: "le", Value: 3, } - c = NewAsPathLengthCondition(asPathLength) + c, _ = NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, false, c.evaluate(path)) + assert.Equal(t, false, c.Evaluate(path)) } func TestAsPathLengthConditionWithOtherCondition(t *testing.T) { @@ -538,8 +537,9 @@ func TestAsPathLengthConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -579,30 +579,30 @@ func TestAs4PathLengthConditionEvaluate(t *testing.T) { Operator: "eq", Value: 5, } - c := NewAsPathLengthCondition(asPathLength) + c, _ := NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, true, c.evaluate(path)) + assert.Equal(t, true, c.Evaluate(path)) // create match condition asPathLength = config.AsPathLength{ Operator: "ge", Value: 3, } - c = NewAsPathLengthCondition(asPathLength) + c, _ = NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, true, c.evaluate(path)) + assert.Equal(t, true, c.Evaluate(path)) // create match condition asPathLength = config.AsPathLength{ Operator: "le", Value: 3, } - c = NewAsPathLengthCondition(asPathLength) + c, _ = NewAsPathLengthCondition(asPathLength) // test - assert.Equal(t, false, c.evaluate(path)) + assert.Equal(t, false, c.Evaluate(path)) } func TestAs4PathLengthConditionWithOtherCondition(t *testing.T) { @@ -654,8 +654,8 @@ func TestAs4PathLengthConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -733,14 +733,18 @@ func TestAsPathConditionEvaluate(t *testing.T) { }, } - asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, - asPathSet4, asPathSet5, asPathSet6} + m := make(map[string]DefinedSet) + for _, s := range []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, + asPathSet4, asPathSet5, asPathSet6} { + a, _ := NewAsPathSet(s) + m[s.AsPathSetName] = a + } createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p := NewAsPathCondition(matchSet, asPathSetList) + p, _ := NewAsPathCondition(matchSet, m) return p } @@ -750,22 +754,19 @@ func TestAsPathConditionEvaluate(t *testing.T) { p4 := createAspathC("asset4", config.MATCH_SET_OPTIONS_TYPE_ANY) p5 := createAspathC("asset5", config.MATCH_SET_OPTIONS_TYPE_ANY) p6 := createAspathC("asset6", config.MATCH_SET_OPTIONS_TYPE_ANY) - - //TODO: add ALL and INVERT cases. p7 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_ALL) p8 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_INVERT) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, false, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, false, p6.evaluate(path1)) - assert.Equal(t, true, p6.evaluate(path2)) - - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path2)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, false, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, false, p6.Evaluate(path1)) + assert.Equal(t, true, p6.Evaluate(path2)) + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path2)) } func TestMultipleAsPathConditionEvaluate(t *testing.T) { @@ -850,14 +851,18 @@ func TestMultipleAsPathConditionEvaluate(t *testing.T) { }, } - asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, - asPathSet4, asPathSet5, asPathSet6, asPathSet7, asPathSet8, asPathSet9} + m := make(map[string]DefinedSet) + for _, s := range []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, + asPathSet4, asPathSet5, asPathSet6, asPathSet7, asPathSet8, asPathSet9} { + a, _ := NewAsPathSet(s) + m[s.AsPathSetName] = a + } createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p := NewAsPathCondition(matchSet, asPathSetList) + p, _ := NewAsPathCondition(matchSet, m) return p } @@ -872,15 +877,15 @@ func TestMultipleAsPathConditionEvaluate(t *testing.T) { p9 := createAspathC("asset9", config.MATCH_SET_OPTIONS_TYPE_ANY) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, true, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, true, p6.evaluate(path1)) - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path1)) - assert.Equal(t, false, p9.evaluate(path1)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, true, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, true, p6.Evaluate(path1)) + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path1)) + assert.Equal(t, false, p9.Evaluate(path1)) } func TestAsPathCondition(t *testing.T) { @@ -930,17 +935,19 @@ func TestAsPathCondition(t *testing.T) { } for k, v := range tests { - r, _ := regexp.Compile(strings.Replace(k, "_", ASPATH_REGEXP_MAGIC, -1)) - c := &AsPathCondition{ - AsRegExpList: []*regexp.Regexp{r}, - MatchOption: config.MATCH_SET_OPTIONS_TYPE_ANY, - } + s, _ := NewAsPathSet(config.AsPathSet{ + AsPathSetName: k, + AsPathList: []config.AsPath{config.AsPath{k}}, + }) + c, _ := NewAsPathCondition(config.MatchAsPathSet{ + AsPathSet: k, + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY, + }, map[string]DefinedSet{k: s}) for _, a := range v { - result := c.evaluate(a.path) + result := c.Evaluate(a.path) if a.result != result { log.WithFields(log.Fields{ "EXP": k, - "ASN": r, "ASSTR": a.path.GetAsString(), "Expected": a.result, "Result": result, @@ -990,8 +997,9 @@ func TestAsPathConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -1077,14 +1085,18 @@ func TestAs4PathConditionEvaluate(t *testing.T) { }, } - asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, - asPathSet4, asPathSet5, asPathSet6} + m := make(map[string]DefinedSet) + for _, s := range []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, + asPathSet4, asPathSet5, asPathSet6} { + a, _ := NewAsPathSet(s) + m[s.AsPathSetName] = a + } createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p := NewAsPathCondition(matchSet, asPathSetList) + p, _ := NewAsPathCondition(matchSet, m) return p } @@ -1099,16 +1111,16 @@ func TestAs4PathConditionEvaluate(t *testing.T) { p8 := createAspathC("asset3", config.MATCH_SET_OPTIONS_TYPE_INVERT) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, false, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, false, p6.evaluate(path1)) - assert.Equal(t, true, p6.evaluate(path2)) - - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path2)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, false, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, false, p6.Evaluate(path1)) + assert.Equal(t, true, p6.Evaluate(path2)) + + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path2)) } func TestMultipleAs4PathConditionEvaluate(t *testing.T) { @@ -1200,14 +1212,18 @@ func TestMultipleAs4PathConditionEvaluate(t *testing.T) { }, } - asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, - asPathSet4, asPathSet5, asPathSet6, asPathSet7, asPathSet8, asPathSet9} + m := make(map[string]DefinedSet) + for _, s := range []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, + asPathSet4, asPathSet5, asPathSet6, asPathSet7, asPathSet8, asPathSet9} { + a, _ := NewAsPathSet(s) + m[s.AsPathSetName] = a + } createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p := NewAsPathCondition(matchSet, asPathSetList) + p, _ := NewAsPathCondition(matchSet, m) return p } @@ -1222,15 +1238,15 @@ func TestMultipleAs4PathConditionEvaluate(t *testing.T) { p9 := createAspathC("asset9", config.MATCH_SET_OPTIONS_TYPE_ANY) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, true, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, true, p6.evaluate(path1)) - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path1)) - assert.Equal(t, false, p9.evaluate(path1)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, true, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, true, p6.Evaluate(path1)) + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path1)) + assert.Equal(t, false, p9.Evaluate(path1)) } func TestAs4PathConditionWithOtherCondition(t *testing.T) { @@ -1286,8 +1302,8 @@ func TestAs4PathConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -1373,14 +1389,18 @@ func TestAs4PathConditionEvaluateMixedWith2byteAS(t *testing.T) { }, } - asPathSetList := []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, - asPathSet4, asPathSet5, asPathSet6, asPathSet7} + m := make(map[string]DefinedSet) + for _, s := range []config.AsPathSet{asPathSet1, asPathSet2, asPathSet3, + asPathSet4, asPathSet5, asPathSet6, asPathSet7} { + a, _ := NewAsPathSet(s) + m[s.AsPathSetName] = a + } createAspathC := func(name string, option config.MatchSetOptionsType) *AsPathCondition { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p := NewAsPathCondition(matchSet, asPathSetList) + p, _ := NewAsPathCondition(matchSet, m) return p } @@ -1393,13 +1413,13 @@ func TestAs4PathConditionEvaluateMixedWith2byteAS(t *testing.T) { p7 := createAspathC("asset7", config.MATCH_SET_OPTIONS_TYPE_ANY) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, true, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, false, p6.evaluate(path1)) - assert.Equal(t, true, p7.evaluate(path1)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, true, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, false, p6.Evaluate(path1)) + assert.Equal(t, true, p7.Evaluate(path1)) } @@ -1434,6 +1454,17 @@ func TestCommunityConditionEvaluate(t *testing.T) { UpdatePathAttrs4ByteAs(updateMsg1.Body.(*bgp.BGPUpdate)) path1 := ProcessMessage(updateMsg1, peer)[0] + communities2 := bgp.NewPathAttributeCommunities([]uint32{ + stringToCommunityValue("65001:100"), + stringToCommunityValue("65001:200"), + stringToCommunityValue("65001:300"), + stringToCommunityValue("65001:400")}) + + pathAttributes2 := []bgp.PathAttributeInterface{origin, aspath, nexthop, med, communities2} + updateMsg2 := bgp.NewBGPUpdateMessage(nil, pathAttributes2, nlri) + UpdatePathAttrs4ByteAs(updateMsg2.Body.(*bgp.BGPUpdate)) + path2 := ProcessMessage(updateMsg2, peer)[0] + // create match condition comSet1 := config.CommunitySet{ CommunitySetName: "comset1", @@ -1496,9 +1527,8 @@ func TestCommunityConditionEvaluate(t *testing.T) { comSet9 := config.CommunitySet{ CommunitySetName: "comset9", CommunityList: []config.Community{ - config.Community{"65001:100"}, - config.Community{"65001:200"}, - config.Community{"65001:300"}, + config.Community{"65001:\\d+"}, + config.Community{"\\d+:\\d00"}, }, } @@ -1511,14 +1541,19 @@ func TestCommunityConditionEvaluate(t *testing.T) { }, } - comSetList := []config.CommunitySet{comSet1, comSet2, comSet3, - comSet4, comSet5, comSet6, comSet7, comSet8, comSet9, comSet10} + m := make(map[string]DefinedSet) + + for _, c := range []config.CommunitySet{comSet1, comSet2, comSet3, + comSet4, comSet5, comSet6, comSet7, comSet8, comSet9, comSet10} { + s, _ := NewCommunitySet(c) + m[c.CommunitySetName] = s + } createCommunityC := func(name string, option config.MatchSetOptionsType) *CommunityCondition { matchSet := config.MatchCommunitySet{} matchSet.CommunitySet = name matchSet.MatchSetOptions = option - c := NewCommunityCondition(matchSet, comSetList) + c, _ := NewCommunityCondition(matchSet, m) return c } @@ -1539,16 +1574,16 @@ func TestCommunityConditionEvaluate(t *testing.T) { p10 := createCommunityC("comset10", config.MATCH_SET_OPTIONS_TYPE_INVERT) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, true, p4.evaluate(path1)) - assert.Equal(t, true, p5.evaluate(path1)) - assert.Equal(t, true, p6.evaluate(path1)) - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path1)) - assert.Equal(t, true, p9.evaluate(path1)) - assert.Equal(t, true, p10.evaluate(path1)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, true, p4.Evaluate(path1)) + assert.Equal(t, true, p5.Evaluate(path1)) + assert.Equal(t, true, p6.Evaluate(path1)) + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path1)) + assert.Equal(t, true, p9.Evaluate(path2)) + assert.Equal(t, true, p10.Evaluate(path1)) } @@ -1626,14 +1661,14 @@ func TestCommunityConditionEvaluateWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd1, pd2) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) - df = pl.DefinedSets - p = NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[1], df) + p = r.PolicyMap["pd2"] pType, newPath = p.Apply(path) assert.Equal(t, ROUTE_TYPE_NONE, pType) assert.Equal(t, newPath, path) @@ -1670,8 +1705,9 @@ func TestPolicyMatchAndAddCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -1713,8 +1749,9 @@ func TestPolicyMatchAndReplaceCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -1756,8 +1793,9 @@ func TestPolicyMatchAndRemoveCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.NotEqual(t, nil, newPath) @@ -1800,8 +1838,9 @@ func TestPolicyMatchAndRemoveCommunitiesRegexp(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.NotEqual(t, nil, newPath) @@ -1844,8 +1883,9 @@ func TestPolicyMatchAndRemoveCommunitiesRegexp2(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.NotEqual(t, nil, newPath) @@ -1888,8 +1928,9 @@ func TestPolicyMatchAndClearCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -2041,9 +2082,8 @@ func TestExtCommunityConditionEvaluate(t *testing.T) { ecomSet10 := config.ExtCommunitySet{ ExtCommunitySetName: "ecomSet10", ExtCommunityList: []config.ExtCommunity{ - config.ExtCommunity{"RT:65001:200"}, - config.ExtCommunity{"RT:10.0.0.1:300"}, - config.ExtCommunity{"SoO:10.0.10.10:[0-9]+"}, + config.ExtCommunity{"RT:.+:\\d00"}, + config.ExtCommunity{"SoO:.+:\\d00"}, }, } @@ -2051,19 +2091,22 @@ func TestExtCommunityConditionEvaluate(t *testing.T) { ExtCommunitySetName: "ecomSet11", ExtCommunityList: []config.ExtCommunity{ config.ExtCommunity{"RT:65001:2"}, - config.ExtCommunity{"RT:10.0.0.1:3"}, config.ExtCommunity{"SoO:11.0.10.10:[0-9]+"}, }, } - comSetList := []config.ExtCommunitySet{ecomSet1, ecomSet2, ecomSet3, ecomSet4, ecomSet5, ecomSet6, ecomSet7, - ecomSet8, ecomSet9, ecomSet10, ecomSet11} + m := make(map[string]DefinedSet) + for _, c := range []config.ExtCommunitySet{ecomSet1, ecomSet2, ecomSet3, ecomSet4, ecomSet5, ecomSet6, ecomSet7, + ecomSet8, ecomSet9, ecomSet10, ecomSet11} { + s, _ := NewExtCommunitySet(c) + m[s.Name()] = s + } createExtCommunityC := func(name string, option config.MatchSetOptionsType) *ExtCommunityCondition { matchSet := config.MatchExtCommunitySet{} matchSet.ExtCommunitySet = name matchSet.MatchSetOptions = option - c := NewExtCommunityCondition(matchSet, comSetList) + c, _ := NewExtCommunityCondition(matchSet, m) return c } @@ -2084,17 +2127,17 @@ func TestExtCommunityConditionEvaluate(t *testing.T) { p11 := createExtCommunityC("ecomSet11", config.MATCH_SET_OPTIONS_TYPE_INVERT) // test - assert.Equal(t, true, p1.evaluate(path1)) - assert.Equal(t, true, p2.evaluate(path1)) - assert.Equal(t, true, p3.evaluate(path1)) - assert.Equal(t, false, p4.evaluate(path1)) - assert.Equal(t, false, p5.evaluate(path1)) - assert.Equal(t, false, p6.evaluate(path1)) - assert.Equal(t, true, p7.evaluate(path1)) - assert.Equal(t, true, p8.evaluate(path1)) - assert.Equal(t, true, p9.evaluate(path1)) - assert.Equal(t, true, p10.evaluate(path1)) - assert.Equal(t, true, p11.evaluate(path1)) + assert.Equal(t, true, p1.Evaluate(path1)) + assert.Equal(t, true, p2.Evaluate(path1)) + assert.Equal(t, true, p3.Evaluate(path1)) + assert.Equal(t, false, p4.Evaluate(path1)) + assert.Equal(t, false, p5.Evaluate(path1)) + assert.Equal(t, false, p6.Evaluate(path1)) + assert.Equal(t, true, p7.Evaluate(path1)) + assert.Equal(t, true, p8.Evaluate(path1)) + assert.Equal(t, true, p9.Evaluate(path1)) + assert.Equal(t, true, p10.Evaluate(path1)) + assert.Equal(t, true, p11.Evaluate(path1)) } @@ -2219,13 +2262,14 @@ func TestExtCommunityConditionEvaluateWithOtherCondition(t *testing.T) { pd2 := createPolicyDefinition("pd2", s2) pl := createRoutingPolicy(ds, pd1, pd2) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_NONE, pType) assert.Equal(t, newPath, path) - p = NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[1], df) + p = r.PolicyMap["pd2"] pType, newPath = p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -2262,8 +2306,9 @@ func TestPolicyMatchAndReplaceMed(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -2304,8 +2349,9 @@ func TestPolicyMatchAndAddingMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.NotEqual(t, nil, newPath) @@ -2347,8 +2393,9 @@ func TestPolicyMatchAndAddingMedOverFlow(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -2391,8 +2438,9 @@ func TestPolicyMatchAndSubtractMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -2435,8 +2483,9 @@ func TestPolicyMatchAndSubtractMedUnderFlow(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -2476,14 +2525,15 @@ func TestPolicyMatchWhenPathHaveNotMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, err := NewRoutingPolicy(pl) + assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) assert.NotEqual(t, nil, newPath) - _, err := newPath.GetMed() + _, err = newPath.GetMed() assert.NotNil(t, err) } @@ -2522,8 +2572,9 @@ func TestPolicyAsPathPrepend(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + // assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(ROUTE_TYPE_ACCEPT, pType) @@ -2565,8 +2616,9 @@ func TestPolicyAsPathPrependLastAs(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + // assert.Nil(t, err) + p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) assert.Equal(ROUTE_TYPE_ACCEPT, pType) @@ -2614,8 +2666,8 @@ func TestPolicyAs4PathPrepend(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(ROUTE_TYPE_ACCEPT, pType) @@ -2668,8 +2720,8 @@ func TestPolicyAs4PathPrependLastAs(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - df := pl.DefinedSets - p := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], df) + r, _ := NewRoutingPolicy(pl) + p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(ROUTE_TYPE_ACCEPT, pType) @@ -2684,7 +2736,6 @@ func TestPolicyAs4PathPrependLastAs(t *testing.T) { } func createStatement(name, psname, nsname string, accept bool) config.Statement { - c := config.Conditions{ MatchPrefixSet: config.MatchPrefixSet{ PrefixSet: psname, diff --git a/test/scenario_test/route_server_policy_test.py b/test/scenario_test/route_server_policy_test.py index 1d372619..490d0173 100644 --- a/test/scenario_test/route_server_policy_test.py +++ b/test/scenario_test/route_server_policy_test.py @@ -2764,7 +2764,7 @@ class ImportPolicyExCommunityAdd(object): 'SetExtCommunity': { 'Options': 'ADD', 'SetExtCommunityMethod': { - 'Communities': ['0:2:0xfd:0xe8:0:0:0:1'] + 'Communities': ['rt:65000:1'], } }, } @@ -2838,7 +2838,7 @@ class ImportPolicyExCommunityAdd2(object): 'SetExtCommunity': { 'Options': 'ADD', 'SetExtCommunityMethod': { - 'Communities': ['0:2:0xfe:0x4c:0:0:0:0x64'] + 'Communities': ['rt:65100:100'], } }, } @@ -2917,7 +2917,7 @@ class ImportPolicyExCommunityMultipleAdd(object): 'SetExtCommunity': { 'Options': 'ADD', 'SetExtCommunityMethod': { - 'Communities': ['0:2:0xfe:0x4c:0:0:0:0x64', '0:2:0:0x64:0:0:0:0x64'] + 'Communities': ['rt:65100:100', 'rt:100:100'], } }, } @@ -2996,7 +2996,7 @@ class ExportPolicyExCommunityAdd(object): 'SetExtCommunity': { 'Options': 'ADD', 'SetExtCommunityMethod': { - 'Communities': ['0:2:0xfd:0xe8:0:0:0:1'], + 'Communities': ['rt:65000:1'], } }, } |