diff options
-rw-r--r-- | api/gobgp.pb.go | 81 | ||||
-rw-r--r-- | api/gobgp.proto | 12 | ||||
-rw-r--r-- | gobgp/cmd/global.go | 49 | ||||
-rw-r--r-- | gobgpd/main.go | 10 | ||||
-rw-r--r-- | server/grpc_server.go | 14 | ||||
-rw-r--r-- | server/server.go | 70 |
6 files changed, 226 insertions, 10 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index d856e19d..e369357c 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -19,6 +19,7 @@ It has these top-level messages: ModStatementArguments ModPolicyArguments ModPolicyAssignmentArguments + ModGlobalConfigArguments Path Destination Peer @@ -68,6 +69,7 @@ It has these top-level messages: RPKI ROA Vrf + Global */ package gobgpapi @@ -478,6 +480,22 @@ func (m *ModPolicyAssignmentArguments) GetAssignment() *PolicyAssignment { return nil } +type ModGlobalConfigArguments struct { + Operation Operation `protobuf:"varint,1,opt,name=operation,enum=gobgpapi.Operation" json:"operation,omitempty"` + Global *Global `protobuf:"bytes,2,opt,name=global" json:"global,omitempty"` +} + +func (m *ModGlobalConfigArguments) Reset() { *m = ModGlobalConfigArguments{} } +func (m *ModGlobalConfigArguments) String() string { return proto.CompactTextString(m) } +func (*ModGlobalConfigArguments) ProtoMessage() {} + +func (m *ModGlobalConfigArguments) GetGlobal() *Global { + if m != nil { + return m.Global + } + return nil +} + type Path struct { Nlri []byte `protobuf:"bytes,1,opt,name=nlri,proto3" json:"nlri,omitempty"` Pattrs [][]byte `protobuf:"bytes,2,rep,name=pattrs,proto3" json:"pattrs,omitempty"` @@ -1454,6 +1472,15 @@ func (m *Vrf) Reset() { *m = Vrf{} } func (m *Vrf) String() string { return proto.CompactTextString(m) } func (*Vrf) ProtoMessage() {} +type Global struct { + As uint32 `protobuf:"varint,1,opt,name=as" json:"as,omitempty"` + RouterId string `protobuf:"bytes,2,opt,name=router_id" json:"router_id,omitempty"` +} + +func (m *Global) Reset() { *m = Global{} } +func (m *Global) String() string { return proto.CompactTextString(m) } +func (*Global) ProtoMessage() {} + func init() { proto.RegisterEnum("gobgpapi.Resource", Resource_name, Resource_value) proto.RegisterEnum("gobgpapi.Operation", Operation_name, Operation_value) @@ -1474,6 +1501,8 @@ var _ grpc.ClientConn // Client API for GobgpApi service type GobgpApiClient interface { + GetGlobalConfig(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (*Global, error) + ModGlobalConfig(ctx context.Context, in *ModGlobalConfigArguments, opts ...grpc.CallOption) (*Error, error) GetNeighbors(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (GobgpApi_GetNeighborsClient, error) GetNeighbor(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (*Peer, error) ModNeighbor(ctx context.Context, in *ModNeighborArguments, opts ...grpc.CallOption) (*Error, error) @@ -1514,6 +1543,24 @@ func NewGobgpApiClient(cc *grpc.ClientConn) GobgpApiClient { return &gobgpApiClient{cc} } +func (c *gobgpApiClient) GetGlobalConfig(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (*Global, error) { + out := new(Global) + err := grpc.Invoke(ctx, "/gobgpapi.GobgpApi/GetGlobalConfig", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *gobgpApiClient) ModGlobalConfig(ctx context.Context, in *ModGlobalConfigArguments, opts ...grpc.CallOption) (*Error, error) { + out := new(Error) + err := grpc.Invoke(ctx, "/gobgpapi.GobgpApi/ModGlobalConfig", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *gobgpApiClient) GetNeighbors(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (GobgpApi_GetNeighborsClient, error) { stream, err := grpc.NewClientStream(ctx, &_GobgpApi_serviceDesc.Streams[0], c.cc, "/gobgpapi.GobgpApi/GetNeighbors", opts...) if err != nil { @@ -2065,6 +2112,8 @@ func (c *gobgpApiClient) ModPolicyAssignment(ctx context.Context, in *ModPolicyA // Server API for GobgpApi service type GobgpApiServer interface { + GetGlobalConfig(context.Context, *Arguments) (*Global, error) + ModGlobalConfig(context.Context, *ModGlobalConfigArguments) (*Error, error) GetNeighbors(*Arguments, GobgpApi_GetNeighborsServer) error GetNeighbor(context.Context, *Arguments) (*Peer, error) ModNeighbor(context.Context, *ModNeighborArguments) (*Error, error) @@ -2101,6 +2150,30 @@ func RegisterGobgpApiServer(s *grpc.Server, srv GobgpApiServer) { s.RegisterService(&_GobgpApi_serviceDesc, srv) } +func _GobgpApi_GetGlobalConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) { + in := new(Arguments) + if err := dec(in); err != nil { + return nil, err + } + out, err := srv.(GobgpApiServer).GetGlobalConfig(ctx, in) + if err != nil { + return nil, err + } + return out, nil +} + +func _GobgpApi_ModGlobalConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) { + in := new(ModGlobalConfigArguments) + if err := dec(in); err != nil { + return nil, err + } + out, err := srv.(GobgpApiServer).ModGlobalConfig(ctx, in) + if err != nil { + return nil, err + } + return out, nil +} + func _GobgpApi_GetNeighbors_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(Arguments) if err := stream.RecvMsg(m); err != nil { @@ -2579,6 +2652,14 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{ HandlerType: (*GobgpApiServer)(nil), Methods: []grpc.MethodDesc{ { + MethodName: "GetGlobalConfig", + Handler: _GobgpApi_GetGlobalConfig_Handler, + }, + { + MethodName: "ModGlobalConfig", + Handler: _GobgpApi_ModGlobalConfig_Handler, + }, + { MethodName: "GetNeighbor", Handler: _GobgpApi_GetNeighbor_Handler, }, diff --git a/api/gobgp.proto b/api/gobgp.proto index 98085a10..95ebeb8b 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -20,6 +20,8 @@ package gobgpapi; // Interface exported by the server. service GobgpApi { + rpc GetGlobalConfig(Arguments) returns (Global) {} + rpc ModGlobalConfig(ModGlobalConfigArguments) returns (Error) {} rpc GetNeighbors(Arguments) returns (stream Peer) {} rpc GetNeighbor(Arguments) returns (Peer) {} rpc ModNeighbor(ModNeighborArguments) returns(Error) {} @@ -117,6 +119,11 @@ message ModPolicyAssignmentArguments { PolicyAssignment assignment = 2; } +message ModGlobalConfigArguments { + Operation operation = 1; + Global global = 2; +} + enum Resource { GLOBAL = 0; LOCAL = 1; @@ -528,3 +535,8 @@ message Vrf { repeated bytes import_rt = 3; repeated bytes export_rt = 4; } + +message Global { + uint32 as = 1; + string router_id = 2; +} diff --git a/gobgp/cmd/global.go b/gobgp/cmd/global.go index e9333d81..3152d01d 100644 --- a/gobgp/cmd/global.go +++ b/gobgp/cmd/global.go @@ -627,15 +627,62 @@ usage: %s rib %s match <MATCH_EXPR> then <THEN_EXPR> -a %%s return nil } +func showGlobalConfig(args []string) error { + g, err := client.GetGlobalConfig(context.Background(), &api.Arguments{}) + if err != nil { + return err + } + fmt.Println("AS: ", g.As) + fmt.Println("Router-ID:", g.RouterId) + return nil +} + +func modGlobalConfig(args []string) error { + if len(args) != 4 || args[0] != "as" || args[2] != "router-id" { + return fmt.Errorf("usage: gobgp global as <asn> router-id <route-id>") + } + asn, err := strconv.Atoi(args[1]) + if err != nil { + return err + } + id := net.ParseIP(args[3]) + if id.To4() == nil { + return fmt.Errorf("invalid router-id format") + } + _, err = client.ModGlobalConfig(context.Background(), &api.ModGlobalConfigArguments{ + Operation: api.Operation_ADD, + Global: &api.Global{ + As: uint32(asn), + RouterId: args[3], + }, + }) + return err +} + func NewGlobalCmd() *cobra.Command { globalCmd := &cobra.Command{ Use: CMD_GLOBAL, + Run: func(cmd *cobra.Command, args []string) { + var err error + if len(args) != 0 { + err = modGlobalConfig(args) + } else { + err = showGlobalConfig(args) + } + if err != nil { + fmt.Println(err) + os.Exit(1) + } + }, } ribCmd := &cobra.Command{ Use: CMD_RIB, Run: func(cmd *cobra.Command, args []string) { - showGlobalRib(args) + if err := showGlobalRib(args); err != nil { + fmt.Println(err) + os.Exit(1) + } }, } diff --git a/gobgpd/main.go b/gobgpd/main.go index 4f44e328..6024b102 100644 --- a/gobgpd/main.go +++ b/gobgpd/main.go @@ -148,14 +148,12 @@ func main() { log.Info("gobgpd started") - if opts.ConfigFile == "" { - opts.ConfigFile = "gobgpd.conf" - } - configCh := make(chan config.BgpConfigSet) reloadCh := make(chan bool) - go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh) - reloadCh <- true + if opts.ConfigFile != "" { + go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh) + reloadCh <- true + } bgpServer := server.NewBgpServer(bgp.BGP_PORT) go bgpServer.Serve() diff --git a/server/grpc_server.go b/server/grpc_server.go index 348d11c7..c475f232 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -28,6 +28,8 @@ import ( const ( _ = iota + REQ_GLOBAL_CONFIG + REQ_MOD_GLOBAL_CONFIG REQ_NEIGHBOR REQ_NEIGHBORS REQ_ADJ_RIB_IN @@ -385,6 +387,18 @@ func (s *Server) ModPolicyAssignment(ctx context.Context, arg *api.ModPolicyAssi return s.mod(REQ_MOD_POLICY_ASSIGNMENT, arg) } +func (s *Server) GetGlobalConfig(ctx context.Context, arg *api.Arguments) (*api.Global, error) { + d, err := s.get(REQ_GLOBAL_CONFIG, arg) + if err != nil { + return nil, err + } + return d.(*api.Global), nil +} + +func (s *Server) ModGlobalConfig(ctx context.Context, arg *api.ModGlobalConfigArguments) (*api.Error, error) { + return s.mod(REQ_MOD_GLOBAL_CONFIG, arg) +} + type GrpcRequest struct { RequestType int Name string diff --git a/server/server.go b/server/server.go index 49b584ca..67499076 100644 --- a/server/server.go +++ b/server/server.go @@ -18,6 +18,7 @@ package server import ( "bytes" "fmt" + "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" "github.com/armon/go-radix" api "github.com/osrg/gobgp/api" @@ -142,8 +143,19 @@ func listenAndAccept(proto string, port int, ch chan *net.TCPConn) (*net.TCPList } func (server *BgpServer) Serve() { - g := <-server.globalTypeCh - server.bgpConfig.Global = g + var g config.Global + for { + select { + case grpcReq := <-server.GrpcReqCh: + server.handleGrpc(grpcReq) + case g = <-server.globalTypeCh: + server.bgpConfig.Global = g + server.globalTypeCh = nil + } + if server.globalTypeCh == nil { + break + } + } server.roaClient, _ = newROAClient(g.GlobalConfig.As, config.RpkiServers{}) @@ -830,7 +842,9 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *fsmMsg, incoming chan * } func (server *BgpServer) SetGlobalType(g config.Global) { - server.globalTypeCh <- g + if server.globalTypeCh != nil { + server.globalTypeCh <- g + } } func (server *BgpServer) SetRpkiConfig(c config.RpkiServers) { @@ -1254,6 +1268,33 @@ END: return msgs } +func (server *BgpServer) handleModGlobalConfig(grpcReq *GrpcRequest) error { + arg := grpcReq.Data.(*api.ModGlobalConfigArguments) + if arg.Operation != api.Operation_ADD { + return fmt.Errorf("invalid operation %s", arg.Operation) + } + if server.globalTypeCh == nil { + return fmt.Errorf("gobgp is already started") + } + g := arg.Global + c := config.Bgp{ + Global: config.Global{ + GlobalConfig: config.GlobalConfig{ + As: g.As, + RouterId: net.ParseIP(g.RouterId), + }, + }, + } + err := config.SetDefaultConfigValues(toml.MetaData{}, &c) + if err != nil { + return err + } + go func() { + server.globalTypeCh <- c.Global + }() + return nil +} + func sendMultipleResponses(grpcReq *GrpcRequest, results []*GrpcResponse) { defer close(grpcReq.ResponseCh) for _, r := range results { @@ -1307,7 +1348,30 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { return results } + if server.globalTypeCh != nil && grpcReq.RequestType != REQ_MOD_GLOBAL_CONFIG { + grpcReq.ResponseCh <- &GrpcResponse{ + ResponseErr: fmt.Errorf("bgpd main loop is not started yet"), + } + close(grpcReq.ResponseCh) + return nil + } + switch grpcReq.RequestType { + case REQ_GLOBAL_CONFIG: + result := &GrpcResponse{ + Data: &api.Global{ + As: server.bgpConfig.Global.GlobalConfig.As, + RouterId: server.bgpConfig.Global.GlobalConfig.RouterId.String(), + }, + } + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + case REQ_MOD_GLOBAL_CONFIG: + err := server.handleModGlobalConfig(grpcReq) + grpcReq.ResponseCh <- &GrpcResponse{ + ResponseErr: err, + } + close(grpcReq.ResponseCh) case REQ_GLOBAL_RIB: var results []*GrpcResponse if t, ok := server.globalRib.Tables[grpcReq.RouteFamily]; ok { |