diff options
-rw-r--r-- | api/gobgp.pb.go | 9 | ||||
-rw-r--r-- | api/gobgp.proto | 1 | ||||
-rw-r--r-- | gobgp/mrt.go | 182 | ||||
-rw-r--r-- | gomrt/main.go | 182 | ||||
-rw-r--r-- | server/server.go | 2 | ||||
-rw-r--r-- | table/destination.go | 3 | ||||
-rw-r--r-- | table/destination_test.go | 2 | ||||
-rw-r--r-- | table/path.go | 6 | ||||
-rw-r--r-- | table/path_test.go | 20 | ||||
-rw-r--r-- | table/table_manager.go | 8 | ||||
-rw-r--r-- | table/table_test.go | 2 |
11 files changed, 209 insertions, 208 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 2f5a50fa..a7e0d90d 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -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{} } diff --git a/api/gobgp.proto b/api/gobgp.proto index cb85db27..84844214 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -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 { diff --git a/gobgp/mrt.go b/gobgp/mrt.go index e32a0931..2a0ae5ea 100644 --- a/gobgp/mrt.go +++ b/gobgp/mrt.go @@ -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 } diff --git a/gomrt/main.go b/gomrt/main.go deleted file mode 100644 index aeca76af..00000000 --- a/gomrt/main.go +++ /dev/null @@ -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() - -} diff --git a/server/server.go b/server/server.go index 8eca9d75..0604fded 100644 --- a/server/server.go +++ b/server/server.go @@ -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) diff --git a/table/destination.go b/table/destination.go index 65697570..5b704e6b 100644 --- a/table/destination.go +++ b/table/destination.go @@ -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 diff --git a/table/destination_test.go b/table/destination_test.go index 0b1b8e3b..80eaa2a4 100644 --- a/table/destination_test.go +++ b/table/destination_test.go @@ -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 } diff --git a/table/path.go b/table/path.go index 251eefbc..18b118b9 100644 --- a/table/path.go +++ b/table/path.go @@ -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 { diff --git a/table/path_test.go b/table/path_test.go index d973294a..7fca310f 100644 --- a/table/path_test.go +++ b/table/path_test.go @@ -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 } diff --git a/table/table_manager.go b/table/table_manager.go index 65ead593..4b164228 100644 --- a/table/table_manager.go +++ b/table/table_manager.go @@ -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) } } diff --git a/table/table_test.go b/table/table_test.go index de8b271c..9f1e6f16 100644 --- a/table/table_test.go +++ b/table/table_test.go @@ -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 } |