diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-11-12 14:47:59 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-11-12 15:01:12 +0900 |
commit | 95e7cc73083dfbc161b4ac6b0271c006d822d38d (patch) | |
tree | f76aeb30f19ee66aca066f366f105c0d0a5bf20c /server | |
parent | 180d68f88f457096ec92bcb6eabd915a64bb8858 (diff) |
mrt: support reset/rotate commands
$ gobgp mrt update reset
create a new file or reopen the existing file and continue to write
update messages to it.
$ gobgp mrt update <filename>
rename the current logging file to <filename> and truncate the logging
file and continue to write update messages to it.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'server')
-rw-r--r-- | server/grpc_server.go | 5 | ||||
-rw-r--r-- | server/server.go | 42 | ||||
-rw-r--r-- | server/watcher.go | 57 |
3 files changed, 100 insertions, 4 deletions
diff --git a/server/grpc_server.go b/server/grpc_server.go index c475f232..5ec5947b 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -48,6 +48,7 @@ const ( REQ_MONITOR_NEIGHBOR_PEER_STATE REQ_MRT_GLOBAL_RIB REQ_MRT_LOCAL_RIB + REQ_MOD_MRT REQ_RPKI REQ_ROA REQ_VRF @@ -259,6 +260,10 @@ func (s *Server) GetMrt(arg *api.MrtArguments, stream api.GobgpApi_GetMrtServer) }) } +func (s *Server) ModMrt(ctx context.Context, arg *api.ModMrtArguments) (*api.Error, error) { + return s.mod(REQ_MOD_MRT, arg) +} + func (s *Server) GetRPKI(arg *api.Arguments, stream api.GobgpApi_GetRPKIServer) error { req := NewGrpcRequest(REQ_RPKI, "", bgp.RouteFamily(arg.Rf), nil) s.bgpServerCh <- req diff --git a/server/server.go b/server/server.go index 8a5cabdf..46b9b44d 100644 --- a/server/server.go +++ b/server/server.go @@ -1691,6 +1691,8 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { server.broadcastReqs = append(server.broadcastReqs, grpcReq) case REQ_MRT_GLOBAL_RIB, REQ_MRT_LOCAL_RIB: server.handleMrt(grpcReq) + case REQ_MOD_MRT: + server.handleModMrt(grpcReq) case REQ_ROA, REQ_RPKI: server.roaClient.handleGRPC(grpcReq) case REQ_VRF, REQ_VRFS, REQ_VRF_MOD: @@ -2197,6 +2199,46 @@ func (server *BgpServer) handleGrpcModPolicyAssignment(grpcReq *GrpcRequest) err return err } +func (server *BgpServer) handleModMrt(grpcReq *GrpcRequest) { + done := func(e error) { + result := &GrpcResponse{ + ResponseErr: e, + } + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + } + arg := grpcReq.Data.(*api.ModMrtArguments) + w, y := server.watchers[WATCHER_MRT] + if arg.Operation == api.Operation_ADD { + if y { + done(fmt.Errorf("already enabled")) + return + } + } else { + if !y { + done(fmt.Errorf("not enabled yet")) + return + } + } + switch arg.Operation { + case api.Operation_ADD: + w, err := newMrtWatcher(arg.Filename) + if err == nil { + server.watchers[WATCHER_MRT] = w + } + done(err) + case api.Operation_DEL: + delete(server.watchers, WATCHER_MRT) + w.stop() + done(nil) + case api.Operation_REPLACE: + go func() { + err := w.restart(arg.Filename) + done(err) + }() + } +} + func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) { now := uint32(time.Now().Unix()) view := "" diff --git a/server/watcher.go b/server/watcher.go index a4c3a192..bed70538 100644 --- a/server/watcher.go +++ b/server/watcher.go @@ -16,6 +16,7 @@ package server import ( + "fmt" log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/packet" "gopkg.in/tomb.v2" @@ -66,14 +67,21 @@ type watcherEventUpdateMsg struct { type watcher interface { notify(watcherEventType) chan watcherEvent + restart(string) error stop() } +type mrtWatcherOp struct { + filename string //used for rotate + result chan error +} + type mrtWatcher struct { t tomb.Tomb filename string file *os.File ch chan watcherEvent + opCh chan *mrtWatcherOp } func (w *mrtWatcher) notify(t watcherEventType) chan watcherEvent { @@ -87,7 +95,21 @@ func (w *mrtWatcher) stop() { w.t.Kill(nil) } +func (w *mrtWatcher) restart(filename string) error { + adminOp := &mrtWatcherOp{ + filename: filename, + result: make(chan error), + } + select { + case w.opCh <- adminOp: + default: + return fmt.Errorf("already an admin operaiton in progress") + } + return <-adminOp.result +} + func (w *mrtWatcher) loop() error { + defer w.file.Close() for { write := func(ev watcherEvent) { m := ev.(*watcherEventUpdateMsg) @@ -117,28 +139,55 @@ func (w *mrtWatcher) loop() error { } } - select { - case <-w.t.Dying(): + drain := func() { for len(w.ch) > 0 { m := <-w.ch write(m) } + } + + select { + case <-w.t.Dying(): + drain() return nil case m := <-w.ch: write(m) + case adminOp := <-w.opCh: + var err error + if adminOp.filename != "" { + err = os.Rename(w.file.Name(), adminOp.filename) + } + if err == nil { + var file *os.File + file, err = mrtFileOpen(w.file.Name()) + if err == nil { + w.file.Close() + w.file = file + } + } + adminOp.result <- err } } } -func newMrtWatcher(filename string) (*mrtWatcher, error) { +func mrtFileOpen(filename string) (*os.File, error) { file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644) if err != nil { - log.Fatal(err) + log.Warn(err) + } + return file, err +} + +func newMrtWatcher(filename string) (*mrtWatcher, error) { + file, err := mrtFileOpen(filename) + if err != nil { + return nil, err } w := mrtWatcher{ filename: filename, file: file, ch: make(chan watcherEvent), + opCh: make(chan *mrtWatcherOp, 1), } w.t.Go(w.loop) return &w, nil |