diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-04-04 14:02:46 +0000 |
---|---|---|
committer | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-04-04 14:02:46 +0000 |
commit | 01a0fc94cc86a536544ab641bbaf9f54aad1593c (patch) | |
tree | 141716b2b98da6bad1a59a2500c2601ddf82c11f | |
parent | 6d2fec2f4f86edc29a058b4971553fe48b1a7c7c (diff) |
api/server: add apis to add/delete routes to/from global rib
add: curl -X POST -d prefix=10.0.0.0/24 http://localhost:8080/v1/bgp/global/ipv4
delete: curl -X DELETE -d prefix=10.0.0.0/24 http://localhost:8080/v1/bgp/global/ipv4
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r-- | api/rest.go | 59 | ||||
-rw-r--r-- | server/peer.go | 65 | ||||
-rw-r--r-- | server/peer_test.go | 18 | ||||
-rw-r--r-- | server/server.go | 3 |
4 files changed, 133 insertions, 12 deletions
diff --git a/api/rest.go b/api/rest.go index 1201abea..fd57253d 100644 --- a/api/rest.go +++ b/api/rest.go @@ -16,11 +16,13 @@ package api import ( + "bytes" log "github.com/Sirupsen/logrus" "github.com/fukata/golang-stats-api-handler" "github.com/gorilla/mux" "github.com/osrg/gobgp/packet" "net/http" + "net/url" "strconv" ) @@ -39,6 +41,8 @@ const ( REQ_NEIGHBOR_ENABLE REQ_NEIGHBOR_DISABLE REQ_GLOBAL_RIB + REQ_GLOBAL_ADD + REQ_GLOBAL_DELETE ) const ( @@ -66,14 +70,16 @@ type RestRequest struct { RouteFamily bgp.RouteFamily ResponseCh chan *RestResponse Err error + Data map[string]interface{} } -func NewRestRequest(reqType int, remoteAddr string, rf bgp.RouteFamily) *RestRequest { +func NewRestRequest(reqType int, remoteAddr string, rf bgp.RouteFamily, d map[string]interface{}) *RestRequest { r := &RestRequest{ RequestType: reqType, RouteFamily: rf, RemoteAddr: remoteAddr, ResponseCh: make(chan *RestResponse), + Data: d, } return r } @@ -122,6 +128,8 @@ func (rs *RestServer) Serve() { operationURL := "/{" + PARAM_OPERATION + "}" routeFamilyURL := "/{" + PARAM_ROUTE_FAMILY + "}" r.HandleFunc(global+showObjectURL+routeFamilyURL, rs.GlobalGET).Methods("GET") + r.HandleFunc(global+routeFamilyURL, rs.GlobalPOST).Methods("POST") + r.HandleFunc(global+routeFamilyURL, rs.GlobalDELETE).Methods("DELETE") r.HandleFunc(neighbors, rs.NeighborGET).Methods("GET") r.HandleFunc(neighbor+perPeerURL, rs.NeighborGET).Methods("GET") r.HandleFunc(neighbor+perPeerURL+showObjectURL+routeFamilyURL, rs.NeighborGET).Methods("GET") @@ -160,7 +168,7 @@ func (rs *RestServer) neighbor(w http.ResponseWriter, r *http.Request, reqType i } //Send channel of request parameter. - req := NewRestRequest(reqType, remoteAddr, rf) + req := NewRestRequest(reqType, remoteAddr, rf, nil) rs.bgpServerCh <- req //Wait response @@ -233,6 +241,53 @@ func (rs *RestServer) GlobalGET(w http.ResponseWriter, r *http.Request) { } +func (rs *RestServer) global(w http.ResponseWriter, r *http.Request, reqType int) { + params := mux.Vars(r) + var rf bgp.RouteFamily + routeFamily, ok := params[PARAM_ROUTE_FAMILY] + if ok { + switch routeFamily { + case "ipv4": + rf = bgp.RF_IPv4_UC + case "ipv6": + rf = bgp.RF_IPv6_UC + case "evpn": + rf = bgp.RF_EVPN + default: + NotFoundHandler(w, r) + return + } + } + var buf bytes.Buffer + buf.ReadFrom(r.Body) + query, _ := url.ParseQuery(buf.String()) + d := make(map[string]interface{}) + for k, v := range query { + d[k] = v + } + req := NewRestRequest(reqType, "", rf, d) + rs.bgpServerCh <- req + + //Wait response + res := <-req.ResponseCh + if e := res.Err(); e != nil { + log.Debug(e.Error()) + http.Error(w, e.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Write(res.Data) +} + +func (rs *RestServer) GlobalPOST(w http.ResponseWriter, r *http.Request) { + rs.global(w, r, REQ_GLOBAL_ADD) +} + +func (rs *RestServer) GlobalDELETE(w http.ResponseWriter, r *http.Request) { + rs.global(w, r, REQ_GLOBAL_DELETE) +} + func NotFoundHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) } diff --git a/server/peer.go b/server/peer.go index 362482a7..8c62d105 100644 --- a/server/peer.go +++ b/server/peer.go @@ -17,6 +17,7 @@ package server import ( "encoding/json" + "fmt" log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" @@ -101,6 +102,9 @@ func NewPeer(g config.Global, peer config.Neighbor, serverMsgCh chan *serverMsg, LocalID: g.RouterId, Address: peer.NeighborAddress, } + if isGlobalRib { + p.peerInfo.ID = g.RouterId + } rfList := p.configuredRFlist() p.adjRib = table.NewAdjRib(rfList) p.rib = table.NewTableManager(p.peerConfig.NeighborAddress.String(), rfList) @@ -287,6 +291,67 @@ func (peer *Peer) sendMessages(msgs []*bgp.BGPMessage) { func (peer *Peer) handleREST(restReq *api.RestRequest) { result := &api.RestResponse{} switch restReq.RequestType { + case api.REQ_GLOBAL_ADD, api.REQ_GLOBAL_DELETE: + rf := restReq.RouteFamily + prefixes := restReq.Data["prefix"].([]string) + var isWithdraw bool + if restReq.RequestType == api.REQ_GLOBAL_DELETE { + isWithdraw = true + } + + pList := make([]table.Path, 0, len(prefixes)) + for _, prefix := range prefixes { + var nlri bgp.AddrPrefixInterface + pattr := make([]bgp.PathAttributeInterface, 0) + pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)) + asparam := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{peer.peerInfo.AS}) + pattr = append(pattr, bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{asparam})) + + if rf == bgp.RF_IPv4_UC { + ip, net, _ := net.ParseCIDR(prefix) + if ip.To4() == nil { + result.ResponseErr = fmt.Errorf("Invalid ipv4 prefix: %s", prefix) + restReq.ResponseCh <- result + close(restReq.ResponseCh) + return + } + ones, _ := net.Mask.Size() + nlri = &bgp.NLRInfo{ + IPAddrPrefix: *bgp.NewIPAddrPrefix(uint8(ones), ip.String()), + } + + pattr = append(pattr, bgp.NewPathAttributeNextHop("0.0.0.0")) + + } else if rf == bgp.RF_IPv6_UC { + ip, net, _ := net.ParseCIDR(prefix) + if ip.To16() == nil { + result.ResponseErr = fmt.Errorf("Invalid ipv6 prefix: %s", prefix) + restReq.ResponseCh <- result + close(restReq.ResponseCh) + return + } + ones, _ := net.Mask.Size() + nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) + + pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})) + + } else { + result.ResponseErr = fmt.Errorf("Unsupported address family: %s", rf) + restReq.ResponseCh <- result + close(restReq.ResponseCh) + return + } + + p := table.CreatePath(peer.peerInfo, nlri, pattr, isWithdraw, time.Now()) + pList = append(pList, p) + } + + pm := &peerMsg{ + msgType: PEER_MSG_PATH, + msgData: pList, + } + peer.peerMsgCh <- pm + case api.REQ_LOCAL_RIB, api.REQ_GLOBAL_RIB: // just empty so we use ipv4 for any route family j, _ := json.Marshal(table.NewIPv4Table(0)) diff --git a/server/peer_test.go b/server/peer_test.go index 23588fdc..90c64960 100644 --- a/server/peer_test.go +++ b/server/peer_test.go @@ -123,7 +123,7 @@ func TestPeerAdminShutdownWhileEstablished(t *testing.T) { peer.connCh <- m waitUntil(assert, bgp.BGP_FSM_ESTABLISHED, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -166,7 +166,7 @@ func TestPeerAdminShutdownWhileIdle(t *testing.T) { waitUntil(assert, bgp.BGP_FSM_IDLE, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -201,7 +201,7 @@ func TestPeerAdminShutdownWhileActive(t *testing.T) { waitUntil(assert, bgp.BGP_FSM_ACTIVE, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -238,7 +238,7 @@ func TestPeerAdminShutdownWhileOpensent(t *testing.T) { peer.connCh <- m waitUntil(assert, bgp.BGP_FSM_OPENSENT, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -283,7 +283,7 @@ func TestPeerAdminShutdownWhileOpenconfirm(t *testing.T) { peer.connCh <- m waitUntil(assert, bgp.BGP_FSM_OPENCONFIRM, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -334,7 +334,7 @@ func TestPeerAdminEnable(t *testing.T) { waitUntil(assert, bgp.BGP_FSM_ESTABLISHED, peer, 1000) // shutdown peer at first - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -350,7 +350,7 @@ func TestPeerAdminEnable(t *testing.T) { assert.Equal(ADMIN_STATE_DOWN, peer.fsm.adminState) // enable peer - restReq = api.NewRestRequest(api.REQ_NEIGHBOR_ENABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq = api.NewRestRequest(api.REQ_NEIGHBOR_ENABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg = &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -397,7 +397,7 @@ func TestPeerAdminShutdownReject(t *testing.T) { peer.connCh <- m waitUntil(assert, bgp.BGP_FSM_OPENSENT, peer, 1000) - restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq := api.NewRestRequest(api.REQ_NEIGHBOR_DISABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, @@ -411,7 +411,7 @@ func TestPeerAdminShutdownReject(t *testing.T) { json.Unmarshal(result.Data, &res) assert.Equal("previous request is still remaining", res["result"]) - restReq = api.NewRestRequest(api.REQ_NEIGHBOR_ENABLE, "0.0.0.0", bgp.RF_IPv4_UC) + restReq = api.NewRestRequest(api.REQ_NEIGHBOR_ENABLE, "0.0.0.0", bgp.RF_IPv4_UC, nil) msg = &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, diff --git a/server/server.go b/server/server.go index ebb7a611..a47f9177 100644 --- a/server/server.go +++ b/server/server.go @@ -116,6 +116,7 @@ func (server *BgpServer) Serve() { neighConf := config.Neighbor{ NeighborAddress: g.RouterId, AfiSafiList: g.AfiSafiList, + PeerAs: g.As, } server.globalRib = NewPeer(g, neighConf, globalSch, globalPch, nil, true, make(map[string]*policy.Policy)) @@ -320,7 +321,7 @@ func (server *BgpServer) handleRest(restReq *api.RestRequest) { } restReq.ResponseCh <- result close(restReq.ResponseCh) - case api.REQ_GLOBAL_RIB: + case api.REQ_GLOBAL_RIB, api.REQ_GLOBAL_ADD, api.REQ_GLOBAL_DELETE: msg := &serverMsg{ msgType: SRV_MSG_API, msgData: restReq, |