mrt: merge gomrt to gobgp cli command

Usage
$ gobgp mrt inject global <filename> [<count>]

Signed-off-by: ISHIDA Wataru <[email protected]>
This commit is contained in:
ISHIDA Wataru
2015-08-03 21:59:39 +09:00
committed by FUJITA Tomonori
parent 84dd9d6983
commit cf23ecec82
11 changed files with 209 additions and 208 deletions
+5 -4
View File
@@ -590,10 +590,11 @@ func (m *Arguments) GetAf() *AddressFamily {
}
type ModPathArguments struct {
Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"`
IsWithdraw bool `protobuf:"varint,2,opt,name=is_withdraw" json:"is_withdraw,omitempty"`
RawNlri []byte `protobuf:"bytes,3,opt,name=raw_nlri,proto3" json:"raw_nlri,omitempty"`
RawPattrs [][]byte `protobuf:"bytes,4,rep,name=raw_pattrs,proto3" json:"raw_pattrs,omitempty"`
Resource Resource `protobuf:"varint,1,opt,name=resource,enum=api.Resource" json:"resource,omitempty"`
IsWithdraw bool `protobuf:"varint,2,opt,name=is_withdraw" json:"is_withdraw,omitempty"`
RawNlri []byte `protobuf:"bytes,3,opt,name=raw_nlri,proto3" json:"raw_nlri,omitempty"`
RawPattrs [][]byte `protobuf:"bytes,4,rep,name=raw_pattrs,proto3" json:"raw_pattrs,omitempty"`
NoImplicitWithdraw bool `protobuf:"varint,5,opt,name=no_implicit_withdraw" json:"no_implicit_withdraw,omitempty"`
}
func (m *ModPathArguments) Reset() { *m = ModPathArguments{} }
+1
View File
@@ -63,6 +63,7 @@ message ModPathArguments {
bool is_withdraw = 2;
bytes raw_nlri = 3;
repeated bytes raw_pattrs = 4;
bool no_implicit_withdraw = 5;
}
message PolicyArguments {
+179 -3
View File
@@ -178,9 +178,155 @@ func dumpRib(r string, remoteIP net.IP, args []string) error {
return nil
}
func injectMrt(r string, filename string, count int) error {
var resource api.Resource
switch r {
case CMD_GLOBAL:
resource = api.Resource_GLOBAL
default:
return fmt.Errorf("unknown resource type: %s", r)
}
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open file: %s", err)
}
idx := 0
ch := make(chan *api.ModPathArguments, 1024)
go func() {
var peers []*bgp.Peer
for {
buf := make([]byte, bgp.MRT_COMMON_HEADER_LEN)
_, err := file.Read(buf)
if err == io.EOF {
break
} else if err != nil {
fmt.Println("failed to read:", err)
os.Exit(1)
}
h := &bgp.MRTHeader{}
err = h.DecodeFromBytes(buf)
if err != nil {
fmt.Println("failed to parse")
os.Exit(1)
}
buf = make([]byte, h.Len)
_, err = file.Read(buf)
if err != nil {
fmt.Println("failed to read")
os.Exit(1)
}
msg, err := bgp.ParseMRTBody(h, buf)
if err != nil {
fmt.Println("failed to parse:", err)
os.Exit(1)
}
if globalOpts.Debug {
fmt.Println(msg)
}
if msg.Header.Type == bgp.TABLE_DUMPv2 {
subType := bgp.MRTSubTypeTableDumpv2(msg.Header.SubType)
var af *api.AddressFamily
switch subType {
case bgp.PEER_INDEX_TABLE:
peers = msg.Body.(*bgp.PeerIndexTable).Peers
continue
case bgp.RIB_IPV4_UNICAST:
af = api.AF_IPV4_UC
case bgp.RIB_IPV6_UNICAST:
af = api.AF_IPV6_UC
default:
fmt.Println("unsupported subType:", subType)
os.Exit(1)
}
if peers == nil {
fmt.Println("not found PEER_INDEX_TABLE")
os.Exit(1)
}
rib := msg.Body.(*bgp.Rib)
nlri := rib.Prefix
for _, e := range rib.Entries {
arg := &api.ModPathArguments{
Resource: resource,
RawPattrs: make([][]byte, 0),
NoImplicitWithdraw: true,
}
if len(peers) < int(e.PeerIndex) {
fmt.Printf("invalid peer index: %d (PEER_INDEX_TABLE has only %d peers)\n", e.PeerIndex, len(peers))
os.Exit(1)
}
nexthop := peers[e.PeerIndex].IpAddress.String()
if af == api.AF_IPV4_UC {
arg.RawNlri, _ = nlri.Serialize()
n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize()
arg.RawPattrs = append(arg.RawPattrs, n)
} else {
mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize()
arg.RawPattrs = append(arg.RawPattrs, mpreach)
}
for _, p := range e.PathAttributes {
b, err := p.Serialize()
if err != nil {
continue
}
arg.RawPattrs = append(arg.RawPattrs, b)
}
ch <- arg
}
idx += 1
if idx == count {
break
}
}
}
close(ch)
}()
stream, err := client.ModPath(context.Background())
if err != nil {
return fmt.Errorf("failed to modpath:", err)
}
for arg := range ch {
err = stream.Send(arg)
if err != nil {
return fmt.Errorf("failed to send:", err)
}
}
res, err := stream.CloseAndRecv()
if err != nil {
return fmt.Errorf("failed to send: %s", err)
}
if res.Code != api.Error_SUCCESS {
return fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
}
return nil
}
func NewMrtCmd() *cobra.Command {
globalCmd := &cobra.Command{
globalDumpCmd := &cobra.Command{
Use: CMD_GLOBAL,
Run: func(cmd *cobra.Command, args []string) {
err := dumpRib(CMD_GLOBAL, net.IP{}, args)
@@ -214,7 +360,7 @@ func NewMrtCmd() *cobra.Command {
ribCmd := &cobra.Command{
Use: CMD_RIB,
}
ribCmd.AddCommand(globalCmd, neighborCmd)
ribCmd.AddCommand(globalDumpCmd, neighborCmd)
ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")
dumpCmd := &cobra.Command{
@@ -224,10 +370,40 @@ func NewMrtCmd() *cobra.Command {
dumpCmd.PersistentFlags().StringVarP(&mrtOpts.OutputDir, "outdir", "o", ".", "output directory")
dumpCmd.PersistentFlags().StringVarP(&mrtOpts.FileFormat, "format", "f", "", "file format")
globalInjectCmd := &cobra.Command{
Use: CMD_GLOBAL,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
fmt.Println("usage: gobgp mrt inject global <filename> [<count>]")
os.Exit(1)
}
filename := args[0]
count := -1
if len(args) > 1 {
var err error
count, err = strconv.Atoi(args[1])
if err != nil {
fmt.Println("invalid count value:", args[1])
os.Exit(1)
}
}
err := injectMrt(CMD_GLOBAL, filename, count)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
injectCmd := &cobra.Command{
Use: CMD_INJECT,
}
injectCmd.AddCommand(globalInjectCmd)
mrtCmd := &cobra.Command{
Use: CMD_MRT,
}
mrtCmd.AddCommand(dumpCmd)
mrtCmd.AddCommand(dumpCmd, injectCmd)
return mrtCmd
}
-182
View File
@@ -1,182 +0,0 @@
// Copyright (C) 2015 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 main
import (
"fmt"
"github.com/osrg/gobgp/api"
"github.com/osrg/gobgp/packet"
"github.com/spf13/cobra"
"golang.org/x/net/context"
"google.golang.org/grpc"
"io"
"net"
"os"
"time"
)
var globalOpts struct {
Host string
Port int
Input string
Count int
}
var client api.GrpcClient
func connGrpc() *grpc.ClientConn {
timeout := grpc.WithTimeout(time.Second)
// determine IP address version
host := net.ParseIP(globalOpts.Host)
target := fmt.Sprintf("%s:%d", globalOpts.Host, globalOpts.Port)
if host.To4() == nil {
target = fmt.Sprintf("[%s]:%d", globalOpts.Host, globalOpts.Port)
}
conn, err := grpc.Dial(target, timeout)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return conn
}
func main() {
rootCmd := &cobra.Command{
Use: "gomrt",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
conn := connGrpc()
client = api.NewGrpcClient(conn)
},
Run: func(cmd *cobra.Command, args []string) {
file, err := os.Open(globalOpts.Input)
if err != nil {
fmt.Println("failed to open file")
os.Exit(1)
}
idx := 0
ch := make(chan *api.Path, 1024)
go func() {
for {
buf := make([]byte, bgp.MRT_COMMON_HEADER_LEN)
_, err := file.Read(buf)
if err == io.EOF {
break
} else if err != nil {
fmt.Println("failed to read:", err)
os.Exit(1)
}
h := &bgp.MRTHeader{}
err = h.DecodeFromBytes(buf)
if err != nil {
fmt.Println("failed to parse")
os.Exit(1)
}
buf = make([]byte, h.Len)
_, err = file.Read(buf)
if err != nil {
fmt.Println("failed to read")
os.Exit(1)
}
msg, err := bgp.ParseMRTBody(h, buf)
if err != nil {
fmt.Println("failed to parse:", err)
os.Exit(1)
}
if msg.Header.Type == bgp.TABLE_DUMPv2 {
subType := bgp.MRTSubTypeTableDumpv2(msg.Header.SubType)
var af *api.AddressFamily
switch subType {
case bgp.PEER_INDEX_TABLE:
continue
case bgp.RIB_IPV4_UNICAST:
af = api.AF_IPV4_UC
case bgp.RIB_IPV6_UNICAST:
af = api.AF_IPV6_UC
default:
fmt.Println("unsupported subType:", subType)
os.Exit(1)
}
rib := msg.Body.(*bgp.Rib)
prefix := rib.Prefix.String()
path := &api.Path{}
path.Nlri = &api.Nlri{
Af: af,
Prefix: prefix,
}
ch <- path
}
idx += 1
if idx == globalOpts.Count {
break
}
}
close(ch)
}()
stream, err := client.ModPath(context.Background())
if err != nil {
fmt.Println("failed to modpath:", err)
os.Exit(1)
}
for path := range ch {
arg := &api.ModPathArguments{
Resource: api.Resource_GLOBAL,
Path: path,
}
err = stream.Send(arg)
if err != nil {
fmt.Println("failed to send:", err)
os.Exit(1)
}
}
res, err := stream.CloseAndRecv()
if err != nil {
fmt.Println("failed to send:", err)
os.Exit(1)
}
if res.Code != api.Error_SUCCESS {
fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
os.Exit(1)
}
},
}
rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host")
rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 8080, "port")
rootCmd.Flags().StringVarP(&globalOpts.Input, "input", "i", "", "input mrt file")
rootCmd.Flags().IntVarP(&globalOpts.Count, "count", "c", -1, "how many mrt record you read")
rootCmd.Execute()
}
+1 -1
View File
@@ -792,7 +792,7 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t
goto ERR
}
return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now())}
return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), args.NoImplicitWithdraw)}
ERR:
grpcReq.ResponseCh <- result
close(grpcReq.ResponseCh)
+3
View File
@@ -369,6 +369,9 @@ func (dest *Destination) removeOldPaths() {
knownPaths := dest.knownPathList
for _, newPath := range newPaths {
if newPath.NoImplicitWithdraw {
continue
}
oldPaths := make([]*Path, 0)
for _, path := range knownPaths {
// Here we just check if source is same and not check if path
+1 -1
View File
@@ -124,7 +124,7 @@ func DestCreatePath(peerD []*PeerInfo) []*Path {
nlriList := updateMsgD.NLRI
pathAttributes := updateMsgD.PathAttributes
nlri_info := nlriList[0]
pathD[i] = NewPath(peerD[i], &nlri_info, false, pathAttributes, false, time.Now())
pathD[i] = NewPath(peerD[i], &nlri_info, false, pathAttributes, false, time.Now(), false)
}
return pathD
}
+4 -2
View File
@@ -35,9 +35,10 @@ type Path struct {
pathAttrs []bgp.PathAttributeInterface
medSetByTargetNeighbor bool
timestamp time.Time
NoImplicitWithdraw bool
}
func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, medSetByTargetNeighbor bool, timestamp time.Time) *Path {
func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, medSetByTargetNeighbor bool, timestamp time.Time, noImplicitWithdraw bool) *Path {
if !isWithdraw && pattrs == nil {
log.WithFields(log.Fields{
"Topic": "Table",
@@ -54,6 +55,7 @@ func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pa
pathAttrs: pattrs,
medSetByTargetNeighbor: medSetByTargetNeighbor,
timestamp: timestamp,
NoImplicitWithdraw: noImplicitWithdraw,
}
}
@@ -172,7 +174,7 @@ func (path *Path) Clone(isWithdraw bool) *Path {
newPathAttrs[i] = v
}
return NewPath(path.source, nlri, isWithdraw, newPathAttrs, false, path.timestamp)
return NewPath(path.source, nlri, isWithdraw, newPathAttrs, false, path.timestamp, path.NoImplicitWithdraw)
}
func (path *Path) GetRouteFamily() bgp.RouteFamily {
+10 -10
View File
@@ -14,13 +14,13 @@ import (
func TestPathNewIPv4(t *testing.T) {
peerP := PathCreatePeer()
pathP := PathCreatePath(peerP)
ipv4p := NewPath(pathP[0].GetSource(), pathP[0].GetNlri(), true, pathP[0].GetPathAttrs(), pathP[0].getMedSetByTargetNeighbor(), time.Now())
ipv4p := NewPath(pathP[0].GetSource(), pathP[0].GetNlri(), true, pathP[0].GetPathAttrs(), pathP[0].getMedSetByTargetNeighbor(), time.Now(), false)
assert.NotNil(t, ipv4p)
}
func TestPathNewIPv6(t *testing.T) {
peerP := PathCreatePeer()
pathP := PathCreatePath(peerP)
ipv6p := NewPath(pathP[0].GetSource(), pathP[0].GetNlri(), true, pathP[0].GetPathAttrs(), pathP[0].getMedSetByTargetNeighbor(), time.Now())
ipv6p := NewPath(pathP[0].GetSource(), pathP[0].GetNlri(), true, pathP[0].GetPathAttrs(), pathP[0].getMedSetByTargetNeighbor(), time.Now(), false)
assert.NotNil(t, ipv6p)
}
@@ -72,7 +72,7 @@ func TestPathCreatePath(t *testing.T) {
nlriList := updateMsgP.NLRI
pathAttributes := updateMsgP.PathAttributes
nlri_info := nlriList[0]
path := NewPath(peerP[0], &nlri_info, false, pathAttributes, false, time.Now())
path := NewPath(peerP[0], &nlri_info, false, pathAttributes, false, time.Now(), false)
assert.NotNil(t, path)
}
@@ -118,7 +118,7 @@ func TestASPathLen(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
assert.Equal(10, p.GetAsPathLen())
}
@@ -145,7 +145,7 @@ func TestPathPrependAsnToExistingSeqAttr(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
p.PrependAsn(65000, 1)
assert.Equal([]uint32{65000, 65001, 65002, 65003, 65004, 65005}, p.GetAsSeqList())
@@ -168,7 +168,7 @@ func TestPathPrependAsnToNewAsPathAttr(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
asn := uint32(65000)
p.PrependAsn(asn, 1)
@@ -197,7 +197,7 @@ func TestPathPrependAsnToNewAsPathSeq(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
asn := uint32(65000)
p.PrependAsn(asn, 1)
@@ -228,7 +228,7 @@ func TestPathPrependAsnToEmptyAsPathAttr(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
asn := uint32(65000)
p.PrependAsn(asn, 1)
@@ -265,7 +265,7 @@ func TestPathPrependAsnToFullPathAttr(t *testing.T) {
update := bgpmsg.Body.(*bgp.BGPUpdate)
UpdatePathAttrs4ByteAs(update)
peer := PathCreatePeer()
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now())
p := NewPath(peer[0], &update.NLRI[0], false, update.PathAttributes, false, time.Now(), false)
expected := []uint32{65000, 65000}
for _, v := range asns {
@@ -294,7 +294,7 @@ func PathCreatePath(peerP []*PeerInfo) []*Path {
nlriList := updateMsgP.NLRI
pathAttributes := updateMsgP.PathAttributes
nlri_info := nlriList[0]
pathP[i] = NewPath(peerP[i], &nlri_info, false, pathAttributes, false, time.Now())
pathP[i] = NewPath(peerP[i], &nlri_info, false, pathAttributes, false, time.Now(), false)
}
return pathP
}
+4 -4
View File
@@ -30,7 +30,7 @@ func nlri2Path(m *bgp.BGPMessage, p *PeerInfo, now time.Time) []*Path {
// define local variable to pass nlri's address to CreatePath
var nlri bgp.NLRInfo = nlri_info
// create Path object
path := NewPath(p, &nlri, false, pathAttributes, false, now)
path := NewPath(p, &nlri, false, pathAttributes, false, now, false)
pathList = append(pathList, path)
}
return pathList
@@ -44,7 +44,7 @@ func withdraw2Path(m *bgp.BGPMessage, p *PeerInfo, now time.Time) []*Path {
// define local variable to pass nlri's address to CreatePath
var w bgp.WithdrawnRoute = nlriWithdraw
// create withdrawn Path object
path := NewPath(p, &w, true, pathAttributes, false, now)
path := NewPath(p, &w, true, pathAttributes, false, now, false)
pathList = append(pathList, path)
}
return pathList
@@ -67,7 +67,7 @@ func mpreachNlri2Path(m *bgp.BGPMessage, p *PeerInfo, now time.Time) []*Path {
for _, mp := range attrList {
nlri_info := mp.Value
for _, nlri := range nlri_info {
path := NewPath(p, nlri, false, pathAttributes, false, now)
path := NewPath(p, nlri, false, pathAttributes, false, now, false)
pathList = append(pathList, path)
}
}
@@ -92,7 +92,7 @@ func mpunreachNlri2Path(m *bgp.BGPMessage, p *PeerInfo, now time.Time) []*Path {
nlri_info := mp.Value
for _, nlri := range nlri_info {
path := NewPath(p, nlri, true, pathAttributes, false, now)
path := NewPath(p, nlri, true, pathAttributes, false, now, false)
pathList = append(pathList, path)
}
}
+1 -1
View File
@@ -107,7 +107,7 @@ func TableCreatePath(peerT []*PeerInfo) []*Path {
nlriList := updateMsgT.NLRI
pathAttributes := updateMsgT.PathAttributes
nlri_info := nlriList[0]
pathT[i] = NewPath(peerT[i], &nlri_info, false, pathAttributes, false, time.Now())
pathT[i] = NewPath(peerT[i], &nlri_info, false, pathAttributes, false, time.Now(), false)
}
return pathT
}