diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-10-18 14:10:46 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-10-20 10:33:10 +0900 |
commit | 7cb50ce1cfdf959a74dad516ef65a6c6c34aaec8 (patch) | |
tree | 188236c04337a475078ec2e57932c3e47c8c6154 | |
parent | 29f9682ecbe0e5bf0a44fdcc2e9f8cec3f6ea31c (diff) |
api/cli: add api to retrieve statements and support showing them via cli
$ gobgp policy statement
$ gobgp policy statement st0
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r-- | api/gobgp.pb.go | 87 | ||||
-rw-r--r-- | api/gobgp.proto | 2 | ||||
-rw-r--r-- | gobgp/cmd/common.go | 1 | ||||
-rw-r--r-- | gobgp/cmd/policy.go | 155 | ||||
-rw-r--r-- | server/grpc_server.go | 52 | ||||
-rw-r--r-- | server/server.go | 29 | ||||
-rw-r--r-- | table/policy.go | 10 |
7 files changed, 266 insertions, 70 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 3b583fe7..d3bdc1e4 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -749,6 +749,8 @@ type GobgpApiClient interface { GetDefinedSet(ctx context.Context, in *DefinedSet, opts ...grpc.CallOption) (*DefinedSet, error) GetDefinedSets(ctx context.Context, in *DefinedSet, opts ...grpc.CallOption) (GobgpApi_GetDefinedSetsClient, error) ModDefinedSet(ctx context.Context, in *ModDefinedSetArguments, opts ...grpc.CallOption) (*Error, error) + GetStatement(ctx context.Context, in *Statement, opts ...grpc.CallOption) (*Statement, error) + GetStatements(ctx context.Context, in *Statement, opts ...grpc.CallOption) (GobgpApi_GetStatementsClient, error) } type gobgpApiClient struct { @@ -1292,6 +1294,47 @@ func (c *gobgpApiClient) ModDefinedSet(ctx context.Context, in *ModDefinedSetArg return out, nil } +func (c *gobgpApiClient) GetStatement(ctx context.Context, in *Statement, opts ...grpc.CallOption) (*Statement, error) { + out := new(Statement) + err := grpc.Invoke(ctx, "/gobgpapi.GobgpApi/GetStatement", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *gobgpApiClient) GetStatements(ctx context.Context, in *Statement, opts ...grpc.CallOption) (GobgpApi_GetStatementsClient, error) { + stream, err := grpc.NewClientStream(ctx, &_GobgpApi_serviceDesc.Streams[13], c.cc, "/gobgpapi.GobgpApi/GetStatements", opts...) + if err != nil { + return nil, err + } + x := &gobgpApiGetStatementsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type GobgpApi_GetStatementsClient interface { + Recv() (*Statement, error) + grpc.ClientStream +} + +type gobgpApiGetStatementsClient struct { + grpc.ClientStream +} + +func (x *gobgpApiGetStatementsClient) Recv() (*Statement, error) { + m := new(Statement) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // Server API for GobgpApi service type GobgpApiServer interface { @@ -1321,6 +1364,8 @@ type GobgpApiServer interface { GetDefinedSet(context.Context, *DefinedSet) (*DefinedSet, error) GetDefinedSets(*DefinedSet, GobgpApi_GetDefinedSetsServer) error ModDefinedSet(context.Context, *ModDefinedSetArguments) (*Error, error) + GetStatement(context.Context, *Statement) (*Statement, error) + GetStatements(*Statement, GobgpApi_GetStatementsServer) error } func RegisterGobgpApiServer(s *grpc.Server, srv GobgpApiServer) { @@ -1771,6 +1816,39 @@ func _GobgpApi_ModDefinedSet_Handler(srv interface{}, ctx context.Context, dec f return out, nil } +func _GobgpApi_GetStatement_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) { + in := new(Statement) + if err := dec(in); err != nil { + return nil, err + } + out, err := srv.(GobgpApiServer).GetStatement(ctx, in) + if err != nil { + return nil, err + } + return out, nil +} + +func _GobgpApi_GetStatements_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(Statement) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(GobgpApiServer).GetStatements(m, &gobgpApiGetStatementsServer{stream}) +} + +type GobgpApi_GetStatementsServer interface { + Send(*Statement) error + grpc.ServerStream +} + +type gobgpApiGetStatementsServer struct { + grpc.ServerStream +} + +func (x *gobgpApiGetStatementsServer) Send(m *Statement) error { + return x.ServerStream.SendMsg(m) +} + var _GobgpApi_serviceDesc = grpc.ServiceDesc{ ServiceName: "gobgpapi.GobgpApi", HandlerType: (*GobgpApiServer)(nil), @@ -1827,6 +1905,10 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{ MethodName: "ModDefinedSet", Handler: _GobgpApi_ModDefinedSet_Handler, }, + { + MethodName: "GetStatement", + Handler: _GobgpApi_GetStatement_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -1896,5 +1978,10 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{ Handler: _GobgpApi_GetDefinedSets_Handler, ServerStreams: true, }, + { + StreamName: "GetStatements", + Handler: _GobgpApi_GetStatements_Handler, + ServerStreams: true, + }, }, } diff --git a/api/gobgp.proto b/api/gobgp.proto index f6b59356..ad070e60 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -46,6 +46,8 @@ service GobgpApi { rpc GetDefinedSet(DefinedSet) returns (DefinedSet) {} rpc GetDefinedSets(DefinedSet) returns (stream DefinedSet) {} rpc ModDefinedSet(ModDefinedSetArguments) returns (Error) {} + rpc GetStatement(Statement) returns (Statement) {} + rpc GetStatements(Statement) returns (stream Statement) {} } message Error { diff --git a/gobgp/cmd/common.go b/gobgp/cmd/common.go index 0b6ca6ff..54bf07ea 100644 --- a/gobgp/cmd/common.go +++ b/gobgp/cmd/common.go @@ -66,6 +66,7 @@ const ( CMD_VRF = "vrf" CMD_ACCEPTED = "accepted" CMD_REJECTED = "rejected" + CMD_STATEMENT = "statement" ) var subOpts struct { diff --git a/gobgp/cmd/policy.go b/gobgp/cmd/policy.go index 2b4ecbc6..441c1ff9 100644 --- a/gobgp/cmd/policy.go +++ b/gobgp/cmd/policy.go @@ -399,75 +399,78 @@ func mod(settype string, modtype string, args []string) error { return err } -func showPolicyStatement(indent int, pd *api.PolicyDefinition) { +func printStatement(indent int, s *api.Statement) { sIndent := func(indent int) string { return strings.Repeat(" ", indent) } - for _, st := range pd.Statements { - fmt.Printf("%sStatementName %s:\n", sIndent(indent), st.Name) - fmt.Printf("%sConditions:\n", sIndent(indent+2)) + fmt.Printf("%sStatementName %s:\n", sIndent(indent), s.Name) + fmt.Printf("%sConditions:\n", sIndent(indent+2)) - ps := st.Conditions.PrefixSet - if ps != nil { - fmt.Printf("%sPrefixSet: %s %s\n", sIndent(indent+4), table.MatchOption(ps.Option), ps.Name) - } + ps := s.Conditions.PrefixSet + if ps != nil { + fmt.Printf("%sPrefixSet: %s %s\n", sIndent(indent+4), table.MatchOption(ps.Option), ps.Name) + } - ns := st.Conditions.NeighborSet - if ns != nil { - fmt.Printf("%sNeighborSet: %s %s\n", sIndent(indent+4), table.MatchOption(ns.Option), ns.Name) - } + ns := s.Conditions.NeighborSet + if ns != nil { + fmt.Printf("%sNeighborSet: %s %s\n", sIndent(indent+4), table.MatchOption(ns.Option), ns.Name) + } - aps := st.Conditions.AsPathSet - if aps != nil { - fmt.Printf("%sAsPathSet: %s %s\n", sIndent(indent+4), table.MatchOption(aps.Option), aps.Name) - } + aps := s.Conditions.AsPathSet + if aps != nil { + fmt.Printf("%sAsPathSet: %s %s\n", sIndent(indent+4), table.MatchOption(aps.Option), aps.Name) + } - cs := st.Conditions.CommunitySet - if cs != nil { - fmt.Printf("%sCommunitySet: %s %s\n", sIndent(indent+4), table.MatchOption(cs.Option), cs.Name) - } + cs := s.Conditions.CommunitySet + if cs != nil { + fmt.Printf("%sCommunitySet: %s %s\n", sIndent(indent+4), table.MatchOption(cs.Option), cs.Name) + } - ecs := st.Conditions.ExtCommunitySet - if ecs != nil { - fmt.Printf("%sExtCommunitySet: %s %s\n", sIndent(indent+4), table.MatchOption(ecs.Option), ecs.Name) - } + ecs := s.Conditions.ExtCommunitySet + if ecs != nil { + fmt.Printf("%sExtCommunitySet: %s %s\n", sIndent(indent+4), table.MatchOption(ecs.Option), ecs.Name) + } - asPathLentgh := st.Conditions.AsPathLength - if asPathLentgh != nil { - fmt.Printf("%sAsPathLength: %s %s\n", sIndent(indent+4), asPathLentgh.Type, asPathLentgh.Length) - } - fmt.Printf("%sActions:\n", sIndent(indent+2)) + asPathLentgh := s.Conditions.AsPathLength + if asPathLentgh != nil { + fmt.Printf("%sAsPathLength: %s %s\n", sIndent(indent+4), asPathLentgh.Type, asPathLentgh.Length) + } + fmt.Printf("%sActions:\n", sIndent(indent+2)) - formatComAction := func(c *api.CommunityAction) string { - option := table.CommunityOptionNameMap[config.BgpSetCommunityOptionType(c.Option)] - if len(c.Communities) != 0 { - communities := strings.Join(c.Communities, ",") - option = fmt.Sprintf("%s[%s]", option, communities) - } - return option - } - if st.Actions.Community != nil { - fmt.Printf("%sCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.Community)) + formatComAction := func(c *api.CommunityAction) string { + option := table.CommunityOptionNameMap[config.BgpSetCommunityOptionType(c.Option)] + if len(c.Communities) != 0 { + communities := strings.Join(c.Communities, ",") + option = fmt.Sprintf("%s[%s]", option, communities) } - if st.Actions.ExtCommunity != nil { - fmt.Printf("%sExtCommunity: %s\n", sIndent(indent+4), formatComAction(st.Actions.ExtCommunity)) - } - if st.Actions.Med != nil { - fmt.Printf("%sMed: %s\n", sIndent(indent+4), st.Actions.Med.Value) + return option + } + if s.Actions.Community != nil { + fmt.Printf("%sCommunity: %s\n", sIndent(indent+4), formatComAction(s.Actions.Community)) + } + if s.Actions.ExtCommunity != nil { + fmt.Printf("%sExtCommunity: %s\n", sIndent(indent+4), formatComAction(s.Actions.ExtCommunity)) + } + if s.Actions.Med != nil { + fmt.Printf("%sMed: %s\n", sIndent(indent+4), s.Actions.Med.Value) + } + if s.Actions.AsPrepend != nil { + var asn string + if s.Actions.AsPrepend.UseLeftMost { + asn = "left-most" + } else { + asn = fmt.Sprintf("%d", s.Actions.AsPrepend.Asn) } - if st.Actions.AsPrepend != nil { - var asn string - if st.Actions.AsPrepend.UseLeftMost { - asn = "left-most" - } else { - asn = fmt.Sprintf("%d", st.Actions.AsPrepend.Asn) - } - fmt.Printf("%sAsPrepend: %s %d\n", sIndent(indent+4), asn, st.Actions.AsPrepend.Repeat) - } - fmt.Printf("%s%s\n", sIndent(indent+4), st.Actions.RouteAction) + fmt.Printf("%sAsPrepend: %s %d\n", sIndent(indent+4), asn, s.Actions.AsPrepend.Repeat) } + fmt.Printf("%s%s\n", sIndent(indent+4), s.Actions.RouteAction) +} +func showPolicyStatement(indent int, pd *api.PolicyDefinition) { + for _, s := range pd.Statements { + printStatement(indent, s) + } } func showPolicyRoutePolicies() error { @@ -872,6 +875,39 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { return nil } +func showStatement(args []string) error { + m := []*api.Statement{} + if len(args) > 0 { + arg := &api.Statement{ + Name: args[0], + } + p, e := client.GetStatement(context.Background(), arg) + if e != nil { + return e + } + m = append(m, p) + } else { + arg := &api.Statement{} + stream, e := client.GetStatements(context.Background(), arg) + if e != nil { + return e + } + for { + p, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + m = append(m, p) + } + } + for _, s := range m { + printStatement(0, s) + } + return nil +} + func NewPolicyCmd() *cobra.Command { policyCmd := &cobra.Command{ Use: CMD_POLICY, @@ -910,5 +946,16 @@ func NewPolicyCmd() *cobra.Command { } policyCmd.AddCommand(cmd) } + + cmd := &cobra.Command{ + Use: CMD_STATEMENT, + Run: func(cmd *cobra.Command, args []string) { + if err := showStatement(args); err != nil { + fmt.Println(err) + } + }, + } + policyCmd.AddCommand(cmd) + return policyCmd } diff --git a/server/grpc_server.go b/server/grpc_server.go index 1ed56144..6753417b 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -61,6 +61,7 @@ const ( REQ_GLOBAL_POLICY REQ_DEFINED_SET REQ_MOD_DEFINED_SET + REQ_STATEMENT ) const GRPC_PORT = 8080 @@ -419,11 +420,20 @@ func (s *Server) GetVrfs(arg *api.Arguments, stream api.GobgpApi_GetVrfsServer) }) } -func (s *Server) ModVrf(ctx context.Context, arg *api.ModVrfArguments) (*api.Error, error) { - none := &api.Error{} - req := NewGrpcRequest(REQ_VRF_MOD, "", bgp.RouteFamily(0), arg) +func (s *Server) get(typ int, d interface{}) (interface{}, error) { + req := NewGrpcRequest(typ, "", bgp.RouteFamily(0), d) s.bgpServerCh <- req + res := <-req.ResponseCh + if err := res.Err(); err != nil { + return nil, err + } + return res.Data, nil +} +func (s *Server) mod(typ int, d interface{}) (*api.Error, error) { + none := &api.Error{} + req := NewGrpcRequest(typ, "", bgp.RouteFamily(0), d) + s.bgpServerCh <- req res := <-req.ResponseCh if err := res.Err(); err != nil { return none, err @@ -431,34 +441,44 @@ func (s *Server) ModVrf(ctx context.Context, arg *api.ModVrfArguments) (*api.Err return none, nil } +func (s *Server) ModVrf(ctx context.Context, arg *api.ModVrfArguments) (*api.Error, error) { + return s.mod(REQ_VRF_MOD, arg) +} + func (s *Server) GetDefinedSet(ctx context.Context, arg *api.DefinedSet) (*api.DefinedSet, error) { - req := NewGrpcRequest(REQ_DEFINED_SET, "", bgp.RouteFamily(0), arg) - s.bgpServerCh <- req - res := <-req.ResponseCh - if err := res.Err(); err != nil { + d, err := s.get(REQ_DEFINED_SET, arg) + if err != nil { return nil, err } - return res.Data.(*api.DefinedSet), nil + return d.(*api.DefinedSet), nil } func (s *Server) GetDefinedSets(arg *api.DefinedSet, stream api.GobgpApi_GetDefinedSetsServer) error { req := NewGrpcRequest(REQ_DEFINED_SET, "", bgp.RouteFamily(0), arg) s.bgpServerCh <- req - return handleMultipleResponses(req, func(res *GrpcResponse) error { return stream.Send(res.Data.(*api.DefinedSet)) }) } func (s *Server) ModDefinedSet(ctx context.Context, arg *api.ModDefinedSetArguments) (*api.Error, error) { - none := &api.Error{} - req := NewGrpcRequest(REQ_MOD_DEFINED_SET, "", bgp.RouteFamily(0), arg) - s.bgpServerCh <- req - res := <-req.ResponseCh - if err := res.Err(); err != nil { - return none, err + return s.mod(REQ_MOD_DEFINED_SET, arg) +} + +func (s *Server) GetStatement(ctx context.Context, arg *api.Statement) (*api.Statement, error) { + d, err := s.get(REQ_STATEMENT, arg) + if err != nil { + return nil, err } - return none, nil + return d.(*api.Statement), nil +} + +func (s *Server) GetStatements(arg *api.Statement, stream api.GobgpApi_GetStatementsServer) error { + req := NewGrpcRequest(REQ_STATEMENT, "", bgp.RouteFamily(0), arg) + s.bgpServerCh <- req + return handleMultipleResponses(req, func(res *GrpcResponse) error { + return stream.Send(res.Data.(*api.Statement)) + }) } type GrpcRequest struct { diff --git a/server/server.go b/server/server.go index 18c2693e..e25d314f 100644 --- a/server/server.go +++ b/server/server.go @@ -1643,6 +1643,13 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { ResponseErr: err, } close(grpcReq.ResponseCh) + case REQ_STATEMENT: + if err := server.handleGrpcGetStatement(grpcReq); err != nil { + grpcReq.ResponseCh <- &GrpcResponse{ + ResponseErr: err, + } + } + close(grpcReq.ResponseCh) case REQ_POLICY_ROUTEPOLICY, REQ_POLICY_ROUTEPOLICIES: info := server.policy.PolicyMap typ := grpcReq.RequestType @@ -1754,6 +1761,28 @@ func (server *BgpServer) handleGrpcModDefinedSet(grpcReq *GrpcRequest) error { return err } +func (server *BgpServer) handleGrpcGetStatement(grpcReq *GrpcRequest) error { + arg := grpcReq.Data.(*api.Statement) + name := arg.Name + found := false + for _, s := range server.policy.StatementMap { + if name != "" && name != s.Name { + continue + } + grpcReq.ResponseCh <- &GrpcResponse{ + Data: s.ToApiStruct(), + } + found = true + if name != "" { + break + } + } + if !found { + return fmt.Errorf("not found %s", name) + } + return nil +} + func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) { now := uint32(time.Now().Unix()) view := "" diff --git a/table/policy.go b/table/policy.go index 97277f6f..8375faab 100644 --- a/table/policy.go +++ b/table/policy.go @@ -2053,6 +2053,7 @@ func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { type RoutingPolicy struct { DefinedSetMap DefinedSetMap PolicyMap map[string]*Policy + StatementMap map[string]*Statement } func (r *RoutingPolicy) InUse(d DefinedSet) bool { @@ -2122,16 +2123,25 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { dmap[DEFINED_TYPE_EXT_COMMUNITY][y.Name()] = y } pmap := make(map[string]*Policy) + smap := make(map[string]*Statement) for _, x := range c.PolicyDefinitions.PolicyDefinitionList { y, err := NewPolicy(x, dmap) if err != nil { return nil, err } pmap[y.Name()] = y + for _, s := range y.Statements { + _, ok := smap[s.Name] + if ok { + return nil, fmt.Errorf("duplicated statement name. statement name must be unique.") + } + smap[s.Name] = s + } } return &RoutingPolicy{ DefinedSetMap: dmap, PolicyMap: pmap, + StatementMap: smap, }, nil } |