diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-07-20 06:50:15 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-07-20 06:50:15 +0900 |
commit | 4635014cbb1f403d4582698f1b0a23f5a879d5d0 (patch) | |
tree | 39a4a770865d576aca7278f2a8b33dac1eefa657 /server | |
parent | c7c8f5612bb726ca8fe85389c688bb5d412e8fdb (diff) |
remove gRPC dependency from table/
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'server')
-rw-r--r-- | server/grpc_server.go | 505 | ||||
-rw-r--r-- | server/server.go | 1064 | ||||
-rw-r--r-- | server/server_test.go | 50 |
3 files changed, 986 insertions, 633 deletions
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) |