mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
Add rest API support
Signed-off-by: FUJITA Tomonori <[email protected]>
This commit is contained in:
committed by
FUJITA Tomonori
parent
275f20e96e
commit
d2bbac0697
+212
@@ -0,0 +1,212 @@
|
||||
// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
// implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var logger *log.Logger = &log.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(log.JSONFormatter),
|
||||
Hooks: make(map[log.Level][]log.Hook),
|
||||
Level: log.InfoLevel,
|
||||
}
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
REQ_NEIGHBOR
|
||||
REQ_NEIGHBORS
|
||||
REQ_ADJ_RIB_IN
|
||||
REQ_ADJ_RIB_OUT
|
||||
REQ_ADJ_RIB_LOCAL
|
||||
REQ_ADJ_RIB_LOCAL_BEST
|
||||
)
|
||||
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"
|
||||
|
||||
PARAM_REMOTE_PEER_ADDR = "remotePeerAddr"
|
||||
)
|
||||
|
||||
const REST_PORT = 8080
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
JSON_FORMATTED
|
||||
JSON_UN_FORMATTED
|
||||
)
|
||||
|
||||
var JsonFormat int = JSON_FORMATTED
|
||||
|
||||
// trigger struct for exchanging information in the rest and peer.
|
||||
// rest and peer operated at different thread.
|
||||
|
||||
type RestRequest struct {
|
||||
RequestType int
|
||||
RemoteAddr string
|
||||
ResponseCh chan RestResponse
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewRestRequest(reqType int, remoteAddr string) *RestRequest {
|
||||
r := &RestRequest{
|
||||
RequestType: reqType,
|
||||
RemoteAddr: remoteAddr,
|
||||
ResponseCh: make(chan RestResponse),
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type RestResponse interface {
|
||||
Err() error
|
||||
}
|
||||
|
||||
type RestResponseDefault struct {
|
||||
ResponseErr error
|
||||
}
|
||||
|
||||
func (r *RestResponseDefault) Err() error {
|
||||
return r.ResponseErr
|
||||
}
|
||||
|
||||
// Response struct for Neighbor
|
||||
type RestResponseNeighbor struct {
|
||||
RestResponseDefault
|
||||
RemoteAddr string
|
||||
RemoteAs uint32
|
||||
NeighborState uint32
|
||||
UpdateCount int
|
||||
}
|
||||
|
||||
// Response struct for Rib
|
||||
type RestResponseRib struct {
|
||||
RestResponseDefault
|
||||
RemoteAddr string
|
||||
RemoteAs uint32
|
||||
RibInfo []string
|
||||
}
|
||||
|
||||
type RestServer struct {
|
||||
port int
|
||||
bgpServerCh chan *RestRequest
|
||||
}
|
||||
|
||||
func NewRestServer(port int, bgpServerCh chan *RestRequest) *RestServer {
|
||||
rs := &RestServer{
|
||||
port: port,
|
||||
bgpServerCh: bgpServerCh}
|
||||
return rs
|
||||
}
|
||||
|
||||
// Main thread of rest service.
|
||||
// URL than can receive.
|
||||
// get state of neighbor.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/neighbor/<remote address of target neighbor>
|
||||
// get state of neighbors.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/neighbors
|
||||
// get adj-rib-in of each neighbor.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-in/<remote address of target neighbor>
|
||||
// get adj-rib-out of each neighbor.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-out/<remote address of target neighbor>
|
||||
// get adj-rib-local of each neighbor.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/<remote address of target neighbor>
|
||||
// get only best path of adj-rib-local of each neighbor.
|
||||
// -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/best/<remote address of target neighbor>
|
||||
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
|
||||
r.HandleFunc(neighbor+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.Neighbor).Methods("GET")
|
||||
// r.HandleFunc(neighbors, rs.Neighbors).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(adjRibLocal+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocal).Methods("GET")
|
||||
// r.HandleFunc(adjRibLocalBest+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocalBest).Methods("GET")
|
||||
|
||||
// Handler when not found url
|
||||
r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
|
||||
http.Handle("/", r)
|
||||
|
||||
http.ListenAndServe(":"+strconv.Itoa(rs.port), nil)
|
||||
|
||||
}
|
||||
|
||||
// Http request of curl, return the json format infomation of neibor state.
|
||||
func (rs *RestServer) Neighbor(w http.ResponseWriter, r *http.Request) {
|
||||
// remotePeerAddr := mux.Vars(r)[PARAM_REMOTE_PEER_ADDR]
|
||||
|
||||
params := mux.Vars(r)
|
||||
remoteAddr, found := params[PARAM_REMOTE_PEER_ADDR]
|
||||
if !found {
|
||||
errStr := "neighbor address is not specified"
|
||||
logger.Debug(errStr)
|
||||
http.Error(w, errStr, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
logger.Debugf("Look up neighbor with the remote address : %v", remoteAddr)
|
||||
|
||||
//Send channel of request parameter.
|
||||
req := NewRestRequest(REQ_NEIGHBOR, remoteAddr)
|
||||
rs.bgpServerCh <- req
|
||||
|
||||
//Wait response
|
||||
resInf := <-req.ResponseCh
|
||||
if e := resInf.Err(); e != nil {
|
||||
logger.Debug(e.Error())
|
||||
http.Error(w, e.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
res := resInf.(*RestResponseNeighbor)
|
||||
|
||||
var jns []byte
|
||||
var err error
|
||||
switch JsonFormat {
|
||||
case JSON_FORMATTED:
|
||||
jns, err = json.MarshalIndent(res, "", " ") // formatted json
|
||||
case JSON_UN_FORMATTED:
|
||||
jns, err = json.Marshal(res) // Unformatted json
|
||||
}
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Failed to perth json of neighbor state", remoteAddr)
|
||||
logger.Error(errStr)
|
||||
http.Error(w, errStr, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Write(jns)
|
||||
}
|
||||
|
||||
func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/osrg/gobgp/api"
|
||||
"github.com/osrg/gobgp/config"
|
||||
"github.com/osrg/gobgp/packet"
|
||||
"github.com/osrg/gobgp/server"
|
||||
@@ -54,6 +55,10 @@ func main() {
|
||||
bgpServer := server.NewBgpServer(bgp.BGP_PORT)
|
||||
go bgpServer.Serve()
|
||||
|
||||
// start Rest Server
|
||||
restServer := api.NewRestServer(api.REST_PORT, bgpServer.RestReqCh)
|
||||
go restServer.Serve()
|
||||
|
||||
var bgpConfig *config.BgpType = nil
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -17,6 +17,7 @@ package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/osrg/gobgp/api"
|
||||
"github.com/osrg/gobgp/config"
|
||||
"net"
|
||||
"os"
|
||||
@@ -43,6 +44,7 @@ type BgpServer struct {
|
||||
globalTypeCh chan config.GlobalType
|
||||
addedPeerCh chan config.NeighborType
|
||||
deletedPeerCh chan config.NeighborType
|
||||
RestReqCh chan *api.RestRequest
|
||||
listenPort int
|
||||
peerMap map[string]*Peer
|
||||
}
|
||||
@@ -52,6 +54,7 @@ func NewBgpServer(port int) *BgpServer {
|
||||
b.globalTypeCh = make(chan config.GlobalType)
|
||||
b.addedPeerCh = make(chan config.NeighborType)
|
||||
b.deletedPeerCh = make(chan config.NeighborType)
|
||||
b.RestReqCh = make(chan *api.RestRequest, 1)
|
||||
b.listenPort = port
|
||||
return &b
|
||||
}
|
||||
@@ -114,6 +117,9 @@ func (server *BgpServer) Serve() {
|
||||
} else {
|
||||
fmt.Println("can't found neighbor", addr)
|
||||
}
|
||||
case restReq := <-server.RestReqCh:
|
||||
server.handleRest(restReq)
|
||||
|
||||
case msg := <-broadcastCh:
|
||||
server.broadcast(msg)
|
||||
}
|
||||
@@ -143,3 +149,23 @@ func (server *BgpServer) broadcast(msg *message) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (server *BgpServer) handleRest(restReq *api.RestRequest) {
|
||||
defer close(restReq.ResponseCh)
|
||||
switch restReq.RequestType {
|
||||
case api.REQ_NEIGHBOR: // get neighbor state
|
||||
|
||||
remoteAddr := restReq.RemoteAddr
|
||||
result := &api.RestResponseNeighbor{}
|
||||
peer, found := server.peerMap[remoteAddr]
|
||||
if found {
|
||||
c := peer.peerConfig
|
||||
result.NeighborState = c.BgpNeighborCommonState.State
|
||||
result.RemoteAddr = c.NeighborAddress.String()
|
||||
result.RemoteAs = c.PeerAs
|
||||
} else {
|
||||
result.ResponseErr = fmt.Errorf("Neighbor that has %v does not exist.", remoteAddr)
|
||||
}
|
||||
restReq.ResponseCh <- result
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user