diff options
-rw-r--r-- | docs/sources/lib.md | 2 | ||||
-rw-r--r-- | gobgpd/main.go | 2 | ||||
-rw-r--r-- | server/grpc_server.go | 505 | ||||
-rw-r--r-- | server/server.go | 1064 | ||||
-rw-r--r-- | server/server_test.go | 50 | ||||
-rw-r--r-- | table/policy.go | 620 | ||||
-rw-r--r-- | table/policy_test.go | 59 |
7 files changed, 1149 insertions, 1153 deletions
diff --git a/docs/sources/lib.md b/docs/sources/lib.md index 4fac54de..b1f80ca1 100644 --- a/docs/sources/lib.md +++ b/docs/sources/lib.md @@ -25,7 +25,7 @@ func main() { // start grpc api server. this is not mandatory // but you will be able to use `gobgp` cmd with this. - g := gobgp.NewGrpcServer(":50051", s.GrpcReqCh) + g := gobgp.NewGrpcServer(s, ":50051", s.GrpcReqCh) go g.Serve() // global configuration diff --git a/gobgpd/main.go b/gobgpd/main.go index 7ad48f83..31029635 100644 --- a/gobgpd/main.go +++ b/gobgpd/main.go @@ -178,7 +178,7 @@ func main() { go bgpServer.Serve() // start grpc Server - grpcServer := server.NewGrpcServer(opts.GrpcHosts, bgpServer.GrpcReqCh) + grpcServer := server.NewGrpcServer(bgpServer, opts.GrpcHosts, bgpServer.GrpcReqCh) go func() { if err := grpcServer.Serve(); err != nil { log.Fatalf("failed to listen grpc port: %s", err) diff --git a/server/grpc_server.go b/server/grpc_server.go index d0103736..12337403 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc" "io" "net" + "reflect" "regexp" "strconv" "strings" @@ -103,6 +104,7 @@ const ( ) type Server struct { + bgpServer *BgpServer grpcServer *grpc.Server bgpServerCh chan *GrpcRequest hosts string @@ -804,13 +806,74 @@ func (s *Server) DeleteNeighbor(ctx context.Context, arg *api.DeleteNeighborRequ return d.(*api.DeleteNeighborResponse), err } +func NewPrefixFromApiStruct(a *api.Prefix) (*table.Prefix, error) { + addr, prefix, err := net.ParseCIDR(a.IpPrefix) + if err != nil { + return nil, err + } + rf := bgp.RF_IPv4_UC + if addr.To4() == nil { + rf = bgp.RF_IPv6_UC + } + return &table.Prefix{ + Prefix: prefix, + AddressFamily: rf, + MasklengthRangeMin: uint8(a.MaskLengthMin), + MasklengthRangeMax: uint8(a.MaskLengthMax), + }, nil +} + +func NewDefinedSetFromApiStruct(a *api.DefinedSet) (table.DefinedSet, error) { + if a.Name == "" { + return nil, fmt.Errorf("empty neighbor set name") + } + switch table.DefinedType(a.Type) { + case table.DEFINED_TYPE_PREFIX: + prefixes := make([]*table.Prefix, 0, len(a.Prefixes)) + for _, p := range a.Prefixes { + prefix, err := NewPrefixFromApiStruct(p) + if err != nil { + return nil, err + } + prefixes = append(prefixes, prefix) + } + return table.NewPrefixSetFromApiStruct(a.Name, prefixes) + case table.DEFINED_TYPE_NEIGHBOR: + list := make([]net.IP, 0, len(a.List)) + for _, x := range a.List { + addr := net.ParseIP(x) + if addr == nil { + return nil, fmt.Errorf("invalid ip address format: %s", x) + } + list = append(list, addr) + } + return table.NewNeighborSetFromApiStruct(a.Name, list) + case table.DEFINED_TYPE_AS_PATH: + return table.NewAsPathSet(config.AsPathSet{ + AsPathSetName: a.Name, + AsPathList: a.List, + }) + case table.DEFINED_TYPE_COMMUNITY: + return table.NewCommunitySet(config.CommunitySet{ + CommunitySetName: a.Name, + CommunityList: a.List, + }) + case table.DEFINED_TYPE_EXT_COMMUNITY: + return table.NewExtCommunitySet(config.ExtCommunitySet{ + ExtCommunitySetName: a.Name, + ExtCommunityList: a.List, + }) + default: + return nil, fmt.Errorf("invalid defined type") + } +} + func (s *Server) GetDefinedSet(ctx context.Context, arg *api.GetDefinedSetRequest) (*api.GetDefinedSetResponse, error) { - d, err := s.get(REQ_GET_DEFINED_SET, arg) + cd, err := s.bgpServer.GetDefinedSet(table.DefinedType(arg.Type)) if err != nil { return nil, err } sets := make([]*api.DefinedSet, 0) - cd := d.(*config.DefinedSets) for _, cs := range cd.PrefixSets { ad := &api.DefinedSet{ Type: api.DefinedType_PREFIX, @@ -868,27 +931,27 @@ func (s *Server) GetDefinedSet(ctx context.Context, arg *api.GetDefinedSetReques } func (s *Server) AddDefinedSet(ctx context.Context, arg *api.AddDefinedSetRequest) (*api.AddDefinedSetResponse, error) { - d, err := s.get(REQ_ADD_DEFINED_SET, arg) + set, err := NewDefinedSetFromApiStruct(arg.Set) if err != nil { return nil, err } - return d.(*api.AddDefinedSetResponse), err + return &api.AddDefinedSetResponse{}, s.bgpServer.AddDefinedSet(set) } func (s *Server) DeleteDefinedSet(ctx context.Context, arg *api.DeleteDefinedSetRequest) (*api.DeleteDefinedSetResponse, error) { - d, err := s.get(REQ_DELETE_DEFINED_SET, arg) + set, err := NewDefinedSetFromApiStruct(arg.Set) if err != nil { return nil, err } - return d.(*api.DeleteDefinedSetResponse), err + return &api.DeleteDefinedSetResponse{}, s.bgpServer.DeleteDefinedSet(set, arg.All) } func (s *Server) ReplaceDefinedSet(ctx context.Context, arg *api.ReplaceDefinedSetRequest) (*api.ReplaceDefinedSetResponse, error) { - d, err := s.get(REQ_REPLACE_DEFINED_SET, arg) + set, err := NewDefinedSetFromApiStruct(arg.Set) if err != nil { return nil, err } - return d.(*api.ReplaceDefinedSetResponse), err + return &api.ReplaceDefinedSetResponse{}, s.bgpServer.ReplaceDefinedSet(set) } func toStatementApi(s *config.Statement) *api.Statement { @@ -1016,41 +1079,323 @@ func toStatementApi(s *config.Statement) *api.Statement { } } -func (s *Server) GetStatement(ctx context.Context, arg *api.GetStatementRequest) (*api.GetStatementResponse, error) { - d, err := s.get(REQ_GET_STATEMENT, arg) +func toConfigMatchSetOption(a api.MatchType) (config.MatchSetOptionsType, error) { + var typ config.MatchSetOptionsType + switch a { + case api.MatchType_ANY: + typ = config.MATCH_SET_OPTIONS_TYPE_ANY + case api.MatchType_ALL: + typ = config.MATCH_SET_OPTIONS_TYPE_ALL + case api.MatchType_INVERT: + typ = config.MATCH_SET_OPTIONS_TYPE_INVERT + default: + return typ, fmt.Errorf("invalid match type") + } + return typ, nil +} + +func toConfigMatchSetOptionRestricted(a api.MatchType) (config.MatchSetOptionsRestrictedType, error) { + var typ config.MatchSetOptionsRestrictedType + switch a { + case api.MatchType_ANY: + typ = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY + case api.MatchType_INVERT: + typ = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT + default: + return typ, fmt.Errorf("invalid match type") + } + return typ, nil +} + +func NewPrefixConditionFromApiStruct(a *api.MatchSet) (*table.PrefixCondition, error) { + if a == nil { + return nil, nil + } + typ, err := toConfigMatchSetOptionRestricted(a.Type) if err != nil { return nil, err } + c := config.MatchPrefixSet{ + PrefixSet: a.Name, + MatchSetOptions: typ, + } + return table.NewPrefixCondition(c) +} - l := make([]*api.Statement, 0) - for _, s := range d.([]*config.Statement) { - l = append(l, toStatementApi(s)) +func NewNeighborConditionFromApiStruct(a *api.MatchSet) (*table.NeighborCondition, error) { + if a == nil { + return nil, nil + } + typ, err := toConfigMatchSetOptionRestricted(a.Type) + if err != nil { + return nil, err + } + c := config.MatchNeighborSet{ + NeighborSet: a.Name, + MatchSetOptions: typ, } - return &api.GetStatementResponse{Statements: l}, err + return table.NewNeighborCondition(c) } -func (s *Server) AddStatement(ctx context.Context, arg *api.AddStatementRequest) (*api.AddStatementResponse, error) { - d, err := s.get(REQ_ADD_STATEMENT, arg) +func NewAsPathLengthConditionFromApiStruct(a *api.AsPathLength) (*table.AsPathLengthCondition, error) { + if a == nil { + return nil, nil + } + return table.NewAsPathLengthCondition(config.AsPathLength{ + Operator: config.IntToAttributeComparisonMap[int(a.Type)], + Value: a.Length, + }) +} + +func NewAsPathConditionFromApiStruct(a *api.MatchSet) (*table.AsPathCondition, error) { + if a == nil { + return nil, nil + } + typ, err := toConfigMatchSetOption(a.Type) if err != nil { return nil, err } - return d.(*api.AddStatementResponse), err + c := config.MatchAsPathSet{ + AsPathSet: a.Name, + MatchSetOptions: typ, + } + return table.NewAsPathCondition(c) } -func (s *Server) DeleteStatement(ctx context.Context, arg *api.DeleteStatementRequest) (*api.DeleteStatementResponse, error) { - d, err := s.get(REQ_DELETE_STATEMENT, arg) +func NewRpkiValidationConditionFromApiStruct(a int32) (*table.RpkiValidationCondition, error) { + if a < 1 { + return nil, nil + } + return table.NewRpkiValidationCondition(config.IntToRpkiValidationResultTypeMap[int(a)]) +} + +func NewCommunityConditionFromApiStruct(a *api.MatchSet) (*table.CommunityCondition, error) { + if a == nil { + return nil, nil + } + typ, err := toConfigMatchSetOption(a.Type) if err != nil { return nil, err } - return d.(*api.DeleteStatementResponse), err + c := config.MatchCommunitySet{ + CommunitySet: a.Name, + MatchSetOptions: typ, + } + return table.NewCommunityCondition(c) } -func (s *Server) ReplaceStatement(ctx context.Context, arg *api.ReplaceStatementRequest) (*api.ReplaceStatementResponse, error) { - d, err := s.get(REQ_REPLACE_STATEMENT, arg) +func NewExtCommunityConditionFromApiStruct(a *api.MatchSet) (*table.ExtCommunityCondition, error) { + if a == nil { + return nil, nil + } + typ, err := toConfigMatchSetOption(a.Type) if err != nil { return nil, err } - return d.(*api.ReplaceStatementResponse), err + c := config.MatchExtCommunitySet{ + ExtCommunitySet: a.Name, + MatchSetOptions: typ, + } + return table.NewExtCommunityCondition(c) +} + +func NewRoutingActionFromApiStruct(a api.RouteAction) (*table.RoutingAction, error) { + if a == api.RouteAction_NONE { + return nil, nil + } + accept := false + if a == api.RouteAction_ACCEPT { + accept = true + } + return &table.RoutingAction{ + AcceptRoute: accept, + }, nil +} + +func NewCommunityActionFromApiStruct(a *api.CommunityAction) (*table.CommunityAction, error) { + if a == nil { + return nil, nil + } + return table.NewCommunityAction(config.SetCommunity{ + Options: string(config.IntToBgpSetCommunityOptionTypeMap[int(a.Type)]), + SetCommunityMethod: config.SetCommunityMethod{ + CommunitiesList: a.Communities, + }, + }) +} + +func NewExtCommunityActionFromApiStruct(a *api.CommunityAction) (*table.ExtCommunityAction, error) { + if a == nil { + return nil, nil + } + return table.NewExtCommunityAction(config.SetExtCommunity{ + Options: string(config.IntToBgpSetCommunityOptionTypeMap[int(a.Type)]), + SetExtCommunityMethod: config.SetExtCommunityMethod{ + CommunitiesList: a.Communities, + }, + }) +} + +func NewMedActionFromApiStruct(a *api.MedAction) (*table.MedAction, error) { + if a == nil { + return nil, nil + } + return table.NewMedActionFromApiStruct(table.MedActionType(a.Type), int(a.Value)), nil +} + +func NewLocalPrefActionFromApiStruct(a *api.LocalPrefAction) (*table.LocalPrefAction, error) { + if a == nil || a.Value == 0 { + return nil, nil + } + return table.NewLocalPrefAction(a.Value) +} + +func NewAsPathPrependActionFromApiStruct(a *api.AsPrependAction) (*table.AsPathPrependAction, error) { + if a == nil { + return nil, nil + } + return table.NewAsPathPrependAction(config.SetAsPathPrepend{ + RepeatN: uint8(a.Repeat), + As: func() string { + if a.UseLeftMost { + return "last-as" + } + return fmt.Sprintf("%d", a.Asn) + }(), + }) +} + +func NewNexthopActionFromApiStruct(a *api.NexthopAction) (*table.NexthopAction, error) { + if a == nil { + return nil, nil + } + return table.NewNexthopAction(config.BgpNextHopType( + func() string { + if a.Self { + return "self" + } + return a.Address + }(), + )) +} + +func NewStatementFromApiStruct(a *api.Statement) (*table.Statement, error) { + if a.Name == "" { + return nil, fmt.Errorf("empty statement name") + } + var ra table.Action + var as []table.Action + var cs []table.Condition + var err error + if a.Conditions != nil { + cfs := []func() (table.Condition, error){ + func() (table.Condition, error) { + return NewPrefixConditionFromApiStruct(a.Conditions.PrefixSet) + }, + func() (table.Condition, error) { + return NewNeighborConditionFromApiStruct(a.Conditions.NeighborSet) + }, + func() (table.Condition, error) { + return NewAsPathLengthConditionFromApiStruct(a.Conditions.AsPathLength) + }, + func() (table.Condition, error) { + return NewRpkiValidationConditionFromApiStruct(a.Conditions.RpkiResult) + }, + func() (table.Condition, error) { + return NewAsPathConditionFromApiStruct(a.Conditions.AsPathSet) + }, + func() (table.Condition, error) { + return NewCommunityConditionFromApiStruct(a.Conditions.CommunitySet) + }, + func() (table.Condition, error) { + return NewExtCommunityConditionFromApiStruct(a.Conditions.ExtCommunitySet) + }, + } + cs = make([]table.Condition, 0, len(cfs)) + for _, f := range cfs { + c, err := f() + if err != nil { + return nil, err + } + if !reflect.ValueOf(c).IsNil() { + cs = append(cs, c) + } + } + } + if a.Actions != nil { + ra, err = NewRoutingActionFromApiStruct(a.Actions.RouteAction) + if err != nil { + return nil, err + } + afs := []func() (table.Action, error){ + func() (table.Action, error) { + return NewCommunityActionFromApiStruct(a.Actions.Community) + }, + func() (table.Action, error) { + return NewExtCommunityActionFromApiStruct(a.Actions.ExtCommunity) + }, + func() (table.Action, error) { + return NewMedActionFromApiStruct(a.Actions.Med) + }, + func() (table.Action, error) { + return NewLocalPrefActionFromApiStruct(a.Actions.LocalPref) + }, + func() (table.Action, error) { + return NewAsPathPrependActionFromApiStruct(a.Actions.AsPrepend) + }, + func() (table.Action, error) { + return NewNexthopActionFromApiStruct(a.Actions.Nexthop) + }, + } + as = make([]table.Action, 0, len(afs)) + for _, f := range afs { + a, err := f() + if err != nil { + return nil, err + } + if !reflect.ValueOf(a).IsNil() { + as = append(as, a) + } + } + } + return &table.Statement{ + Name: a.Name, + Conditions: cs, + RouteAction: ra, + ModActions: as, + }, nil +} + +func (s *Server) GetStatement(ctx context.Context, arg *api.GetStatementRequest) (*api.GetStatementResponse, error) { + l := make([]*api.Statement, 0) + for _, s := range s.bgpServer.GetStatement() { + l = append(l, toStatementApi(s)) + } + return &api.GetStatementResponse{Statements: l}, nil +} + +func (s *Server) AddStatement(ctx context.Context, arg *api.AddStatementRequest) (*api.AddStatementResponse, error) { + st, err := NewStatementFromApiStruct(arg.Statement) + if err == nil { + err = s.bgpServer.AddStatement(st) + } + return &api.AddStatementResponse{}, err +} + +func (s *Server) DeleteStatement(ctx context.Context, arg *api.DeleteStatementRequest) (*api.DeleteStatementResponse, error) { + st, err := NewStatementFromApiStruct(arg.Statement) + if err == nil { + err = s.bgpServer.DeleteStatement(st, arg.All) + } + return &api.DeleteStatementResponse{}, err +} + +func (s *Server) ReplaceStatement(ctx context.Context, arg *api.ReplaceStatementRequest) (*api.ReplaceStatementResponse, error) { + st, err := NewStatementFromApiStruct(arg.Statement) + if err == nil { + err = s.bgpServer.ReplaceStatement(st) + } + return &api.ReplaceStatementResponse{}, err } func toPolicyApi(p *config.PolicyDefinition) *api.Policy { @@ -1066,52 +1411,100 @@ func toPolicyApi(p *config.PolicyDefinition) *api.Policy { } } -func (s *Server) GetPolicy(ctx context.Context, arg *api.GetPolicyRequest) (*api.GetPolicyResponse, error) { - d, err := s.get(REQ_GET_POLICY, arg) - if err != nil { - return nil, err +func NewPolicyFromApiStruct(a *api.Policy) (*table.Policy, error) { + if a.Name == "" { + return nil, fmt.Errorf("empty policy name") + } + stmts := make([]*table.Statement, 0, len(a.Statements)) + for idx, x := range a.Statements { + if x.Name == "" { + x.Name = fmt.Sprintf("%s_stmt%d", a.Name, idx) + } + y, err := NewStatementFromApiStruct(x) + if err != nil { + return nil, err + } + stmts = append(stmts, y) } + return &table.Policy{ + Name: a.Name, + Statements: stmts, + }, nil +} + +func (s *Server) GetPolicy(ctx context.Context, arg *api.GetPolicyRequest) (*api.GetPolicyResponse, error) { l := make([]*api.Policy, 0) - for _, p := range d.([]*config.PolicyDefinition) { + for _, p := range s.bgpServer.GetPolicy() { l = append(l, toPolicyApi(p)) } - return &api.GetPolicyResponse{Policies: l}, err + return &api.GetPolicyResponse{Policies: l}, nil } func (s *Server) AddPolicy(ctx context.Context, arg *api.AddPolicyRequest) (*api.AddPolicyResponse, error) { - d, err := s.get(REQ_ADD_POLICY, arg) + x, err := NewPolicyFromApiStruct(arg.Policy) if err != nil { return nil, err } - return d.(*api.AddPolicyResponse), err + return &api.AddPolicyResponse{}, s.bgpServer.AddPolicy(x, arg.ReferExistingStatements) } func (s *Server) DeletePolicy(ctx context.Context, arg *api.DeletePolicyRequest) (*api.DeletePolicyResponse, error) { - d, err := s.get(REQ_DELETE_POLICY, arg) + x, err := NewPolicyFromApiStruct(arg.Policy) if err != nil { return nil, err } - return d.(*api.DeletePolicyResponse), err + return &api.DeletePolicyResponse{}, s.bgpServer.DeletePolicy(x, arg.All, arg.PreserveStatements) } func (s *Server) ReplacePolicy(ctx context.Context, arg *api.ReplacePolicyRequest) (*api.ReplacePolicyResponse, error) { - d, err := s.get(REQ_REPLACE_POLICY, arg) + x, err := NewPolicyFromApiStruct(arg.Policy) if err != nil { return nil, err } - return d.(*api.ReplacePolicyResponse), err + return &api.ReplacePolicyResponse{}, s.bgpServer.ReplacePolicy(x, arg.ReferExistingStatements, arg.PreserveStatements) +} + +func toPolicyAssignmentName(a *api.PolicyAssignment) (string, table.PolicyDirection, error) { + switch a.Resource { + case api.Resource_GLOBAL: + switch a.Type { + case api.PolicyType_IMPORT: + return "", table.POLICY_DIRECTION_IMPORT, nil + case api.PolicyType_EXPORT: + return "", table.POLICY_DIRECTION_EXPORT, nil + default: + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") + } + case api.Resource_LOCAL: + switch a.Type { + case api.PolicyType_IN: + return a.Name, table.POLICY_DIRECTION_IN, nil + case api.PolicyType_IMPORT: + return a.Name, table.POLICY_DIRECTION_IMPORT, nil + case api.PolicyType_EXPORT: + return a.Name, table.POLICY_DIRECTION_EXPORT, nil + default: + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") + } + default: + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid resource type") + } + } func (s *Server) GetPolicyAssignment(ctx context.Context, arg *api.GetPolicyAssignmentRequest) (*api.GetPolicyAssignmentResponse, error) { - d, err := s.get(REQ_GET_POLICY_ASSIGNMENT, arg) + name, dir, err := toPolicyAssignmentName(arg.Assignment) + if err != nil { + return nil, err + } + d, a, err := s.bgpServer.GetPolicyAssignment(name, dir) if err != nil { return nil, err } - a := d.(*PolicyAssignment) return &api.GetPolicyAssignmentResponse{ Assignment: &api.PolicyAssignment{ Default: func() api.RouteAction { - switch a.Default { + switch d { case table.ROUTE_TYPE_ACCEPT: return api.RouteAction_ACCEPT case table.ROUTE_TYPE_REJECT: @@ -1122,7 +1515,7 @@ func (s *Server) GetPolicyAssignment(ctx context.Context, arg *api.GetPolicyAssi }(), Policies: func() []*api.Policy { l := make([]*api.Policy, 0) - for _, p := range a.PolicyDefinitions { + for _, p := range a { l = append(l, toPolicyApi(p)) } return l @@ -1131,28 +1524,47 @@ func (s *Server) GetPolicyAssignment(ctx context.Context, arg *api.GetPolicyAssi }, err } +func defaultRouteType(d api.RouteAction) table.RouteType { + switch d { + case api.RouteAction_ACCEPT: + return table.ROUTE_TYPE_ACCEPT + case api.RouteAction_REJECT: + return table.ROUTE_TYPE_REJECT + default: + return table.ROUTE_TYPE_NONE + } +} + +func toPolicyDefinition(policies []*api.Policy) []*config.PolicyDefinition { + l := make([]*config.PolicyDefinition, 0, len(policies)) + for _, p := range policies { + l = append(l, &config.PolicyDefinition{Name: p.Name}) + } + return l +} + func (s *Server) AddPolicyAssignment(ctx context.Context, arg *api.AddPolicyAssignmentRequest) (*api.AddPolicyAssignmentResponse, error) { - d, err := s.get(REQ_ADD_POLICY_ASSIGNMENT, arg) + name, dir, err := toPolicyAssignmentName(arg.Assignment) if err != nil { return nil, err } - return d.(*api.AddPolicyAssignmentResponse), err + return &api.AddPolicyAssignmentResponse{}, s.bgpServer.AddPolicyAssignment(name, dir, toPolicyDefinition(arg.Assignment.Policies), defaultRouteType(arg.Assignment.Default)) } func (s *Server) DeletePolicyAssignment(ctx context.Context, arg *api.DeletePolicyAssignmentRequest) (*api.DeletePolicyAssignmentResponse, error) { - d, err := s.get(REQ_DELETE_POLICY_ASSIGNMENT, arg) + name, dir, err := toPolicyAssignmentName(arg.Assignment) if err != nil { return nil, err } - return d.(*api.DeletePolicyAssignmentResponse), err + return &api.DeletePolicyAssignmentResponse{}, s.bgpServer.DeletePolicyAssignment(name, dir, toPolicyDefinition(arg.Assignment.Policies), arg.All) } func (s *Server) ReplacePolicyAssignment(ctx context.Context, arg *api.ReplacePolicyAssignmentRequest) (*api.ReplacePolicyAssignmentResponse, error) { - d, err := s.get(REQ_REPLACE_POLICY_ASSIGNMENT, arg) + name, dir, err := toPolicyAssignmentName(arg.Assignment) if err != nil { return nil, err } - return d.(*api.ReplacePolicyAssignmentResponse), err + return &api.ReplacePolicyAssignmentResponse{}, s.bgpServer.ReplacePolicyAssignment(name, dir, toPolicyDefinition(arg.Assignment.Policies), defaultRouteType(arg.Assignment.Default)) } func (s *Server) GetServer(ctx context.Context, arg *api.GetServerRequest) (*api.GetServerResponse, error) { @@ -1220,10 +1632,11 @@ func (r *GrpcResponse) Err() error { return r.ResponseErr } -func NewGrpcServer(hosts string, bgpServerCh chan *GrpcRequest) *Server { +func NewGrpcServer(b *BgpServer, hosts string, bgpServerCh chan *GrpcRequest) *Server { grpc.EnableTracing = false grpcServer := grpc.NewServer() server := &Server{ + bgpServer: b, grpcServer: grpcServer, bgpServerCh: bgpServerCh, hosts: hosts, diff --git a/server/server.go b/server/server.go index 09d63259..381f1f61 100644 --- a/server/server.go +++ b/server/server.go @@ -945,15 +945,16 @@ func (server *BgpServer) Shutdown() { // TODO: call fsmincomingCh.Close() } -func (server *BgpServer) UpdatePolicy(policy config.RoutingPolicy) error { - ch := make(chan *GrpcResponse) - server.GrpcReqCh <- &GrpcRequest{ - RequestType: REQ_RELOAD_POLICY, - Data: policy, - ResponseCh: ch, +func (s *BgpServer) UpdatePolicy(policy config.RoutingPolicy) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + defer close(ch) + + err = s.handlePolicy(policy) } - res := <-ch - return res.Err() + return err } // This function MUST be called with policyMutex locked. @@ -1942,118 +1943,6 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) { ResponseErr: err, } close(grpcReq.ResponseCh) - case REQ_GET_DEFINED_SET: - rsp, err := server.handleGrpcGetDefinedSet(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_ADD_DEFINED_SET: - rsp, err := server.handleGrpcAddDefinedSet(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_DELETE_DEFINED_SET: - rsp, err := server.handleGrpcDeleteDefinedSet(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_REPLACE_DEFINED_SET: - rsp, err := server.handleGrpcReplaceDefinedSet(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_GET_STATEMENT: - rsp, err := server.handleGrpcGetStatement(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_ADD_STATEMENT: - data, err := server.handleGrpcAddStatement(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_DELETE_STATEMENT: - data, err := server.handleGrpcDeleteStatement(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_REPLACE_STATEMENT: - data, err := server.handleGrpcReplaceStatement(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_GET_POLICY: - rsp, err := server.handleGrpcGetPolicy(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: rsp, - } - close(grpcReq.ResponseCh) - case REQ_ADD_POLICY: - data, err := server.handleGrpcAddPolicy(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_DELETE_POLICY: - data, err := server.handleGrpcDeletePolicy(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_REPLACE_POLICY: - data, err := server.handleGrpcReplacePolicy(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_GET_POLICY_ASSIGNMENT: - data, err := server.handleGrpcGetPolicyAssignment(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_ADD_POLICY_ASSIGNMENT: - data, err := server.handleGrpcAddPolicyAssignment(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_DELETE_POLICY_ASSIGNMENT: - data, err := server.handleGrpcDeletePolicyAssignment(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) - case REQ_REPLACE_POLICY_ASSIGNMENT: - data, err := server.handleGrpcReplacePolicyAssignment(grpcReq) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - Data: data, - } - close(grpcReq.ResponseCh) case REQ_MONITOR_RIB, REQ_MONITOR_NEIGHBOR_PEER_STATE: if grpcReq.Name != "" { if _, err = server.checkNeighborRequest(grpcReq); err != nil { @@ -2095,12 +1984,6 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) { if len(pathList) > 0 { server.propagateUpdate(nil, pathList) } - case REQ_RELOAD_POLICY: - err := server.handlePolicy(grpcReq.Data.(config.RoutingPolicy)) - grpcReq.ResponseCh <- &GrpcResponse{ - ResponseErr: err, - } - close(grpcReq.ResponseCh) case REQ_INITIALIZE_ZEBRA: c := grpcReq.Data.(*config.ZebraConfig) protos := make([]string, 0, len(c.RedistributeRouteTypeList)) @@ -2287,200 +2170,260 @@ func (server *BgpServer) handleUpdateNeighbor(c *config.Neighbor) (bool, error) return policyUpdated, err } -func (server *BgpServer) handleGrpcGetDefinedSet(grpcReq *GrpcRequest) (*config.DefinedSets, error) { - arg := grpcReq.Data.(*api.GetDefinedSetRequest) - typ := table.DefinedType(arg.Type) - set, ok := server.policy.DefinedSetMap[typ] - if !ok { - return nil, fmt.Errorf("invalid defined-set type: %d", typ) - } - sets := config.DefinedSets{ - PrefixSets: make([]config.PrefixSet, 0), - NeighborSets: make([]config.NeighborSet, 0), - BgpDefinedSets: config.BgpDefinedSets{ - CommunitySets: make([]config.CommunitySet, 0), - ExtCommunitySets: make([]config.ExtCommunitySet, 0), - AsPathSets: make([]config.AsPathSet, 0), - }, - } - for _, s := range set { - switch s.(type) { - case *table.PrefixSet: - sets.PrefixSets = append(sets.PrefixSets, *s.(*table.PrefixSet).ToConfig()) - case *table.NeighborSet: - sets.NeighborSets = append(sets.NeighborSets, *s.(*table.NeighborSet).ToConfig()) - case *table.CommunitySet: - sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *s.(*table.CommunitySet).ToConfig()) - case *table.ExtCommunitySet: - sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *s.(*table.ExtCommunitySet).ToConfig()) - case *table.AsPathSet: - sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *s.(*table.AsPathSet).ToConfig()) +func (s *BgpServer) GetDefinedSet(typ table.DefinedType) (sets *config.DefinedSets, err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + set, ok := s.policy.DefinedSetMap[typ] + if !ok { + err = fmt.Errorf("invalid defined-set type: %d", typ) + return + } + sets = &config.DefinedSets{ + PrefixSets: make([]config.PrefixSet, 0), + NeighborSets: make([]config.NeighborSet, 0), + BgpDefinedSets: config.BgpDefinedSets{ + CommunitySets: make([]config.CommunitySet, 0), + ExtCommunitySets: make([]config.ExtCommunitySet, 0), + AsPathSets: make([]config.AsPathSet, 0), + }, + } + for _, s := range set { + switch s.(type) { + case *table.PrefixSet: + sets.PrefixSets = append(sets.PrefixSets, *s.(*table.PrefixSet).ToConfig()) + case *table.NeighborSet: + sets.NeighborSets = append(sets.NeighborSets, *s.(*table.NeighborSet).ToConfig()) + case *table.CommunitySet: + sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *s.(*table.CommunitySet).ToConfig()) + case *table.ExtCommunitySet: + sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *s.(*table.ExtCommunitySet).ToConfig()) + case *table.AsPathSet: + sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *s.(*table.AsPathSet).ToConfig()) + } } } - return &sets, nil + return sets, nil } -func (server *BgpServer) handleGrpcAddDefinedSet(grpcReq *GrpcRequest) (*api.AddDefinedSetResponse, error) { - arg := grpcReq.Data.(*api.AddDefinedSetRequest) - set := arg.Set - typ := table.DefinedType(set.Type) - name := set.Name - var err error - m, ok := server.policy.DefinedSetMap[typ] - if !ok { - return nil, fmt.Errorf("invalid defined-set type: %d", typ) - } - d, ok := m[name] - s, err := table.NewDefinedSetFromApiStruct(set) - if err != nil { - return nil, err - } - if ok { - err = d.Append(s) - } else { - m[name] = s +func (s *BgpServer) AddDefinedSet(a table.DefinedSet) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { + err = fmt.Errorf("invalid defined-set type: %d", a.Type()) + } else { + if d, ok := m[a.Name()]; ok { + err = d.Append(a) + } else { + m[a.Name()] = a + } + } } - return &api.AddDefinedSetResponse{}, err + return err } -func (server *BgpServer) handleGrpcDeleteDefinedSet(grpcReq *GrpcRequest) (*api.DeleteDefinedSetResponse, error) { - arg := grpcReq.Data.(*api.DeleteDefinedSetRequest) - set := arg.Set - typ := table.DefinedType(set.Type) - name := set.Name - var err error - m, ok := server.policy.DefinedSetMap[typ] - if !ok { - return nil, fmt.Errorf("invalid defined-set type: %d", typ) - } - d, ok := m[name] - if !ok { - return nil, fmt.Errorf("not found defined-set: %s", name) - } - s, err := table.NewDefinedSetFromApiStruct(set) - if err != nil { - return nil, err - } - if arg.All { - if server.policy.InUse(d) { - return nil, fmt.Errorf("can't delete. defined-set %s is in use", name) +func (s *BgpServer) DeleteDefinedSet(a table.DefinedSet, all bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { + err = fmt.Errorf("invalid defined-set type: %d", a.Type()) + } else { + d, ok := m[a.Name()] + if !ok { + err = fmt.Errorf("not found defined-set: %s", a.Name()) + return + } + if all { + if s.policy.InUse(d) { + err = fmt.Errorf("can't delete. defined-set %s is in use", a.Name()) + } else { + delete(m, a.Name()) + } + } else { + err = d.Remove(a) + } } - delete(m, name) - } else { - err = d.Remove(s) } - return &api.DeleteDefinedSetResponse{}, err + return err } -func (server *BgpServer) handleGrpcReplaceDefinedSet(grpcReq *GrpcRequest) (*api.ReplaceDefinedSetResponse, error) { - arg := grpcReq.Data.(*api.ReplaceDefinedSetRequest) - set := arg.Set - typ := table.DefinedType(set.Type) - name := set.Name - var err error - m, ok := server.policy.DefinedSetMap[typ] - if !ok { - return nil, fmt.Errorf("invalid defined-set type: %d", typ) - } - d, ok := m[name] - if !ok { - return nil, fmt.Errorf("not found defined-set: %s", name) - } - s, err := table.NewDefinedSetFromApiStruct(set) - if err != nil { - return nil, err +func (s *BgpServer) ReplaceDefinedSet(a table.DefinedSet) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { + err = fmt.Errorf("invalid defined-set type: %d", a.Type()) + } else { + if d, ok := m[a.Name()]; !ok { + err = fmt.Errorf("not found defined-set: %s", a.Name()) + } else { + err = d.Replace(a) + } + } } - return &api.ReplaceDefinedSetResponse{}, d.Replace(s) + return err } -func (server *BgpServer) handleGrpcGetStatement(grpcReq *GrpcRequest) ([]*config.Statement, error) { - l := make([]*config.Statement, 0) - for _, s := range server.policy.StatementMap { - l = append(l, s.ToConfig()) +func (s *BgpServer) GetStatement() (l []*config.Statement) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + l = make([]*config.Statement, 0, len(s.policy.StatementMap)) + for _, st := range s.policy.StatementMap { + l = append(l, st.ToConfig()) + } } - return l, nil + return l } -func (server *BgpServer) handleGrpcAddStatement(grpcReq *GrpcRequest) (*api.AddStatementResponse, error) { - var err error - arg := grpcReq.Data.(*api.AddStatementRequest) - s, err := table.NewStatementFromApiStruct(arg.Statement, server.policy.DefinedSetMap) - if err != nil { - return nil, err - } - m := server.policy.StatementMap - name := s.Name - if d, ok := m[name]; ok { - err = d.Add(s) - } else { - m[name] = s +func (s *BgpServer) AddStatement(st *table.Statement) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + for _, c := range st.Conditions { + if err = s.policy.ValidateCondition(c); err != nil { + return + } + } + m := s.policy.StatementMap + name := st.Name + if d, ok := m[name]; ok { + err = d.Add(st) + } else { + m[name] = st + } } - return &api.AddStatementResponse{}, err + return err } -func (server *BgpServer) handleGrpcDeleteStatement(grpcReq *GrpcRequest) (*api.DeleteStatementResponse, error) { - var err error - arg := grpcReq.Data.(*api.DeleteStatementRequest) - s, err := table.NewStatementFromApiStruct(arg.Statement, server.policy.DefinedSetMap) - if err != nil { - return nil, err - } - m := server.policy.StatementMap - name := s.Name - if d, ok := m[name]; ok { - if arg.All { - if server.policy.StatementInUse(d) { - err = fmt.Errorf("can't delete. statement %s is in use", name) +func (s *BgpServer) DeleteStatement(st *table.Statement, all bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + m := s.policy.StatementMap + name := st.Name + if d, ok := m[name]; ok { + if all { + if s.policy.StatementInUse(d) { + err = fmt.Errorf("can't delete. statement %s is in use", name) + } else { + delete(m, name) + } } else { - delete(m, name) + err = d.Remove(st) } } else { - err = d.Remove(s) + err = fmt.Errorf("not found statement: %s", name) } - } else { - err = fmt.Errorf("not found statement: %s", name) } - return &api.DeleteStatementResponse{}, err + return err } -func (server *BgpServer) handleGrpcReplaceStatement(grpcReq *GrpcRequest) (*api.ReplaceStatementResponse, error) { - var err error - arg := grpcReq.Data.(*api.ReplaceStatementRequest) - s, err := table.NewStatementFromApiStruct(arg.Statement, server.policy.DefinedSetMap) - if err != nil { - return nil, err - } - m := server.policy.StatementMap - name := s.Name - if d, ok := m[name]; ok { - err = d.Replace(s) - } else { - err = fmt.Errorf("not found statement: %s", name) +func (s *BgpServer) ReplaceStatement(st *table.Statement) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + m := s.policy.StatementMap + name := st.Name + if d, ok := m[name]; ok { + err = d.Replace(st) + } else { + err = fmt.Errorf("not found statement: %s", name) + } } - return &api.ReplaceStatementResponse{}, err + return err } -func (server *BgpServer) handleGrpcGetPolicy(grpcReq *GrpcRequest) ([]*config.PolicyDefinition, error) { - policies := make([]*config.PolicyDefinition, 0, len(server.policy.PolicyMap)) - for _, s := range server.policy.PolicyMap { - policies = append(policies, s.ToConfig()) +func (s *BgpServer) GetPolicy() (l []*config.PolicyDefinition) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + l := make([]*config.PolicyDefinition, 0, len(s.policy.PolicyMap)) + for _, p := range s.policy.PolicyMap { + l = append(l, p.ToConfig()) + } } - return policies, nil + return l } -func (server *BgpServer) policyInUse(x *table.Policy) bool { - for _, peer := range server.neighborMap { +func (s *BgpServer) policyInUse(x *table.Policy) bool { + for _, peer := range s.neighborMap { for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_IN, table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range server.policy.GetPolicy(peer.ID(), dir) { - if x.Name() == y.Name() { + for _, y := range s.policy.GetPolicy(peer.ID(), dir) { + if x.Name == y.Name { return true } } } } for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range server.policy.GetPolicy(table.GLOBAL_RIB_NAME, dir) { - if x.Name() == y.Name() { + for _, y := range s.policy.GetPolicy(table.GLOBAL_RIB_NAME, dir) { + if x.Name == y.Name { return true } } @@ -2488,326 +2431,353 @@ func (server *BgpServer) policyInUse(x *table.Policy) bool { return false } -func (server *BgpServer) handleGrpcAddPolicy(grpcReq *GrpcRequest) (*api.AddPolicyResponse, error) { - policyMutex.Lock() - defer policyMutex.Unlock() - rsp := &api.AddPolicyResponse{} - arg := grpcReq.Data.(*api.AddPolicyRequest) - x, err := table.NewPolicyFromApiStruct(arg.Policy, server.policy.DefinedSetMap) - if err != nil { - return rsp, err - } - pMap := server.policy.PolicyMap - sMap := server.policy.StatementMap - name := x.Name() - y, ok := pMap[name] - if arg.ReferExistingStatements { - err = x.FillUp(sMap) - } else { - for _, s := range x.Statements { - if _, ok := sMap[s.Name]; ok { - return rsp, fmt.Errorf("statement %s already defined", s.Name) +func (s *BgpServer) AddPolicy(x *table.Policy, refer bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + for _, st := range x.Statements { + for _, c := range st.Conditions { + if err = s.policy.ValidateCondition(c); err != nil { + return + } } - sMap[s.Name] = s + } + + pMap := s.policy.PolicyMap + sMap := s.policy.StatementMap + name := x.Name + y, ok := pMap[name] + if refer { + err = x.FillUp(sMap) + } else { + for _, st := range x.Statements { + if _, ok := sMap[st.Name]; ok { + err = fmt.Errorf("statement %s already defined", st.Name) + return + } + sMap[st.Name] = st + } + } + if ok { + err = y.Add(x) + } else { + pMap[name] = x } } - if ok { - err = y.Add(x) - } else { - pMap[name] = x - } - return &api.AddPolicyResponse{}, err + return err } -func (server *BgpServer) handleGrpcDeletePolicy(grpcReq *GrpcRequest) (*api.DeletePolicyResponse, error) { - policyMutex.Lock() - defer policyMutex.Unlock() - rsp := &api.DeletePolicyResponse{} - arg := grpcReq.Data.(*api.DeletePolicyRequest) - x, err := table.NewPolicyFromApiStruct(arg.Policy, server.policy.DefinedSetMap) - if err != nil { - return rsp, err - } - pMap := server.policy.PolicyMap - sMap := server.policy.StatementMap - name := x.Name() - y, ok := pMap[name] - if !ok { - return rsp, fmt.Errorf("not found policy: %s", name) - } - if arg.All { - if server.policyInUse(y) { - return rsp, fmt.Errorf("can't delete. policy %s is in use", name) +func (s *BgpServer) DeletePolicy(x *table.Policy, all, preserve bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + pMap := s.policy.PolicyMap + sMap := s.policy.StatementMap + name := x.Name + y, ok := pMap[name] + if !ok { + err = fmt.Errorf("not found policy: %s", name) + return } - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": name, - }).Debug("delete policy") - delete(pMap, name) - } else { - err = y.Remove(x) - } - if err == nil && !arg.PreserveStatements { - for _, s := range y.Statements { - if !server.policy.StatementInUse(s) { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": s.Name, - }).Debug("delete unused statement") - delete(sMap, s.Name) + if all { + if s.policyInUse(y) { + err = fmt.Errorf("can't delete. policy %s is in use", name) + return + } + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": name, + }).Debug("delete policy") + delete(pMap, name) + } else { + err = y.Remove(x) + } + if err == nil && !preserve { + for _, st := range y.Statements { + if !s.policy.StatementInUse(st) { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": st.Name, + }).Debug("delete unused statement") + delete(sMap, st.Name) + } } } } - return rsp, err + return err } -func (server *BgpServer) handleGrpcReplacePolicy(grpcReq *GrpcRequest) (*api.ReplacePolicyResponse, error) { - policyMutex.Lock() - defer policyMutex.Unlock() - rsp := &api.ReplacePolicyResponse{} - arg := grpcReq.Data.(*api.ReplacePolicyRequest) - x, err := table.NewPolicyFromApiStruct(arg.Policy, server.policy.DefinedSetMap) - if err != nil { - return rsp, err - } - pMap := server.policy.PolicyMap - sMap := server.policy.StatementMap - name := x.Name() - y, ok := pMap[name] - if !ok { - return rsp, fmt.Errorf("not found policy: %s", name) - } - if arg.ReferExistingStatements { - if err = x.FillUp(sMap); err != nil { - return rsp, err +func (s *BgpServer) ReplacePolicy(x *table.Policy, refer, preserve bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + for _, st := range x.Statements { + for _, c := range st.Conditions { + if err = s.policy.ValidateCondition(c); err != nil { + return + } + } } - } else { - for _, s := range x.Statements { - if _, ok := sMap[s.Name]; ok { - return rsp, fmt.Errorf("statement %s already defined", s.Name) + + pMap := s.policy.PolicyMap + sMap := s.policy.StatementMap + name := x.Name + y, ok := pMap[name] + if !ok { + err = fmt.Errorf("not found policy: %s", name) + return + } + if refer { + if err = x.FillUp(sMap); err != nil { + return + } + } else { + for _, st := range x.Statements { + if _, ok := sMap[st.Name]; ok { + err = fmt.Errorf("statement %s already defined", st.Name) + return + } + sMap[st.Name] = st } - sMap[s.Name] = s } - } - err = y.Replace(x) - if err == nil && !arg.PreserveStatements { - for _, s := range y.Statements { - if !server.policy.StatementInUse(s) { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": s.Name, - }).Debug("delete unused statement") - delete(sMap, s.Name) + err = y.Replace(x) + if err == nil && !preserve { + for _, st := range y.Statements { + if !s.policy.StatementInUse(st) { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": st.Name, + }).Debug("delete unused statement") + delete(sMap, st.Name) + } } } } - return rsp, err + return err } -func (server *BgpServer) getPolicyInfo(a *api.PolicyAssignment) (string, table.PolicyDirection, error) { - switch a.Resource { - case api.Resource_GLOBAL: - switch a.Type { - case api.PolicyType_IMPORT: - return table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT, nil - case api.PolicyType_EXPORT: - return table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_EXPORT, nil - default: - return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") +func (server *BgpServer) toPolicyInfo(name string, dir table.PolicyDirection) (string, error) { + if name == "" { + switch dir { + case table.POLICY_DIRECTION_IMPORT, table.POLICY_DIRECTION_EXPORT: + return table.GLOBAL_RIB_NAME, nil } - case api.Resource_LOCAL: - peer, ok := server.neighborMap[a.Name] + return "", fmt.Errorf("invalid policy type") + } else { + peer, ok := server.neighborMap[name] if !ok { - return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("not found peer %s", a.Name) + return "", fmt.Errorf("not found peer %s", name) } if !peer.isRouteServerClient() { - return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("non-rs-client peer %s doesn't have per peer policy", a.Name) - } - switch a.Type { - case api.PolicyType_IN: - return peer.ID(), table.POLICY_DIRECTION_IN, nil - case api.PolicyType_IMPORT: - return peer.ID(), table.POLICY_DIRECTION_IMPORT, nil - case api.PolicyType_EXPORT: - return peer.ID(), table.POLICY_DIRECTION_EXPORT, nil - default: - return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") + return "", fmt.Errorf("non-rs-client peer %s doesn't have per peer policy", name) } - default: - return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid resource type") + return peer.ID(), nil } - } -// temporarily -type PolicyAssignment struct { - Default table.RouteType - PolicyDefinitions []*config.PolicyDefinition -} +func (s *BgpServer) GetPolicyAssignment(name string, dir table.PolicyDirection) (rt table.RouteType, l []*config.PolicyDefinition, err error) { + ch := make(chan struct{}) + defer func() { <-ch }() -func (server *BgpServer) handleGrpcGetPolicyAssignment(grpcReq *GrpcRequest) (*PolicyAssignment, error) { - id, dir, err := server.getPolicyInfo(grpcReq.Data.(*api.GetPolicyAssignmentRequest).Assignment) - if err != nil { - return nil, err - } - return &PolicyAssignment{ - Default: server.policy.GetDefaultPolicy(id, dir), - PolicyDefinitions: func() []*config.PolicyDefinition { - ps := server.policy.GetPolicy(id, dir) - l := make([]*config.PolicyDefinition, 0, len(ps)) + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + var id string + id, err = s.toPolicyInfo(name, dir) + if err != nil { + rt = table.ROUTE_TYPE_NONE + } else { + rt = s.policy.GetDefaultPolicy(id, dir) + + ps := s.policy.GetPolicy(id, dir) + l = make([]*config.PolicyDefinition, 0, len(ps)) for _, p := range ps { l = append(l, p.ToConfig()) } - return l - }(), - }, nil + } + } + return rt, l, err } -func (server *BgpServer) handleGrpcAddPolicyAssignment(grpcReq *GrpcRequest) (*api.AddPolicyAssignmentResponse, error) { - var err error - var dir table.PolicyDirection - var id string - rsp := &api.AddPolicyAssignmentResponse{} - policyMutex.Lock() - defer policyMutex.Unlock() - arg := grpcReq.Data.(*api.AddPolicyAssignmentRequest) - assignment := arg.Assignment - id, dir, err = server.getPolicyInfo(assignment) - if err != nil { - return rsp, err - } - ps := make([]*table.Policy, 0, len(assignment.Policies)) - seen := make(map[string]bool) - for _, x := range assignment.Policies { - p, ok := server.policy.PolicyMap[x.Name] - if !ok { - return rsp, fmt.Errorf("not found policy %s", x.Name) +func (s *BgpServer) AddPolicyAssignment(name string, dir table.PolicyDirection, policies []*config.PolicyDefinition, def table.RouteType) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + var id string + id, err = s.toPolicyInfo(name, dir) + if err != nil { + return } - if seen[x.Name] { - return rsp, fmt.Errorf("duplicated policy %s", x.Name) + + ps := make([]*table.Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := s.policy.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return + } + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) } - seen[x.Name] = true - ps = append(ps, p) - } - cur := server.policy.GetPolicy(id, dir) - if cur == nil { - err = server.policy.SetPolicy(id, dir, ps) - } else { - seen = make(map[string]bool) - ps = append(cur, ps...) - for _, x := range ps { - if seen[x.Name()] { - return rsp, fmt.Errorf("duplicated policy %s", x.Name()) + cur := s.policy.GetPolicy(id, dir) + if cur == nil { + err = s.policy.SetPolicy(id, dir, ps) + } else { + seen = make(map[string]bool) + ps = append(cur, ps...) + for _, x := range ps { + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true } - seen[x.Name()] = true + err = s.policy.SetPolicy(id, dir, ps) + } + if err == nil && def != table.ROUTE_TYPE_NONE { + err = s.policy.SetDefaultPolicy(id, dir, def) } - err = server.policy.SetPolicy(id, dir, ps) - } - if err != nil { - return rsp, err - } - - switch assignment.Default { - case api.RouteAction_ACCEPT: - err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_ACCEPT) - case api.RouteAction_REJECT: - err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_REJECT) } - return rsp, err + return err } -func (server *BgpServer) handleGrpcDeletePolicyAssignment(grpcReq *GrpcRequest) (*api.DeletePolicyAssignmentResponse, error) { - var err error - var dir table.PolicyDirection - var id string - policyMutex.Lock() - defer policyMutex.Unlock() - rsp := &api.DeletePolicyAssignmentResponse{} - arg := grpcReq.Data.(*api.DeletePolicyAssignmentRequest) - assignment := arg.Assignment - id, dir, err = server.getPolicyInfo(assignment) - if err != nil { - return rsp, err - } - ps := make([]*table.Policy, 0, len(assignment.Policies)) - seen := make(map[string]bool) - for _, x := range assignment.Policies { - p, ok := server.policy.PolicyMap[x.Name] - if !ok { - return rsp, fmt.Errorf("not found policy %s", x.Name) - } - if seen[x.Name] { - return rsp, fmt.Errorf("duplicated policy %s", x.Name) - } - seen[x.Name] = true - ps = append(ps, p) - } - cur := server.policy.GetPolicy(id, dir) +func (s *BgpServer) DeletePolicyAssignment(name string, dir table.PolicyDirection, policies []*config.PolicyDefinition, all bool) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() - if arg.All { - err = server.policy.SetPolicy(id, dir, nil) + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + var id string + id, err = s.toPolicyInfo(name, dir) if err != nil { - return rsp, err + return } - err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_NONE) - } else { - n := make([]*table.Policy, 0, len(cur)-len(ps)) - for _, y := range cur { - found := false - for _, x := range ps { - if x.Name() == y.Name() { - found = true - break - } + + ps := make([]*table.Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := s.policy.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return } - if !found { - n = append(n, y) + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) + } + cur := s.policy.GetPolicy(id, dir) + + if all { + err = s.policy.SetPolicy(id, dir, nil) + if err != nil { + return + } + err = s.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_NONE) + } else { + n := make([]*table.Policy, 0, len(cur)-len(ps)) + for _, y := range cur { + found := false + for _, x := range ps { + if x.Name == y.Name { + found = true + break + } + } + if !found { + n = append(n, y) + } } + err = s.policy.SetPolicy(id, dir, n) } - err = server.policy.SetPolicy(id, dir, n) } - return rsp, err + return err } -func (server *BgpServer) handleGrpcReplacePolicyAssignment(grpcReq *GrpcRequest) (*api.ReplacePolicyAssignmentResponse, error) { - var err error - var dir table.PolicyDirection - var id string - policyMutex.Lock() - defer policyMutex.Unlock() - rsp := &api.ReplacePolicyAssignmentResponse{} - arg := grpcReq.Data.(*api.ReplacePolicyAssignmentRequest) - assignment := arg.Assignment - id, dir, err = server.getPolicyInfo(assignment) - if err != nil { - return rsp, err - } - ps := make([]*table.Policy, 0, len(assignment.Policies)) - seen := make(map[string]bool) - for _, x := range assignment.Policies { - p, ok := server.policy.PolicyMap[x.Name] - if !ok { - return rsp, fmt.Errorf("not found policy %s", x.Name) +func (s *BgpServer) ReplacePolicyAssignment(name string, dir table.PolicyDirection, policies []*config.PolicyDefinition, def table.RouteType) (err error) { + ch := make(chan struct{}) + defer func() { <-ch }() + + s.mgmtCh <- func() { + policyMutex.Lock() + defer func() { + policyMutex.Unlock() + close(ch) + }() + + var id string + id, err = s.toPolicyInfo(name, dir) + if err != nil { + return } - if seen[x.Name] { - return rsp, fmt.Errorf("duplicated policy %s", x.Name) + + ps := make([]*table.Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := s.policy.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return + } + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) + } + s.policy.GetPolicy(id, dir) + err = s.policy.SetPolicy(id, dir, ps) + if err == nil && def != table.ROUTE_TYPE_NONE { + err = s.policy.SetDefaultPolicy(id, dir, def) } - seen[x.Name] = true - ps = append(ps, p) - } - server.policy.GetPolicy(id, dir) - err = server.policy.SetPolicy(id, dir, ps) - if err != nil { - return rsp, err - } - switch assignment.Default { - case api.RouteAction_ACCEPT: - err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_ACCEPT) - case api.RouteAction_REJECT: - err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_REJECT) } - return rsp, err + return err } func grpcDone(grpcReq *GrpcRequest, e error) { diff --git a/server/server_test.go b/server/server_test.go index 48d7e52d..9a55f775 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -16,7 +16,6 @@ package server import ( - api "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/table" "github.com/stretchr/testify/assert" @@ -33,50 +32,21 @@ func TestModPolicyAssign(t *testing.T) { RouterId: "1.1.1.1", }, }) - _, err := s.handleGrpcAddPolicy(&GrpcRequest{ - Data: &api.AddPolicyRequest{ - Policy: &api.Policy{ - Name: "p1", - }, - }, - }) + err := s.AddPolicy(&table.Policy{Name: "p1"}, false) assert.Nil(err) - _, err = s.handleGrpcAddPolicy(&GrpcRequest{ - Data: &api.AddPolicyRequest{ - Policy: &api.Policy{ - Name: "p2", - }, - }, - }) + + err = s.AddPolicy(&table.Policy{Name: "p2"}, false) assert.Nil(err) - _, err = s.handleGrpcAddPolicy(&GrpcRequest{ - Data: &api.AddPolicyRequest{ - Policy: &api.Policy{ - Name: "p3", - }, - }, - }) + + err = s.AddPolicy(&table.Policy{Name: "p3"}, false) assert.Nil(err) - _, err = s.handleGrpcAddPolicyAssignment(&GrpcRequest{ - Data: &api.AddPolicyAssignmentRequest{ - Assignment: &api.PolicyAssignment{ - Type: api.PolicyType_IMPORT, - Resource: api.Resource_GLOBAL, - Policies: []*api.Policy{&api.Policy{Name: "p1"}, &api.Policy{Name: "p2"}, &api.Policy{Name: "p3"}}, - }, - }, - }) + + err = s.AddPolicyAssignment("", table.POLICY_DIRECTION_IMPORT, + []*config.PolicyDefinition{&config.PolicyDefinition{Name: "p1"}, &config.PolicyDefinition{Name: "p2"}, &config.PolicyDefinition{Name: "p3"}}, table.ROUTE_TYPE_ACCEPT) assert.Nil(err) - _, err = s.handleGrpcDeletePolicyAssignment(&GrpcRequest{ - Data: &api.DeletePolicyAssignmentRequest{ - Assignment: &api.PolicyAssignment{ - Type: api.PolicyType_IMPORT, - Resource: api.Resource_GLOBAL, - Policies: []*api.Policy{&api.Policy{Name: "p1"}}, - }, - }, - }) + err = s.DeletePolicyAssignment("", table.POLICY_DIRECTION_IMPORT, + []*config.PolicyDefinition{&config.PolicyDefinition{Name: "p1"}}, false) assert.Nil(err) ps := s.policy.GetPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT) diff --git a/table/policy.go b/table/policy.go index 09c4ea19..37aa4355 100644 --- a/table/policy.go +++ b/table/policy.go @@ -1,4 +1,4 @@ -// Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation. +// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -26,7 +26,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/armon/go-radix" - api "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet/bgp" ) @@ -96,34 +95,6 @@ func (o MatchOption) String() string { } } -func toConfigMatchSetOption(a api.MatchType) (config.MatchSetOptionsType, error) { - var typ config.MatchSetOptionsType - switch a { - case api.MatchType_ANY: - typ = config.MATCH_SET_OPTIONS_TYPE_ANY - case api.MatchType_ALL: - typ = config.MATCH_SET_OPTIONS_TYPE_ALL - case api.MatchType_INVERT: - typ = config.MATCH_SET_OPTIONS_TYPE_INVERT - default: - return typ, fmt.Errorf("invalid match type") - } - return typ, nil -} - -func toConfigMatchSetOptionRestricted(a api.MatchType) (config.MatchSetOptionsRestrictedType, error) { - var typ config.MatchSetOptionsRestrictedType - switch a { - case api.MatchType_ANY: - typ = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY - case api.MatchType_INVERT: - typ = config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT - default: - return typ, fmt.Errorf("invalid match type") - } - return typ, nil -} - type MedActionType int const ( @@ -255,23 +226,6 @@ func (lhs *Prefix) Equal(rhs *Prefix) bool { return lhs.Prefix.String() == rhs.Prefix.String() && lhs.MasklengthRangeMin == rhs.MasklengthRangeMin && lhs.MasklengthRangeMax == rhs.MasklengthRangeMax } -func NewPrefixFromApiStruct(a *api.Prefix) (*Prefix, error) { - addr, prefix, err := net.ParseCIDR(a.IpPrefix) - if err != nil { - return nil, err - } - rf := bgp.RF_IPv4_UC - if addr.To4() == nil { - rf = bgp.RF_IPv6_UC - } - return &Prefix{ - Prefix: prefix, - AddressFamily: rf, - MasklengthRangeMin: uint8(a.MaskLengthMin), - MasklengthRangeMax: uint8(a.MaskLengthMax), - }, nil -} - func NewPrefix(c config.Prefix) (*Prefix, error) { addr, prefix, err := net.ParseCIDR(c.IpPrefix) if err != nil { @@ -371,20 +325,16 @@ func (s *PrefixSet) ToConfig() *config.PrefixSet { } } -func NewPrefixSetFromApiStruct(a *api.DefinedSet) (*PrefixSet, error) { - if a.Name == "" { +func NewPrefixSetFromApiStruct(name string, prefixes []*Prefix) (*PrefixSet, error) { + if name == "" { return nil, fmt.Errorf("empty prefix set name") } tree := radix.New() - for _, x := range a.Prefixes { - y, err := NewPrefixFromApiStruct(x) - if err != nil { - return nil, err - } - tree.Insert(CidrToRadixkey(y.Prefix.String()), y) + for _, x := range prefixes { + tree.Insert(CidrToRadixkey(x.Prefix.String()), x) } return &PrefixSet{ - name: a.Name, + name: name, tree: tree, }, nil } @@ -475,20 +425,9 @@ func (s *NeighborSet) ToConfig() *config.NeighborSet { } } -func NewNeighborSetFromApiStruct(a *api.DefinedSet) (*NeighborSet, error) { - if a.Name == "" { - return nil, fmt.Errorf("empty neighbor set name") - } - list := make([]net.IP, 0, len(a.List)) - for _, x := range a.List { - addr := net.ParseIP(x) - if addr == nil { - return nil, fmt.Errorf("invalid ip address format: %s", x) - } - list = append(list, addr) - } +func NewNeighborSetFromApiStruct(name string, list []net.IP) (*NeighborSet, error) { return &NeighborSet{ - name: a.Name, + name: name, list: list, }, nil } @@ -691,14 +630,6 @@ func (s *AsPathSet) ToConfig() *config.AsPathSet { } } -func NewAsPathSetFromApiStruct(a *api.DefinedSet) (*AsPathSet, error) { - c := config.AsPathSet{ - AsPathSetName: a.Name, - AsPathList: a.List, - } - return NewAsPathSet(c) -} - func NewAsPathSet(c config.AsPathSet) (*AsPathSet, error) { name := c.AsPathSetName if name == "" { @@ -906,14 +837,6 @@ func ParseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *reg return subtype, exp, err } -func NewCommunitySetFromApiStruct(a *api.DefinedSet) (*CommunitySet, error) { - c := config.CommunitySet{ - CommunitySetName: a.Name, - CommunityList: a.List, - } - return NewCommunitySet(c) -} - func NewCommunitySet(c config.CommunitySet) (*CommunitySet, error) { name := c.CommunitySetName if name == "" { @@ -967,14 +890,6 @@ func (s *ExtCommunitySet) ToConfig() *config.ExtCommunitySet { } } -func NewExtCommunitySetFromApiStruct(a *api.DefinedSet) (*ExtCommunitySet, error) { - c := config.ExtCommunitySet{ - ExtCommunitySetName: a.Name, - ExtCommunityList: a.List, - } - return NewExtCommunitySet(c) -} - func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) { name := c.ExtCommunitySetName if name == "" { @@ -1003,30 +918,15 @@ func NewExtCommunitySet(c config.ExtCommunitySet) (*ExtCommunitySet, error) { }, nil } -func NewDefinedSetFromApiStruct(a *api.DefinedSet) (DefinedSet, error) { - switch DefinedType(a.Type) { - case DEFINED_TYPE_PREFIX: - return NewPrefixSetFromApiStruct(a) - case DEFINED_TYPE_NEIGHBOR: - return NewNeighborSetFromApiStruct(a) - case DEFINED_TYPE_AS_PATH: - return NewAsPathSetFromApiStruct(a) - case DEFINED_TYPE_COMMUNITY: - return NewCommunitySetFromApiStruct(a) - case DEFINED_TYPE_EXT_COMMUNITY: - return NewExtCommunitySetFromApiStruct(a) - default: - return nil, fmt.Errorf("invalid defined type") - } -} - type Condition interface { + Name() string Type() ConditionType Evaluate(*Path, *PolicyOptions) bool Set() DefinedSet } type PrefixCondition struct { + name string set *PrefixSet option MatchOption } @@ -1080,44 +980,24 @@ func (c *PrefixCondition) Evaluate(path *Path, _ *PolicyOptions) bool { return result } -func NewPrefixConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*PrefixCondition, error) { - if a == nil { - return nil, nil - } - typ, err := toConfigMatchSetOptionRestricted(a.Type) - if err != nil { - return nil, err - } - c := config.MatchPrefixSet{ - PrefixSet: a.Name, - MatchSetOptions: typ, - } - return NewPrefixCondition(c, m) -} +func (c *PrefixCondition) Name() string { return c.name } -func NewPrefixCondition(c config.MatchPrefixSet, m map[string]DefinedSet) (*PrefixCondition, error) { +func NewPrefixCondition(c config.MatchPrefixSet) (*PrefixCondition, error) { if c.PrefixSet == "" { return nil, nil } - i, ok := m[c.PrefixSet] - if !ok { - return nil, fmt.Errorf("not found prefix set %s", c.PrefixSet) - } - 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, + name: c.PrefixSet, option: o, }, nil } type NeighborCondition struct { + name string set *NeighborSet option MatchOption } @@ -1167,44 +1047,24 @@ func (c *NeighborCondition) Evaluate(path *Path, options *PolicyOptions) bool { return result } -func NewNeighborConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*NeighborCondition, error) { - if a == nil { - return nil, nil - } - typ, err := toConfigMatchSetOptionRestricted(a.Type) - if err != nil { - return nil, err - } - c := config.MatchNeighborSet{ - NeighborSet: a.Name, - MatchSetOptions: typ, - } - return NewNeighborCondition(c, m) -} +func (c *NeighborCondition) Name() string { return c.name } -func NewNeighborCondition(c config.MatchNeighborSet, m map[string]DefinedSet) (*NeighborCondition, error) { +func NewNeighborCondition(c config.MatchNeighborSet) (*NeighborCondition, error) { if c.NeighborSet == "" { return nil, nil } - i, ok := m[c.NeighborSet] - if !ok { - return nil, fmt.Errorf("not found neighbor set %s", c.NeighborSet) - } - s, ok := i.(*NeighborSet) - if !ok { - return nil, fmt.Errorf("type assert from DefinedSet to *NeighborSet failed") - } o, err := NewMatchOption(c.MatchSetOptions) if err != nil { return nil, err } return &NeighborCondition{ - set: s, + name: c.NeighborSet, option: o, }, nil } type AsPathCondition struct { + name string set *AsPathSet option MatchOption } @@ -1258,44 +1118,24 @@ func (c *AsPathCondition) Evaluate(path *Path, _ *PolicyOptions) bool { return true } -func NewAsPathConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*AsPathCondition, error) { - if a == nil { - return nil, nil - } - typ, err := toConfigMatchSetOption(a.Type) - if err != nil { - return nil, err - } - c := config.MatchAsPathSet{ - AsPathSet: a.Name, - MatchSetOptions: typ, - } - return NewAsPathCondition(c, m) -} +func (c *AsPathCondition) Name() string { return c.name } -func NewAsPathCondition(c config.MatchAsPathSet, m map[string]DefinedSet) (*AsPathCondition, error) { +func NewAsPathCondition(c config.MatchAsPathSet) (*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, + name: c.AsPathSet, option: o, }, nil } type CommunityCondition struct { + name string set *CommunitySet option MatchOption } @@ -1336,44 +1176,24 @@ func (c *CommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool { return result } -func NewCommunityConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*CommunityCondition, error) { - if a == nil { - return nil, nil - } - typ, err := toConfigMatchSetOption(a.Type) - if err != nil { - return nil, err - } - c := config.MatchCommunitySet{ - CommunitySet: a.Name, - MatchSetOptions: typ, - } - return NewCommunityCondition(c, m) -} +func (c *CommunityCondition) Name() string { return c.name } -func NewCommunityCondition(c config.MatchCommunitySet, m map[string]DefinedSet) (*CommunityCondition, error) { +func NewCommunityCondition(c config.MatchCommunitySet) (*CommunityCondition, error) { if c.CommunitySet == "" { return nil, nil } - 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, + name: c.CommunitySet, option: o, }, nil } type ExtCommunityCondition struct { + name string set *ExtCommunitySet option MatchOption } @@ -1419,39 +1239,18 @@ func (c *ExtCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool { return result } -func NewExtCommunityConditionFromApiStruct(a *api.MatchSet, m map[string]DefinedSet) (*ExtCommunityCondition, error) { - if a == nil { - return nil, nil - } - typ, err := toConfigMatchSetOption(a.Type) - if err != nil { - return nil, err - } - c := config.MatchExtCommunitySet{ - ExtCommunitySet: a.Name, - MatchSetOptions: typ, - } - return NewExtCommunityCondition(c, m) -} +func (c *ExtCommunityCondition) Name() string { return c.name } -func NewExtCommunityCondition(c config.MatchExtCommunitySet, m map[string]DefinedSet) (*ExtCommunityCondition, error) { +func NewExtCommunityCondition(c config.MatchExtCommunitySet) (*ExtCommunityCondition, error) { if c.ExtCommunitySet == "" { return nil, nil } - i, ok := m[c.ExtCommunitySet] - if !ok { - return nil, fmt.Errorf("not found ext-community set %s", c.ExtCommunitySet) - } - s, ok := i.(*ExtCommunitySet) - if !ok { - return nil, fmt.Errorf("type assert from DefinedSet to *ExtCommunitySet failed") - } o, err := NewMatchOption(c.MatchSetOptions) if err != nil { return nil, err } return &ExtCommunityCondition{ - set: s, + name: c.ExtCommunitySet, option: o, }, nil } @@ -1487,15 +1286,7 @@ func (c *AsPathLengthCondition) Set() DefinedSet { return nil } -func NewAsPathLengthConditionFromApiStruct(a *api.AsPathLength) (*AsPathLengthCondition, error) { - if a == nil { - return nil, nil - } - return &AsPathLengthCondition{ - length: a.Length, - operator: AttributeComparison(a.Type), - }, nil -} +func (c *AsPathLengthCondition) Name() string { return "" } func NewAsPathLengthCondition(c config.AsPathLength) (*AsPathLengthCondition, error) { if c.Value == 0 && c.Operator == "" { @@ -1531,12 +1322,7 @@ func (c *RpkiValidationCondition) Set() DefinedSet { return nil } -func NewRpkiValidationConditionFromApiStruct(a int32) (*RpkiValidationCondition, error) { - if a < 1 { - return nil, nil - } - return NewRpkiValidationCondition(config.IntToRpkiValidationResultTypeMap[int(a)]) -} +func (c *RpkiValidationCondition) Name() string { return "" } func NewRpkiValidationCondition(c config.RpkiValidationResultType) (*RpkiValidationCondition, error) { if c == config.RPKI_VALIDATION_RESULT_TYPE_NONE { @@ -1567,19 +1353,6 @@ func (a *RoutingAction) Apply(path *Path, _ *PolicyOptions) *Path { return nil } -func NewRoutingActionFromApiStruct(a api.RouteAction) (*RoutingAction, error) { - if a == api.RouteAction_NONE { - return nil, nil - } - accept := false - if a == api.RouteAction_ACCEPT { - accept = true - } - return &RoutingAction{ - AcceptRoute: accept, - }, nil -} - func NewRoutingAction(c config.RouteDisposition) (*RoutingAction, error) { if c.AcceptRoute == c.RejectRoute && c.AcceptRoute { return nil, fmt.Errorf("invalid route disposition") @@ -1672,40 +1445,6 @@ func (a *CommunityAction) ToConfig() *config.SetCommunity { } } -func NewCommunityActionFromApiStruct(a *api.CommunityAction) (*CommunityAction, error) { - if a == nil { - return nil, nil - } - var list []uint32 - var removeList []*regexp.Regexp - op := config.IntToBgpSetCommunityOptionTypeMap[int(a.Type)] - if op == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { - removeList = make([]*regexp.Regexp, 0, len(a.Communities)) - } else { - list = make([]uint32, 0, len(a.Communities)) - } - for _, x := range a.Communities { - if op == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { - exp, err := ParseCommunityRegexp(x) - if err != nil { - return nil, err - } - removeList = append(removeList, exp) - } else { - comm, err := ParseCommunity(x) - if err != nil { - return nil, err - } - list = append(list, comm) - } - } - return &CommunityAction{ - action: op, - list: list, - removeList: removeList, - }, nil -} - func NewCommunityAction(c config.SetCommunity) (*CommunityAction, error) { a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] if !ok { @@ -1794,45 +1533,6 @@ func (a *ExtCommunityAction) ToConfig() *config.SetExtCommunity { } } -func NewExtCommunityActionFromApiStruct(a *api.CommunityAction) (*ExtCommunityAction, error) { - if a == nil { - return nil, nil - } - var list []bgp.ExtendedCommunityInterface - var removeList []*regexp.Regexp - subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(a.Communities)) - op := config.IntToBgpSetCommunityOptionTypeMap[int(a.Type)] - if op == config.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { - removeList = make([]*regexp.Regexp, 0, len(a.Communities)) - } else { - list = make([]bgp.ExtendedCommunityInterface, 0, len(a.Communities)) - } - for _, x := range a.Communities { - if op == 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 &ExtCommunityAction{ - action: op, - list: list, - removeList: removeList, - subtypeList: subtypeList, - }, nil -} - func NewExtCommunityAction(c config.SetExtCommunity) (*ExtCommunityAction, error) { a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] if !ok { @@ -1909,16 +1609,6 @@ func (a *MedAction) ToConfig() config.BgpSetMedType { return config.BgpSetMedType(fmt.Sprintf("%d", a.value)) } -func NewMedActionFromApiStruct(a *api.MedAction) (*MedAction, error) { - if a == nil { - return nil, nil - } - return &MedAction{ - action: MedActionType(a.Type), - value: int(a.Value), - }, nil -} - func NewMedAction(c config.BgpSetMedType) (*MedAction, error) { if string(c) == "" { return nil, nil @@ -1940,6 +1630,10 @@ func NewMedAction(c config.BgpSetMedType) (*MedAction, error) { }, nil } +func NewMedActionFromApiStruct(action MedActionType, value int) *MedAction { + return &MedAction{action: action, value: value} +} + type LocalPrefAction struct { value uint32 } @@ -1957,15 +1651,6 @@ func (a *LocalPrefAction) ToConfig() uint32 { return a.value } -func NewLocalPrefActionFromApiStruct(a *api.LocalPrefAction) (*LocalPrefAction, error) { - if a == nil || a.Value == 0 { - return nil, nil - } - return &LocalPrefAction{ - value: a.Value, - }, nil -} - func NewLocalPrefAction(value uint32) (*LocalPrefAction, error) { if value == 0 { return nil, nil @@ -2025,17 +1710,6 @@ func (a *AsPathPrependAction) ToConfig() *config.SetAsPathPrepend { } } -func NewAsPathPrependActionFromApiStruct(a *api.AsPrependAction) (*AsPathPrependAction, error) { - if a == nil { - return nil, nil - } - return &AsPathPrependAction{ - asn: a.Asn, - useLeftMost: a.UseLeftMost, - repeat: uint8(a.Repeat), - }, nil -} - // NewAsPathPrependAction creates AsPathPrependAction object. // If ASN cannot be parsed, nil will be returned. func NewAsPathPrependAction(action config.SetAsPathPrepend) (*AsPathPrependAction, error) { @@ -2087,16 +1761,6 @@ func (a *NexthopAction) ToConfig() config.BgpNextHopType { return config.BgpNextHopType(a.value.String()) } -func NewNexthopActionFromApiStruct(a *api.NexthopAction) (*NexthopAction, error) { - if a == nil { - return nil, nil - } - return &NexthopAction{ - value: net.ParseIP(a.Address), - self: a.Self, - }, nil -} - func NewNexthopAction(c config.BgpNextHopType) (*NexthopAction, error) { switch string(c) { case "": @@ -2338,94 +2002,7 @@ func (lhs *Statement) Replace(rhs *Statement) error { return lhs.mod(REPLACE, rhs) } -func NewStatementFromApiStruct(a *api.Statement, dmap DefinedSetMap) (*Statement, error) { - if a.Name == "" { - return nil, fmt.Errorf("empty statement name") - } - var ra Action - var as []Action - var cs []Condition - var err error - if a.Conditions != nil { - cfs := []func() (Condition, error){ - func() (Condition, error) { - return NewPrefixConditionFromApiStruct(a.Conditions.PrefixSet, dmap[DEFINED_TYPE_PREFIX]) - }, - func() (Condition, error) { - return NewNeighborConditionFromApiStruct(a.Conditions.NeighborSet, dmap[DEFINED_TYPE_NEIGHBOR]) - }, - func() (Condition, error) { - return NewAsPathLengthConditionFromApiStruct(a.Conditions.AsPathLength) - }, - func() (Condition, error) { - return NewRpkiValidationConditionFromApiStruct(a.Conditions.RpkiResult) - }, - func() (Condition, error) { - return NewAsPathConditionFromApiStruct(a.Conditions.AsPathSet, dmap[DEFINED_TYPE_AS_PATH]) - }, - func() (Condition, error) { - return NewCommunityConditionFromApiStruct(a.Conditions.CommunitySet, dmap[DEFINED_TYPE_COMMUNITY]) - }, - func() (Condition, error) { - return NewExtCommunityConditionFromApiStruct(a.Conditions.ExtCommunitySet, dmap[DEFINED_TYPE_EXT_COMMUNITY]) - }, - } - cs = make([]Condition, 0, len(cfs)) - for _, f := range cfs { - c, err := f() - if err != nil { - return nil, err - } - if !reflect.ValueOf(c).IsNil() { - cs = append(cs, c) - } - } - } - if a.Actions != nil { - ra, err = NewRoutingActionFromApiStruct(a.Actions.RouteAction) - if err != nil { - return nil, err - } - afs := []func() (Action, error){ - func() (Action, error) { - return NewCommunityActionFromApiStruct(a.Actions.Community) - }, - func() (Action, error) { - return NewExtCommunityActionFromApiStruct(a.Actions.ExtCommunity) - }, - func() (Action, error) { - return NewMedActionFromApiStruct(a.Actions.Med) - }, - func() (Action, error) { - return NewLocalPrefActionFromApiStruct(a.Actions.LocalPref) - }, - func() (Action, error) { - return NewAsPathPrependActionFromApiStruct(a.Actions.AsPrepend) - }, - func() (Action, error) { - return NewNexthopActionFromApiStruct(a.Actions.Nexthop) - }, - } - as = make([]Action, 0, len(afs)) - for _, f := range afs { - a, err := f() - if err != nil { - return nil, err - } - if !reflect.ValueOf(a).IsNil() { - as = append(as, a) - } - } - } - return &Statement{ - Name: a.Name, - Conditions: cs, - RouteAction: ra, - ModActions: as, - }, nil -} - -func NewStatement(c config.Statement, dmap DefinedSetMap) (*Statement, error) { +func NewStatement(c config.Statement) (*Statement, error) { if c.Name == "" { return nil, fmt.Errorf("empty statement name") } @@ -2435,10 +2012,10 @@ func NewStatement(c config.Statement, dmap DefinedSetMap) (*Statement, error) { var err error cfs := []func() (Condition, error){ func() (Condition, error) { - return NewPrefixCondition(c.Conditions.MatchPrefixSet, dmap[DEFINED_TYPE_PREFIX]) + return NewPrefixCondition(c.Conditions.MatchPrefixSet) }, func() (Condition, error) { - return NewNeighborCondition(c.Conditions.MatchNeighborSet, dmap[DEFINED_TYPE_NEIGHBOR]) + return NewNeighborCondition(c.Conditions.MatchNeighborSet) }, func() (Condition, error) { return NewAsPathLengthCondition(c.Conditions.BgpConditions.AsPathLength) @@ -2447,13 +2024,13 @@ func NewStatement(c config.Statement, dmap DefinedSetMap) (*Statement, error) { return NewRpkiValidationCondition(c.Conditions.BgpConditions.RpkiValidationResult) }, func() (Condition, error) { - return NewAsPathCondition(c.Conditions.BgpConditions.MatchAsPathSet, dmap[DEFINED_TYPE_AS_PATH]) + return NewAsPathCondition(c.Conditions.BgpConditions.MatchAsPathSet) }, func() (Condition, error) { - return NewCommunityCondition(c.Conditions.BgpConditions.MatchCommunitySet, dmap[DEFINED_TYPE_COMMUNITY]) + return NewCommunityCondition(c.Conditions.BgpConditions.MatchCommunitySet) }, func() (Condition, error) { - return NewExtCommunityCondition(c.Conditions.BgpConditions.MatchExtCommunitySet, dmap[DEFINED_TYPE_EXT_COMMUNITY]) + return NewExtCommunityCondition(c.Conditions.BgpConditions.MatchExtCommunitySet) }, } cs = make([]Condition, 0, len(cfs)) @@ -2509,14 +2086,10 @@ func NewStatement(c config.Statement, dmap DefinedSetMap) (*Statement, error) { } type Policy struct { - name string + Name string Statements []*Statement } -func (p *Policy) Name() string { - return p.name -} - // 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. @@ -2537,7 +2110,7 @@ func (p *Policy) ToConfig() *config.PolicyDefinition { ss = append(ss, *s.ToConfig()) } return &config.PolicyDefinition{ - Name: p.name, + Name: p.Name, Statements: ss, } } @@ -2583,28 +2156,7 @@ func (lhs *Policy) Replace(rhs *Policy) error { return nil } -func NewPolicyFromApiStruct(a *api.Policy, dmap DefinedSetMap) (*Policy, error) { - if a.Name == "" { - return nil, fmt.Errorf("empty policy name") - } - stmts := make([]*Statement, 0, len(a.Statements)) - for idx, x := range a.Statements { - if x.Name == "" { - x.Name = fmt.Sprintf("%s_stmt%d", a.Name, idx) - } - y, err := NewStatementFromApiStruct(x, dmap) - if err != nil { - return nil, err - } - stmts = append(stmts, y) - } - return &Policy{ - name: a.Name, - Statements: stmts, - }, nil -} - -func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { +func NewPolicy(c config.PolicyDefinition) (*Policy, error) { if c.Name == "" { return nil, fmt.Errorf("empty policy name") } @@ -2616,7 +2168,7 @@ func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { if stmt.Name == "" { stmt.Name = fmt.Sprintf("%s_stmt%d", c.Name, idx) } - s, err := NewStatement(stmt, dmap) + s, err := NewStatement(stmt) if err != nil { return nil, err } @@ -2624,7 +2176,7 @@ func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { } } return &Policy{ - name: c.Name, + Name: c.Name, Statements: st, }, nil } @@ -2780,6 +2332,54 @@ func (r *RoutingPolicy) GetAssignmentFromConfig(dir PolicyDirection, a config.Ap return ps, def, nil } +func (r *RoutingPolicy) ValidateCondition(v Condition) (err error) { + switch v.Type() { + case CONDITION_PREFIX: + m := r.DefinedSetMap[DEFINED_TYPE_PREFIX] + if i, ok := m[v.Name()]; !ok { + return fmt.Errorf("not found prefix set %s", v.Name()) + } else { + c := v.(*PrefixCondition) + c.set = i.(*PrefixSet) + } + case CONDITION_NEIGHBOR: + m := r.DefinedSetMap[DEFINED_TYPE_NEIGHBOR] + if i, ok := m[v.Name()]; !ok { + return fmt.Errorf("not found neighbor set %s", v.Name()) + } else { + c := v.(*NeighborCondition) + c.set = i.(*NeighborSet) + } + case CONDITION_AS_PATH: + m := r.DefinedSetMap[DEFINED_TYPE_AS_PATH] + if i, ok := m[v.Name()]; !ok { + return fmt.Errorf("not found as path set %s", v.Name()) + } else { + c := v.(*AsPathCondition) + c.set = i.(*AsPathSet) + } + case CONDITION_COMMUNITY: + m := r.DefinedSetMap[DEFINED_TYPE_COMMUNITY] + if i, ok := m[v.Name()]; !ok { + return fmt.Errorf("not found community set %s", v.Name()) + } else { + c := v.(*CommunityCondition) + c.set = i.(*CommunitySet) + } + case CONDITION_EXT_COMMUNITY: + m := r.DefinedSetMap[DEFINED_TYPE_EXT_COMMUNITY] + if i, ok := m[v.Name()]; !ok { + return fmt.Errorf("not found ext-community set %s", v.Name()) + } else { + c := v.(*ExtCommunityCondition) + c.set = i.(*ExtCommunitySet) + } + case CONDITION_AS_PATH_LENGTH: + case CONDITION_RPKI: + } + return nil +} + func (r *RoutingPolicy) InUse(d DefinedSet) bool { name := d.Name() for _, p := range r.PolicyMap { @@ -2875,14 +2475,14 @@ func (r *RoutingPolicy) Reload(c config.RoutingPolicy) error { pmap := make(map[string]*Policy) smap := make(map[string]*Statement) for _, x := range c.PolicyDefinitions { - y, err := NewPolicy(x, dmap) + y, err := NewPolicy(x) if err != nil { return err } - if _, ok := pmap[y.Name()]; ok { + if _, ok := pmap[y.Name]; ok { return fmt.Errorf("duplicated policy name. policy name must be unique.") } - pmap[y.Name()] = y + pmap[y.Name] = y for _, s := range y.Statements { _, ok := smap[s.Name] if ok { @@ -2891,6 +2491,21 @@ func (r *RoutingPolicy) Reload(c config.RoutingPolicy) error { smap[s.Name] = s } } + + // hacky + oldMap := r.DefinedSetMap + r.DefinedSetMap = dmap + for _, y := range pmap { + for _, s := range y.Statements { + for _, c := range s.Conditions { + if err := r.ValidateCondition(c); err != nil { + r.DefinedSetMap = oldMap + return err + } + } + } + } + r.DefinedSetMap = dmap r.PolicyMap = pmap r.StatementMap = smap @@ -2923,14 +2538,7 @@ func CanImportToVrf(v *Vrf, path *Path) bool { ExtCommunitySet: v.Name, MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY, } - c, _ := NewExtCommunityCondition(matchSet, map[string]DefinedSet{v.Name: set}) + c, _ := NewExtCommunityCondition(matchSet) + c.set = set return c.Evaluate(path, nil) } - -func PoliciesToString(ps []*api.Policy) []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 e5bc52c9..ff52e3c7 100644 --- a/table/policy_test.go +++ b/table/policy_test.go @@ -612,6 +612,14 @@ func TestAs4PathLengthConditionEvaluate(t *testing.T) { assert.Equal(t, false, c.Evaluate(path, nil)) } +func addPolicy(r *RoutingPolicy, x *Policy) { + for _, s := range x.Statements { + for _, c := range s.Conditions { + r.ValidateCondition(c) + } + } +} + func TestAs4PathLengthConditionWithOtherCondition(t *testing.T) { // setup // create path @@ -663,7 +671,8 @@ func TestAs4PathLengthConditionWithOtherCondition(t *testing.T) { //test r := NewRoutingPolicy() r.Reload(pl) - p, _ := NewPolicy(pl.PolicyDefinitions[0], r.DefinedSetMap) + p, _ := NewPolicy(pl.PolicyDefinitions[0]) + addPolicy(r, p) pType, newPath := p.Apply(path, nil) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -739,7 +748,10 @@ func TestAsPathConditionEvaluate(t *testing.T) { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p, _ := NewAsPathCondition(matchSet, m) + p, _ := NewAsPathCondition(matchSet) + if v, ok := m[name]; ok { + p.set = v.(*AsPathSet) + } return p } @@ -839,7 +851,10 @@ func TestMultipleAsPathConditionEvaluate(t *testing.T) { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p, _ := NewAsPathCondition(matchSet, m) + p, _ := NewAsPathCondition(matchSet) + if v, ok := m[name]; ok { + p.set = v.(*AsPathSet) + } return p } @@ -931,7 +946,8 @@ func TestAsPathCondition(t *testing.T) { c, _ := NewAsPathCondition(config.MatchAsPathSet{ AsPathSet: k, MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY, - }, map[string]DefinedSet{k: s}) + }) + c.set = s for _, a := range v { result := c.Evaluate(a.path, nil) if a.result != result { @@ -1082,7 +1098,10 @@ func TestAs4PathConditionEvaluate(t *testing.T) { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p, _ := NewAsPathCondition(matchSet, m) + p, _ := NewAsPathCondition(matchSet) + if v, ok := m[name]; ok { + p.set = v.(*AsPathSet) + } return p } @@ -1203,7 +1222,10 @@ func TestMultipleAs4PathConditionEvaluate(t *testing.T) { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p, _ := NewAsPathCondition(matchSet, m) + p, _ := NewAsPathCondition(matchSet) + if v, ok := m[name]; ok { + p.set = v.(*AsPathSet) + } return p } @@ -1282,7 +1304,8 @@ func TestAs4PathConditionWithOtherCondition(t *testing.T) { //test r := NewRoutingPolicy() r.Reload(pl) - p, _ := NewPolicy(pl.PolicyDefinitions[0], r.DefinedSetMap) + p, _ := NewPolicy(pl.PolicyDefinitions[0]) + addPolicy(r, p) pType, newPath := p.Apply(path, nil) assert.Equal(t, ROUTE_TYPE_REJECT, pType) assert.Equal(t, newPath, path) @@ -1364,7 +1387,10 @@ func TestAs4PathConditionEvaluateMixedWith2byteAS(t *testing.T) { matchSet := config.MatchAsPathSet{} matchSet.AsPathSet = name matchSet.MatchSetOptions = option - p, _ := NewAsPathCondition(matchSet, m) + p, _ := NewAsPathCondition(matchSet) + if v, ok := m[name]; ok { + p.set = v.(*AsPathSet) + } return p } @@ -1499,7 +1525,10 @@ func TestCommunityConditionEvaluate(t *testing.T) { matchSet := config.MatchCommunitySet{} matchSet.CommunitySet = name matchSet.MatchSetOptions = option - c, _ := NewCommunityCondition(matchSet, m) + c, _ := NewCommunityCondition(matchSet) + if v, ok := m[name]; ok { + c.set = v.(*CommunitySet) + } return c } @@ -2027,7 +2056,11 @@ func TestExtCommunityConditionEvaluate(t *testing.T) { matchSet := config.MatchExtCommunitySet{} matchSet.ExtCommunitySet = name matchSet.MatchSetOptions = option - c, _ := NewExtCommunityCondition(matchSet, m) + c, _ := NewExtCommunityCondition(matchSet) + if v, ok := m[name]; ok { + c.set = v.(*ExtCommunitySet) + } + return c } @@ -2590,7 +2623,8 @@ func TestPolicyAs4PathPrepend(t *testing.T) { //test r := NewRoutingPolicy() r.Reload(pl) - p, _ := NewPolicy(pl.PolicyDefinitions[0], r.DefinedSetMap) + p, _ := NewPolicy(pl.PolicyDefinitions[0]) + addPolicy(r, p) pType, newPath := p.Apply(path, nil) assert.Equal(ROUTE_TYPE_ACCEPT, pType) @@ -2645,7 +2679,8 @@ func TestPolicyAs4PathPrependLastAs(t *testing.T) { //test r := NewRoutingPolicy() r.Reload(pl) - p, _ := NewPolicy(pl.PolicyDefinitions[0], r.DefinedSetMap) + p, _ := NewPolicy(pl.PolicyDefinitions[0]) + addPolicy(r, p) pType, newPath := p.Apply(path, nil) assert.Equal(ROUTE_TYPE_ACCEPT, pType) |