diff options
-rw-r--r-- | api/rest.go | 51 | ||||
-rwxr-xr-x | cli/gobgpcli | 33 | ||||
-rw-r--r-- | server/fsm.go | 17 | ||||
-rw-r--r-- | server/peer.go | 20 | ||||
-rw-r--r-- | server/server.go | 4 |
5 files changed, 96 insertions, 29 deletions
diff --git a/api/rest.go b/api/rest.go index 2fba4496..404a6bb5 100644 --- a/api/rest.go +++ b/api/rest.go @@ -21,6 +21,7 @@ import ( "github.com/gorilla/mux" "net/http" "strconv" + "strings" ) const ( @@ -30,16 +31,17 @@ const ( REQ_ADJ_RIB_IN REQ_ADJ_RIB_OUT REQ_LOCAL_RIB + REQ_NEIGHBOR_SHUTDOWN + REQ_NEIGHBOR_RESET + REQ_NEIGHBOR_SOFT_RESET + REQ_NEIGHBOR_SOFT_RESET_IN + REQ_NEIGHBOR_SOFT_RESET_OUT ) const ( - BASE_VERSION = "/v1" - NEIGHBOR = "/bgp/neighbor" - NEIGHBORS = "/bgp/neighbors" - ADJ_RIB_IN = "/bgp/adj-rib-in" - ADJ_RIB_OUT = "/bgp/adj-rib-out" - ADJ_RIB_LOCAL = "/bgp/adj-rib-local" - ADJ_RIB_LOCAL_BEST = "/bgp/adj-rib-local/best" + BASE_VERSION = "/v1" + NEIGHBOR = "/bgp/neighbor" + NEIGHBORS = "/bgp/neighbors" PARAM_REMOTE_PEER_ADDR = "remotePeerAddr" STATS = "/stats" @@ -102,18 +104,19 @@ func NewRestServer(port int, bgpServerCh chan *RestRequest) *RestServer { func (rs *RestServer) Serve() { neighbor := BASE_VERSION + NEIGHBOR neighbors := BASE_VERSION + NEIGHBORS - // adjRibIn := BASE_VERSION + ADJ_RIB_IN - // adjRibOut := BASE_VERSION + ADJ_RIB_OUT - // adjRibLocal := BASE_VERSION + ADJ_RIB_LOCAL - // adjRibLocalBest := BASE_VERSION + ADJ_RIB_LOCAL_BEST r := mux.NewRouter() - // set URLs + + perPeerURL := "/{" + PARAM_REMOTE_PEER_ADDR + "}" r.HandleFunc(neighbors, rs.Neighbors).Methods("GET") - r.HandleFunc(neighbor+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.Neighbor).Methods("GET") - // r.HandleFunc(adjRibIn+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibIn).Methods("GET") - // r.HandleFunc(adjRibOut+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibOut).Methods("GET") - r.HandleFunc(neighbor+"/{"+PARAM_REMOTE_PEER_ADDR+"}/"+"local-rib", rs.NeighborLocalRib).Methods("GET") + r.HandleFunc(neighbor+perPeerURL, rs.Neighbor).Methods("GET") + r.HandleFunc(neighbor+perPeerURL+"/"+"local-rib", rs.NeighborLocalRib).Methods("GET") + r.HandleFunc(neighbor+perPeerURL+"/"+"shutdown", rs.NeighborPostHandler).Methods("POST") + r.HandleFunc(neighbor+perPeerURL+"/"+"reset", rs.NeighborPostHandler).Methods("POST") + r.HandleFunc(neighbor+perPeerURL+"/"+"softreset", rs.NeighborPostHandler).Methods("POST") + r.HandleFunc(neighbor+perPeerURL+"/"+"softresetin", rs.NeighborPostHandler).Methods("POST") + r.HandleFunc(neighbor+perPeerURL+"/"+"softresetout", rs.NeighborPostHandler).Methods("POST") + // stats r.HandleFunc(STATS, stats_api.Handler).Methods("GET") @@ -154,6 +157,22 @@ func (rs *RestServer) neighbor(w http.ResponseWriter, r *http.Request, reqType i w.Write(res.Data) } +func (rs *RestServer) NeighborPostHandler(w http.ResponseWriter, r *http.Request) { + action := strings.Split(r.URL.Path, "/") + switch action[len(action)-1] { + case "shutdown": + rs.neighbor(w, r, REQ_NEIGHBOR_SHUTDOWN) + case "reset": + rs.neighbor(w, r, REQ_NEIGHBOR_RESET) + case "softreset": + rs.neighbor(w, r, REQ_NEIGHBOR_SOFT_RESET) + case "softresetin": + rs.neighbor(w, r, REQ_NEIGHBOR_SOFT_RESET_IN) + case "softresetout": + rs.neighbor(w, r, REQ_NEIGHBOR_SOFT_RESET_OUT) + } +} + func (rs *RestServer) Neighbor(w http.ResponseWriter, r *http.Request) { rs.neighbor(w, r, REQ_NEIGHBOR) } diff --git a/cli/gobgpcli b/cli/gobgpcli index 70e70e78..55d9b379 100755 --- a/cli/gobgpcli +++ b/cli/gobgpcli @@ -24,6 +24,14 @@ # $ gobgpcli show neighbor 10.0.0.2 # - get the local rib of a neighbor # $ gobgpcli show neighbor 10.0.0.2 local +# - reset +# $ gobgpcli reset neighbor 10.0.0.2 +# - softresetin +# $ gobgpcli softresetin neighbor 10.0.0.2 +# - softresetout +# $ gobgpcli softresetout neighbor 10.0.0.2 +# - shutdown +# $ gobgpcli shutdown neighbor 10.0.0.2 from optparse import OptionParser import requests @@ -33,8 +41,27 @@ import json from datetime import timedelta +class Action(object): + def __init__(self, command, options, args): + super(Action, self).__init__() + self.command = command + self.options = options + self.args = args + self.base_url = self.options.url + ":" + str(self.options.port) + "/v1/bgp" + + def __call__(self): + if len(self.args) != 1: + return 1 + r = requests.post(self.base_url + "/neighbor/" + self.args[0] + "/" + self.command) + if r.status_code == requests.codes.ok: + print "Succeed" + else: + print "Failed" + return 0 + + class Show(object): - def __init__(self, options, args): + def __init__(self, _command, options, args): super(Show, self).__init__() self.options = options self.args = args @@ -194,7 +221,7 @@ def main(): (options, args) = parser.parse_args() - commands = {"show": Show} + commands = {"show": Show, "reset": Action, "shutdown": Action, "softreset": Action, "softresetin": Action, "softresetout": Action} if len(args) == 0: parser.print_help() @@ -204,7 +231,7 @@ def main(): parser.print_help() sys.exit(1) - ret = commands[args[0]](options, args[1:])() + ret = commands[args[0]](args[0], options, args[1:])() if ret != 0: parser.print_help() sys.exit(1) diff --git a/server/fsm.go b/server/fsm.go index d57a6f42..81050b31 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -122,7 +122,7 @@ type FSMHandler struct { func NewFSMHandler(fsm *FSM) *FSMHandler { f := &FSMHandler{ fsm: fsm, - errorCh: make(chan bool), + errorCh: make(chan bool, 2), } f.t.Go(f.loop) return f @@ -281,7 +281,11 @@ func (h *FSMHandler) opensent() bgp.FSMState { case *bgp.MessageError: err := e.MsgData.(*bgp.MessageError) m := bgp.NewBGPNotificationMessage(err.TypeCode, err.SubTypeCode, err.Data) - h.fsm.outgoing <- m + b, _ := m.Serialize() + fsm.passiveConn.Write(b) + fsm.bgpMessageStateUpdate(m.Header.Type, false) + h.conn.Close() + nextState = bgp.BGP_FSM_IDLE default: log.WithFields(log.Fields{ "Topic": "Peer", @@ -330,10 +334,11 @@ func (h *FSMHandler) openconfirm() bgp.FSMState { case *bgp.MessageError: err := e.MsgData.(*bgp.MessageError) m := bgp.NewBGPNotificationMessage(err.TypeCode, err.SubTypeCode, err.Data) - h.fsm.outgoing <- m - // tx goroutine will close the tcp - // connection and state will be - // changed. so no need to change here. + b, _ := m.Serialize() + fsm.passiveConn.Write(b) + fsm.bgpMessageStateUpdate(m.Header.Type, false) + h.conn.Close() + return bgp.BGP_FSM_IDLE default: log.WithFields(log.Fields{ "Topic": "Peer", diff --git a/server/peer.go b/server/peer.go index 4e6f2ff3..6f0d2f6b 100644 --- a/server/peer.go +++ b/server/peer.go @@ -168,8 +168,24 @@ func (peer *Peer) sendMessages(msgs []*bgp.BGPMessage) { func (peer *Peer) handleREST(restReq *api.RestRequest) { result := &api.RestResponse{} - j, _ := json.Marshal(peer.rib.Tables[peer.rf]) - result.Data = j + switch restReq.RequestType { + case api.REQ_LOCAL_RIB: + j, _ := json.Marshal(peer.rib.Tables[peer.rf]) + result.Data = j + case api.REQ_NEIGHBOR_SHUTDOWN: + peer.fsm.outgoing <- bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN, nil) + case api.REQ_NEIGHBOR_RESET: + peer.fsm.outgoing <- bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_RESET, nil) + case api.REQ_NEIGHBOR_SOFT_RESET: + case api.REQ_NEIGHBOR_SOFT_RESET_IN: + // check capability + // drop allIn and other peers? + // peer.adjRib.DropAllIn(peer.rf) + peer.fsm.outgoing <- bgp.NewBGPRouteRefreshMessage(uint16(int(peer.rf)>>16), 0, uint8(int(peer.rf)&0xff)) + case api.REQ_NEIGHBOR_SOFT_RESET_OUT: + pathList := peer.adjRib.GetOutPathList(peer.rf) + peer.sendMessages(table.CreateUpdateMsgFromPaths(pathList)) + } restReq.ResponseCh <- result close(restReq.ResponseCh) } diff --git a/server/server.go b/server/server.go index bc4274de..cbd67732 100644 --- a/server/server.go +++ b/server/server.go @@ -228,7 +228,7 @@ func (server *BgpServer) handleRest(restReq *api.RestRequest) { restReq.ResponseCh <- result close(restReq.ResponseCh) - case api.REQ_NEIGHBOR: // get neighbor state + case api.REQ_NEIGHBOR: remoteAddr := restReq.RemoteAddr result := &api.RestResponse{} @@ -241,7 +241,7 @@ func (server *BgpServer) handleRest(restReq *api.RestRequest) { } restReq.ResponseCh <- result close(restReq.ResponseCh) - case api.REQ_LOCAL_RIB: + case api.REQ_LOCAL_RIB, api.REQ_NEIGHBOR_SHUTDOWN, api.REQ_NEIGHBOR_RESET, api.REQ_NEIGHBOR_SOFT_RESET_IN, api.REQ_NEIGHBOR_SOFT_RESET_OUT: remoteAddr := restReq.RemoteAddr result := &api.RestResponse{} info, found := server.peerMap[remoteAddr] |