summaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/grpc_server.go30
-rw-r--r--server/server.go137
2 files changed, 167 insertions, 0 deletions
diff --git a/server/grpc_server.go b/server/grpc_server.go
index 160e9cfc..4a652c4f 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -82,6 +82,7 @@ const (
REQ_POLICY_EXTCOMMUNITIES_DELETE
REQ_MONITOR_GLOBAL_BEST_CHANGED
REQ_MONITOR_NEIGHBOR_PEER_STATE
+ REQ_MRT_GLOBAL_RIB
)
const GRPC_PORT = 8080
@@ -591,6 +592,35 @@ func (s *Server) ModPolicyRoutePolicy(stream api.Grpc_ModPolicyRoutePolicyServer
}
}
+func (s *Server) GetMrt(arg *api.MrtArguments, stream api.Grpc_GetMrtServer) error {
+ var reqType int
+ switch arg.Resource {
+ case api.Resource_GLOBAL:
+ reqType = REQ_MRT_GLOBAL_RIB
+ default:
+ return fmt.Errorf("unsupported resource type: %v", arg.Resource)
+ }
+ rf, err := convertAf2Rf(arg.Af)
+ if err != nil {
+ return err
+ }
+
+ req := NewGrpcRequest(reqType, "", rf, arg.Interval)
+ s.bgpServerCh <- req
+ for res := range req.ResponseCh {
+ if err = res.Err(); err != nil {
+ log.Debug(err.Error())
+ goto END
+ }
+ if err = stream.Send(res.Data.(*api.MrtMessage)); err != nil {
+ goto END
+ }
+ }
+END:
+ req.EndCh <- struct{}{}
+ return err
+}
+
type GrpcRequest struct {
RequestType int
RemoteAddr string
diff --git a/server/server.go b/server/server.go
index 78dd3b80..859abba2 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1235,6 +1235,8 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
server.handleGrpcDelPolicies(grpcReq)
case REQ_MONITOR_GLOBAL_BEST_CHANGED, REQ_MONITOR_NEIGHBOR_PEER_STATE:
server.broadcastReqs = append(server.broadcastReqs, grpcReq)
+ case REQ_MRT_GLOBAL_RIB:
+ server.handleMrt(grpcReq)
default:
errmsg := fmt.Errorf("Unknown request type: %v", grpcReq.RequestType)
result := &GrpcResponse{
@@ -1853,3 +1855,138 @@ func (server *BgpServer) handleGrpcDelPolicies(grpcReq *GrpcRequest) {
grpcReq.ResponseCh <- result
close(grpcReq.ResponseCh)
}
+
+func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) {
+ now := uint32(time.Now().Unix())
+ msg, err := server.mkMrtPeerIndexTableMsg(now)
+ result := &GrpcResponse{}
+ if err != nil {
+ result.ResponseErr = fmt.Errorf("failed to make new mrt peer index table message: %s", err)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+ data, err := msg.Serialize()
+ if err != nil {
+ result.ResponseErr = fmt.Errorf("failed to serialize table: %s", err)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+
+ msgs, err := server.mkMrtRibMsgs(grpcReq.RouteFamily, now)
+ if err != nil {
+ result.ResponseErr = fmt.Errorf("failed to make new mrt rib message: %s", err)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+ for _, msg := range msgs {
+ d, err := msg.Serialize()
+ if err != nil {
+ result.ResponseErr = fmt.Errorf("failed to serialize rib msg: %s", err)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+ data = append(data, d...)
+ }
+
+ result.Data = &api.MrtMessage{
+ Data: data,
+ }
+
+ select {
+ case <-grpcReq.EndCh:
+ return
+ case grpcReq.ResponseCh <- result:
+ default:
+ }
+
+ interval := int64(grpcReq.Data.(uint64))
+ if interval > 0 {
+ go func() {
+ t := time.NewTimer(time.Second * time.Duration(interval))
+ <-t.C
+ server.GrpcReqCh <- grpcReq
+ }()
+ } else {
+ close(grpcReq.ResponseCh)
+ }
+
+ return
+}
+
+func (server *BgpServer) mkMrtPeerIndexTableMsg(t uint32) (*bgp.MRTMessage, error) {
+ peers := make([]*bgp.Peer, 0, len(server.neighborMap))
+ for _, peer := range server.neighborMap {
+ id := peer.peerInfo.ID.To4().String()
+ ipaddr := peer.config.NeighborAddress.String()
+ asn := peer.config.PeerAs
+ peers = append(peers, bgp.NewPeer(id, ipaddr, asn, true))
+ }
+ bgpid := server.bgpConfig.Global.RouterId.To4().String()
+ table := bgp.NewPeerIndexTable(bgpid, "", peers)
+ return bgp.NewMRTMessage(t, bgp.TABLE_DUMPv2, bgp.PEER_INDEX_TABLE, table)
+}
+
+func (server *BgpServer) mkMrtRibMsgs(rf bgp.RouteFamily, t uint32) ([]*bgp.MRTMessage, error) {
+ tbl, ok := server.localRibMap[GLOBAL_RIB_NAME].rib.Tables[rf]
+ if !ok {
+ return nil, fmt.Errorf("unsupported route family: %s", rf)
+ }
+
+ getPeerIndex := func(info *table.PeerInfo) uint16 {
+ var idx uint16
+ for _, peer := range server.neighborMap {
+ if peer.peerInfo.Equal(info) {
+ return idx
+ }
+ idx++
+ }
+ return idx
+ }
+
+ var subtype bgp.MRTSubTypeTableDumpv2
+
+ switch rf {
+ case bgp.RF_IPv4_UC:
+ subtype = bgp.RIB_IPV4_UNICAST
+ case bgp.RF_IPv4_MC:
+ subtype = bgp.RIB_IPV4_MULTICAST
+ case bgp.RF_IPv6_UC:
+ subtype = bgp.RIB_IPV6_UNICAST
+ case bgp.RF_IPv6_MC:
+ subtype = bgp.RIB_IPV6_MULTICAST
+ default:
+ subtype = bgp.RIB_GENERIC
+ }
+
+ var seq uint32
+ msgs := make([]*bgp.MRTMessage, 0, len(tbl.GetDestinations()))
+ for _, dst := range tbl.GetDestinations() {
+ l := dst.GetKnownPathList()
+ entries := make([]*bgp.RibEntry, 0, len(l))
+ for _, p := range l {
+ // mrt doesn't assume to dump locally generated routes
+ if p.IsLocal() {
+ continue
+ }
+ idx := getPeerIndex(p.GetSource())
+ e := bgp.NewRibEntry(idx, uint32(p.GetTimestamp().Unix()), p.GetPathAttrs())
+ entries = append(entries, e)
+ }
+ // if dst only contains locally generated routes, ignore it
+ if len(entries) == 0 {
+ continue
+ }
+ rib := bgp.NewRib(seq, dst.GetNlri(), entries)
+ seq++
+ msg, err := bgp.NewMRTMessage(t, bgp.TABLE_DUMPv2, subtype, rib)
+ if err != nil {
+ return nil, err
+ }
+ msgs = append(msgs, msg)
+ }
+ return msgs, nil
+}