summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/gobgp.pb.go7
-rw-r--r--api/gobgp.proto1
-rw-r--r--api/util.go20
-rw-r--r--gobgp/common.go3
-rw-r--r--gobgp/mrt.go192
-rw-r--r--server/grpc_server.go5
-rw-r--r--server/server.go49
7 files changed, 210 insertions, 67 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index 40a1e596..901abcad 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -633,9 +633,10 @@ func (m *PolicyArguments) GetApplyPolicy() *ApplyPolicy {
}
type MrtArguments struct {
- Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"`
- Af *AddressFamily `protobuf:"bytes,2,opt,name=af" json:"af,omitempty"`
- Interval uint64 `protobuf:"varint,3,opt,name=interval" json:"interval,omitempty"`
+ Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"`
+ Af *AddressFamily `protobuf:"bytes,2,opt,name=af" json:"af,omitempty"`
+ Interval uint64 `protobuf:"varint,3,opt,name=interval" json:"interval,omitempty"`
+ NeighborAddress string `protobuf:"bytes,4,opt,name=neighbor_address" json:"neighbor_address,omitempty"`
}
func (m *MrtArguments) Reset() { *m = MrtArguments{} }
diff --git a/api/gobgp.proto b/api/gobgp.proto
index b80964eb..e50e3c71 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -76,6 +76,7 @@ message MrtArguments {
Resource resource = 1;
AddressFamily af = 2;
uint64 interval = 3;
+ string neighbor_address = 4;
}
enum Resource {
diff --git a/api/util.go b/api/util.go
index 677d4f6a..d1bd4649 100644
--- a/api/util.go
+++ b/api/util.go
@@ -26,3 +26,23 @@ var AF_RTC *AddressFamily = &AddressFamily{AFI_IP, SAFI_ROUTE_TARGET_CONSTRAINTS
func (lhs *AddressFamily) Equal(rhs *AddressFamily) bool {
return lhs.Afi == rhs.Afi && lhs.Safi == rhs.Safi
}
+
+func (af *AddressFamily) ShortString() string {
+ switch {
+ case af.Equal(AF_IPV4_UC):
+ return "ipv4"
+ case af.Equal(AF_IPV6_UC):
+ return "ipv6"
+ case af.Equal(AF_IPV4_VPN):
+ return "vpnv4"
+ case af.Equal(AF_IPV4_VPN):
+ return "vpnv6"
+ case af.Equal(AF_EVPN):
+ return "evpn"
+ case af.Equal(AF_ENCAP):
+ return "encap"
+ case af.Equal(AF_RTC):
+ return "rtc"
+ }
+ return "unknown"
+}
diff --git a/gobgp/common.go b/gobgp/common.go
index 436dae8a..f94b36df 100644
--- a/gobgp/common.go
+++ b/gobgp/common.go
@@ -86,7 +86,8 @@ var actionOpts struct {
}
var mrtOpts struct {
- OutputDir string
+ OutputDir string
+ FileFormat string
}
func formatTimedelta(d int64) string {
diff --git a/gobgp/mrt.go b/gobgp/mrt.go
index 3dc2d540..e32a0931 100644
--- a/gobgp/mrt.go
+++ b/gobgp/mrt.go
@@ -28,6 +28,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "text/template"
"time"
)
@@ -69,72 +70,163 @@ func printMrtMsgs(data []byte) {
}
-func NewMrtCmd() *cobra.Command {
- mrtCmd := &cobra.Command{
- Use: CMD_MRT,
+func dumpRib(r string, remoteIP net.IP, args []string) error {
+ var resource api.Resource
+ switch r {
+ case CMD_GLOBAL:
+ resource = api.Resource_GLOBAL
+ case CMD_LOCAL:
+ resource = api.Resource_LOCAL
+ default:
+ return fmt.Errorf("unknown resource type: %s", r)
}
- mrtCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")
- dumpCmd := &cobra.Command{
- Use: CMD_DUMP,
+ af, err := checkAddressFamily(remoteIP)
+ if err != nil {
+ return err
+ }
+
+ var interval uint64
+ if len(args) > 0 {
+ i, err := strconv.Atoi(args[0])
+ if err != nil {
+ return err
+ }
+ interval = uint64(i)
+ }
+
+ arg := &api.MrtArguments{
+ Resource: resource,
+ Af: af,
+ Interval: interval,
+ NeighborAddress: remoteIP.String(),
+ }
+
+ seed := struct {
+ Y string
+ M string
+ D string
+ H string
+ Min string
+ Sec string
+ Af string
+ NeighborAddress string
+ Resource string
+ }{
+ Af: af.ShortString(),
+ NeighborAddress: remoteIP.String(),
+ Resource: r,
+ }
+
+ stream, err := client.GetMrt(context.Background(), arg)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ var fileformat string
+
+ if mrtOpts.FileFormat != "" {
+ fileformat = mrtOpts.FileFormat
+ } else if r == CMD_GLOBAL {
+ fileformat = "rib_{{.Af}}_{{.Y}}{{.M}}{{.D}}_{{.H}}{{.Min}}{{.Sec}}"
+ } else {
+ fileformat = "rib_{{.NeighborAddress}}_{{.Y}}{{.M}}{{.D}}_{{.H}}{{.Min}}{{.Sec}}"
+ }
+
+ for {
+ s, err := stream.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ if globalOpts.Debug {
+ printMrtMsgs(s.Data)
+ }
+
+ now := time.Now()
+ y, m, d := now.Date()
+ seed.Y = fmt.Sprintf("%04d", y)
+ seed.M = fmt.Sprintf("%02d", int(m))
+ seed.D = fmt.Sprintf("%02d", d)
+ h, min, sec := now.Clock()
+ seed.H = fmt.Sprintf("%02d", h)
+ seed.Min = fmt.Sprintf("%02d", min)
+ seed.Sec = fmt.Sprintf("%02d", sec)
+ t, err := template.New("f").Parse(fileformat)
+ if err != nil {
+ return err
+ }
+ buf := bytes.NewBuffer(make([]byte, 0, 32))
+ err = t.Execute(buf, seed)
+ if err != nil {
+ return err
+ }
+ filename := fmt.Sprintf("%s/%s", mrtOpts.OutputDir, buf.String())
+
+ err = ioutil.WriteFile(filename, s.Data, 0600)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ fmt.Println("mrt dump:", filepath.Clean(filename))
+ }
+ return nil
+}
+
+func NewMrtCmd() *cobra.Command {
+
+ globalCmd := &cobra.Command{
+ Use: CMD_GLOBAL,
Run: func(cmd *cobra.Command, args []string) {
- var interval uint64
- if len(args) > 0 {
- i, err := strconv.Atoi(args[0])
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
- interval = uint64(i)
- }
- af, err := checkAddressFamily(net.IP{})
+ err := dumpRib(CMD_GLOBAL, net.IP{}, args)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
+ },
+ }
- arg := &api.MrtArguments{
- Resource: api.Resource_GLOBAL,
- Af: af,
- Interval: interval,
+ neighborCmd := &cobra.Command{
+ Use: CMD_NEIGHBOR,
+ Run: func(cmd *cobra.Command, args []string) {
+ if len(args) < 1 {
+ fmt.Println("usage: gobgp mrt dump neighbor <neighbor address> [<interval>]")
+ os.Exit(1)
}
-
- stream, err := client.GetMrt(context.Background(), arg)
+ remoteIP := net.ParseIP(args[0])
+ if remoteIP == nil {
+ fmt.Println("invalid ip address:", args[0])
+ os.Exit(1)
+ }
+ err := dumpRib(CMD_LOCAL, remoteIP, args[1:])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
-
- for {
- s, err := stream.Recv()
- if err == io.EOF {
- break
- } else if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- if globalOpts.Debug {
- printMrtMsgs(s.Data)
- }
-
- now := time.Now()
- y, m, d := now.Date()
- h, min, sec := now.Clock()
- filename := fmt.Sprintf("%s/rib.%04d%02d%02d.%02d%02d%02d", mrtOpts.OutputDir, y, m, d, h, min, sec)
-
- err = ioutil.WriteFile(filename, s.Data, 0600)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- fmt.Println("mrt dump:", filepath.Clean(filename))
- }
},
}
- dumpCmd.Flags().StringVarP(&mrtOpts.OutputDir, "outdir", "o", ".", "output directory")
+ ribCmd := &cobra.Command{
+ Use: CMD_RIB,
+ }
+ ribCmd.AddCommand(globalCmd, neighborCmd)
+ ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")
+
+ dumpCmd := &cobra.Command{
+ Use: CMD_DUMP,
+ }
+ dumpCmd.AddCommand(ribCmd)
+ dumpCmd.PersistentFlags().StringVarP(&mrtOpts.OutputDir, "outdir", "o", ".", "output directory")
+ dumpCmd.PersistentFlags().StringVarP(&mrtOpts.FileFormat, "format", "f", "", "file format")
+
+ mrtCmd := &cobra.Command{
+ Use: CMD_MRT,
+ }
mrtCmd.AddCommand(dumpCmd)
return mrtCmd
diff --git a/server/grpc_server.go b/server/grpc_server.go
index 3c1c7b08..55dd4381 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -83,6 +83,7 @@ const (
REQ_MONITOR_GLOBAL_BEST_CHANGED
REQ_MONITOR_NEIGHBOR_PEER_STATE
REQ_MRT_GLOBAL_RIB
+ REQ_MRT_LOCAL_RIB
REQ_RPKI
)
@@ -598,6 +599,8 @@ func (s *Server) GetMrt(arg *api.MrtArguments, stream api.Grpc_GetMrtServer) err
switch arg.Resource {
case api.Resource_GLOBAL:
reqType = REQ_MRT_GLOBAL_RIB
+ case api.Resource_LOCAL:
+ reqType = REQ_MRT_LOCAL_RIB
default:
return fmt.Errorf("unsupported resource type: %v", arg.Resource)
}
@@ -606,7 +609,7 @@ func (s *Server) GetMrt(arg *api.MrtArguments, stream api.Grpc_GetMrtServer) err
return err
}
- req := NewGrpcRequest(reqType, "", rf, arg.Interval)
+ req := NewGrpcRequest(reqType, arg.NeighborAddress, rf, arg.Interval)
s.bgpServerCh <- req
for res := range req.ResponseCh {
if err = res.Err(); err != nil {
diff --git a/server/server.go b/server/server.go
index 444ef2ca..b2ad3764 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1290,7 +1290,7 @@ 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:
+ case REQ_MRT_GLOBAL_RIB, REQ_MRT_LOCAL_RIB:
server.handleMrt(grpcReq)
case REQ_RPKI:
server.roaClient.handleGRPC(grpcReq)
@@ -1914,8 +1914,30 @@ func (server *BgpServer) handleGrpcDelPolicies(grpcReq *GrpcRequest) {
func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) {
now := uint32(time.Now().Unix())
- msg, err := server.mkMrtPeerIndexTableMsg(now)
+ view := ""
result := &GrpcResponse{}
+ var manager *table.TableManager
+
+ switch grpcReq.RequestType {
+ case REQ_MRT_GLOBAL_RIB:
+ manager = server.localRibMap[GLOBAL_RIB_NAME].rib
+ case REQ_MRT_LOCAL_RIB:
+ _, err := server.checkNeighborRequest(grpcReq)
+ if err != nil {
+ return
+ }
+ loc, ok := server.localRibMap[grpcReq.RemoteAddr]
+ if !ok {
+ result.ResponseErr = fmt.Errorf("no local rib for %s", grpcReq.RemoteAddr)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+ manager = loc.rib
+ view = grpcReq.RemoteAddr
+ }
+
+ msg, err := server.mkMrtPeerIndexTableMsg(now, view)
if err != nil {
result.ResponseErr = fmt.Errorf("failed to make new mrt peer index table message: %s", err)
grpcReq.ResponseCh <- result
@@ -1930,7 +1952,15 @@ func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) {
return
}
- msgs, err := server.mkMrtRibMsgs(grpcReq.RouteFamily, now)
+ tbl, ok := manager.Tables[grpcReq.RouteFamily]
+ if !ok {
+ result.ResponseErr = fmt.Errorf("unsupported route family: %s", grpcReq.RouteFamily)
+ grpcReq.ResponseCh <- result
+ close(grpcReq.ResponseCh)
+ return
+ }
+
+ msgs, err := server.mkMrtRibMsgs(tbl, now)
if err != nil {
result.ResponseErr = fmt.Errorf("failed to make new mrt rib message: %s", err)
grpcReq.ResponseCh <- result
@@ -1978,7 +2008,7 @@ func (server *BgpServer) handleMrt(grpcReq *GrpcRequest) {
return
}
-func (server *BgpServer) mkMrtPeerIndexTableMsg(t uint32) (*bgp.MRTMessage, error) {
+func (server *BgpServer) mkMrtPeerIndexTableMsg(t uint32, view string) (*bgp.MRTMessage, error) {
peers := make([]*bgp.Peer, 0, len(server.neighborMap))
for _, peer := range server.neighborMap {
id := peer.peerInfo.ID.To4().String()
@@ -1987,16 +2017,11 @@ func (server *BgpServer) mkMrtPeerIndexTableMsg(t uint32) (*bgp.MRTMessage, erro
peers = append(peers, bgp.NewPeer(id, ipaddr, asn, true))
}
bgpid := server.bgpConfig.Global.GlobalConfig.RouterId.To4().String()
- table := bgp.NewPeerIndexTable(bgpid, "", peers)
+ table := bgp.NewPeerIndexTable(bgpid, view, 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)
- }
-
+func (server *BgpServer) mkMrtRibMsgs(tbl *table.Table, t uint32) ([]*bgp.MRTMessage, error) {
getPeerIndex := func(info *table.PeerInfo) uint16 {
var idx uint16
for _, peer := range server.neighborMap {
@@ -2010,7 +2035,7 @@ func (server *BgpServer) mkMrtRibMsgs(rf bgp.RouteFamily, t uint32) ([]*bgp.MRTM
var subtype bgp.MRTSubTypeTableDumpv2
- switch rf {
+ switch tbl.GetRoutefamily() {
case bgp.RF_IPv4_UC:
subtype = bgp.RIB_IPV4_UNICAST
case bgp.RF_IPv4_MC: