summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/gobgp.pb.go72
-rw-r--r--api/gobgp.proto8
-rw-r--r--gobgp/common.go17
-rw-r--r--gobgp/main.go3
-rw-r--r--gobgp/rpki.go77
-rw-r--r--gobgpd/main.go3
-rw-r--r--server/grpc_server.go21
-rw-r--r--server/rpki.go121
-rw-r--r--server/server.go8
9 files changed, 327 insertions, 3 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go
index 218f1629..0d425fd6 100644
--- a/api/gobgp.pb.go
+++ b/api/gobgp.pb.go
@@ -53,6 +53,7 @@ It has these top-level messages:
PolicyDefinition
ApplyPolicy
MrtMessage
+ ROA
*/
package api
@@ -1377,6 +1378,17 @@ func (m *MrtMessage) Reset() { *m = MrtMessage{} }
func (m *MrtMessage) String() string { return proto.CompactTextString(m) }
func (*MrtMessage) ProtoMessage() {}
+type ROA struct {
+ As uint32 `protobuf:"varint,1,opt,name=as" json:"as,omitempty"`
+ Prefixlen uint32 `protobuf:"varint,2,opt,name=prefixlen" json:"prefixlen,omitempty"`
+ Maxlen uint32 `protobuf:"varint,3,opt,name=maxlen" json:"maxlen,omitempty"`
+ Prefix string `protobuf:"bytes,4,opt,name=prefix" json:"prefix,omitempty"`
+}
+
+func (m *ROA) Reset() { *m = ROA{} }
+func (m *ROA) String() string { return proto.CompactTextString(m) }
+func (*ROA) ProtoMessage() {}
+
func init() {
proto.RegisterEnum("api.Resource", Resource_name, Resource_value)
proto.RegisterEnum("api.Operation", Operation_name, Operation_value)
@@ -1418,6 +1430,7 @@ type GrpcClient interface {
MonitorBestChanged(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (Grpc_MonitorBestChangedClient, error)
MonitorPeerState(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (Grpc_MonitorPeerStateClient, error)
GetMrt(ctx context.Context, in *MrtArguments, opts ...grpc.CallOption) (Grpc_GetMrtClient, error)
+ GetRPKI(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (Grpc_GetRPKIClient, error)
}
type grpcClient struct {
@@ -1838,6 +1851,38 @@ func (x *grpcGetMrtClient) Recv() (*MrtMessage, error) {
return m, nil
}
+func (c *grpcClient) GetRPKI(ctx context.Context, in *Arguments, opts ...grpc.CallOption) (Grpc_GetRPKIClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_Grpc_serviceDesc.Streams[10], c.cc, "/api.Grpc/GetRPKI", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpcGetRPKIClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Grpc_GetRPKIClient interface {
+ Recv() (*ROA, error)
+ grpc.ClientStream
+}
+
+type grpcGetRPKIClient struct {
+ grpc.ClientStream
+}
+
+func (x *grpcGetRPKIClient) Recv() (*ROA, error) {
+ m := new(ROA)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
// Server API for Grpc service
type GrpcServer interface {
@@ -1861,6 +1906,7 @@ type GrpcServer interface {
MonitorBestChanged(*Arguments, Grpc_MonitorBestChangedServer) error
MonitorPeerState(*Arguments, Grpc_MonitorPeerStateServer) error
GetMrt(*MrtArguments, Grpc_GetMrtServer) error
+ GetRPKI(*Arguments, Grpc_GetRPKIServer) error
}
func RegisterGrpcServer(s *grpc.Server, srv GrpcServer) {
@@ -2212,6 +2258,27 @@ func (x *grpcGetMrtServer) Send(m *MrtMessage) error {
return x.ServerStream.SendMsg(m)
}
+func _Grpc_GetRPKI_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(Arguments)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(GrpcServer).GetRPKI(m, &grpcGetRPKIServer{stream})
+}
+
+type Grpc_GetRPKIServer interface {
+ Send(*ROA) error
+ grpc.ServerStream
+}
+
+type grpcGetRPKIServer struct {
+ grpc.ServerStream
+}
+
+func (x *grpcGetRPKIServer) Send(m *ROA) error {
+ return x.ServerStream.SendMsg(m)
+}
+
var _Grpc_serviceDesc = grpc.ServiceDesc{
ServiceName: "api.Grpc",
HandlerType: (*GrpcServer)(nil),
@@ -2310,5 +2377,10 @@ var _Grpc_serviceDesc = grpc.ServiceDesc{
Handler: _Grpc_GetMrt_Handler,
ServerStreams: true,
},
+ {
+ StreamName: "GetRPKI",
+ Handler: _Grpc_GetRPKI_Handler,
+ ServerStreams: true,
+ },
},
}
diff --git a/api/gobgp.proto b/api/gobgp.proto
index 5441647c..1a573977 100644
--- a/api/gobgp.proto
+++ b/api/gobgp.proto
@@ -40,6 +40,7 @@ service Grpc {
rpc MonitorBestChanged(Arguments) returns (stream Path) {}
rpc MonitorPeerState(Arguments) returns (stream Peer) {}
rpc GetMrt(MrtArguments) returns (stream MrtMessage) {}
+ rpc GetRPKI(Arguments) returns (stream ROA) {}
}
message Error {
@@ -497,3 +498,10 @@ message ApplyPolicy {
message MrtMessage {
bytes data = 1;
}
+
+message ROA {
+ uint32 as = 1;
+ uint32 prefixlen = 2;
+ uint32 maxlen = 3;
+ string prefix = 4;
+} \ No newline at end of file
diff --git a/gobgp/common.go b/gobgp/common.go
index b65a7662..29928bac 100644
--- a/gobgp/common.go
+++ b/gobgp/common.go
@@ -58,6 +58,7 @@ const (
CMD_MRT = "mrt"
CMD_DUMP = "dump"
CMD_INJECT = "inject"
+ CMD_RPKI = "rpki"
)
var subOpts struct {
@@ -271,6 +272,22 @@ func (p policyDefinitions) Less(i, j int) bool {
return p[i].PolicyDefinitionName < p[j].PolicyDefinitionName
}
+type roas []*api.ROA
+
+func (r roas) Len() int {
+ return len(r)
+}
+
+func (r roas) Swap(i, j int) {
+ r[i], r[j] = r[j], r[i]
+}
+
+func (r roas) Less(i, j int) bool {
+ strings := sort.StringSlice{cidr2prefix(fmt.Sprintf("%s/%d", r[i].Prefix, r[i].Prefixlen)),
+ cidr2prefix(fmt.Sprintf("%s/%d", r[j].Prefix, r[j].Prefixlen))}
+ return strings.Less(0, 1)
+}
+
func connGrpc() *grpc.ClientConn {
timeout := grpc.WithTimeout(time.Second)
diff --git a/gobgp/main.go b/gobgp/main.go
index 0878c593..08134c4b 100644
--- a/gobgp/main.go
+++ b/gobgp/main.go
@@ -60,6 +60,7 @@ func main() {
policyCmd := NewPolicyCmd()
monitorCmd := NewMonitorCmd()
mrtCmd := NewMrtCmd()
- rootCmd.AddCommand(globalCmd, neighborCmd, policyCmd, monitorCmd, mrtCmd)
+ rpkiCmd := NewRPKICmd()
+ rootCmd.AddCommand(globalCmd, neighborCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd)
rootCmd.Execute()
}
diff --git a/gobgp/rpki.go b/gobgp/rpki.go
new file mode 100644
index 00000000..9ec500d7
--- /dev/null
+++ b/gobgp/rpki.go
@@ -0,0 +1,77 @@
+// 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"
+ "io"
+ "sort"
+ "net"
+ "os"
+)
+
+func showRPKITable(args []string) error {
+ af, err := checkAddressFamily(net.IP{})
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ arg := &api.Arguments{
+ Af: af,
+ }
+ stream, err := client.GetRPKI(context.Background(), arg)
+ if err != nil {
+ fmt.Println(err)
+ return err
+ }
+ l := roas{}
+ for {
+ r, err := stream.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return err
+ }
+ l = append(l, r)
+ }
+ sort.Sort(l)
+ var format string
+ if af.Afi == bgp.AFI_IP {
+ format = "%-18s %-6s %s\n"
+ } else {
+ format = "%-42s %-6s %s\n"
+ }
+ fmt.Printf(format, "Network", "Maxlen", "AS")
+ for _, r := range l {
+ fmt.Printf(format, fmt.Sprintf("%s/%d", r.Prefix, r.Prefixlen), fmt.Sprint(r.Maxlen), fmt.Sprint(r.Maxlen))
+ }
+ return nil
+}
+
+func NewRPKICmd() *cobra.Command {
+ rpkiCmd := &cobra.Command{
+ Use: CMD_RPKI,
+ Run: func(cmd *cobra.Command, args []string) {
+ showRPKITable(args)
+ },
+ }
+ rpkiCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")
+ return rpkiCmd
+}
diff --git a/gobgpd/main.go b/gobgpd/main.go
index 89cd0cb8..9d96401b 100644
--- a/gobgpd/main.go
+++ b/gobgpd/main.go
@@ -46,6 +46,7 @@ func main() {
DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"`
EnableZapi bool `short:"z" long:"enable-zapi" description:"enable zebra api"`
ZapiURL string `long:"zapi-url" description:"specify zebra api url"`
+ RPKIServer string `long:"rpki-server" description:"specify rpki server url"`
}
_, err := flags.Parse(&opts)
if err != nil {
@@ -141,7 +142,7 @@ func main() {
reloadCh := make(chan bool)
go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh)
reloadCh <- true
- bgpServer := server.NewBgpServer(bgp.BGP_PORT)
+ bgpServer := server.NewBgpServer(bgp.BGP_PORT, opts.RPKIServer)
go bgpServer.Serve()
// start grpc Server
diff --git a/server/grpc_server.go b/server/grpc_server.go
index 4a652c4f..a4e61be7 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_RPKI
)
const GRPC_PORT = 8080
@@ -621,6 +622,26 @@ END:
return err
}
+func (s *Server) GetRPKI(arg *api.Arguments, stream api.Grpc_GetRPKIServer) error {
+ rf, err := convertAf2Rf(arg.Af)
+ if err != nil {
+ return err
+ }
+ req := NewGrpcRequest(REQ_RPKI, "", rf, nil)
+ s.bgpServerCh <- req
+
+ for res := range req.ResponseCh {
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return err
+ }
+ if err := stream.Send(res.Data.(*api.ROA)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
type GrpcRequest struct {
RequestType int
RemoteAddr string
diff --git a/server/rpki.go b/server/rpki.go
new file mode 100644
index 00000000..6ad6aa0a
--- /dev/null
+++ b/server/rpki.go
@@ -0,0 +1,121 @@
+// 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 server
+
+import (
+ "bufio"
+ "fmt"
+ "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/packet"
+ "net"
+)
+
+type roa struct {
+ AS uint32
+ PrefixLen uint8
+ MaxLen uint8
+ Prefix net.IP
+}
+
+func (r *roa) key() string {
+ return fmt.Sprintf("%s/%d", r.Prefix.String(), r.PrefixLen)
+}
+
+func (r *roa) toApiStruct() *api.ROA {
+ return &api.ROA{
+ As: r.AS,
+ Prefixlen: uint32(r.PrefixLen),
+ Maxlen: uint32(r.MaxLen),
+ Prefix: r.Prefix.String(),
+ }
+}
+
+type roaClient struct {
+ roas map[bgp.RouteFamily]map[string]*roa
+ outgoing chan *roa
+}
+
+func (c *roaClient) recieveROA() chan *roa {
+ return c.outgoing
+}
+
+func (c *roaClient) handleRTRMsg(r *roa) {
+ if r.Prefix.To4() != nil {
+ c.roas[bgp.RF_IPv4_UC][r.key()] = r
+ } else {
+ c.roas[bgp.RF_IPv6_UC][r.key()] = r
+ }
+}
+
+func (c *roaClient) handleGRPC(grpcReq *GrpcRequest) {
+ if roas, ok := c.roas[grpcReq.RouteFamily]; ok {
+ for _, r := range roas {
+ result := &GrpcResponse{}
+ result.Data = r.toApiStruct()
+ grpcReq.ResponseCh <- result
+ }
+ }
+ close(grpcReq.ResponseCh)
+}
+
+func newROAClient(url string) (*roaClient, error) {
+ c := &roaClient{
+ roas: make(map[bgp.RouteFamily]map[string]*roa),
+ }
+ c.roas[bgp.RF_IPv4_UC] = make(map[string]*roa)
+ c.roas[bgp.RF_IPv6_UC] = make(map[string]*roa)
+
+ if url == "" {
+ return c, nil
+ }
+
+ conn, err := net.Dial("tcp", url)
+ if err != nil {
+ return c, err
+ }
+
+ r := bgp.NewRTRResetQuery()
+ data, _ := r.Serialize()
+ conn.Write(data)
+ reader := bufio.NewReader(conn)
+ scanner := bufio.NewScanner(reader)
+ scanner.Split(bgp.SplitRTR)
+
+ ch := make(chan *roa)
+ c.outgoing = ch
+
+ go func(ch chan *roa) {
+ for scanner.Scan() {
+ m, _ := bgp.ParseRTR(scanner.Bytes())
+ if m != nil {
+ switch msg := m.(type) {
+ case *bgp.RTRIPPrefix:
+ p := make([]byte, len(msg.Prefix))
+ copy(p, msg.Prefix)
+ ch <- &roa{
+ AS: msg.AS,
+ PrefixLen: msg.PrefixLen,
+ MaxLen: msg.MaxLen,
+ Prefix: p,
+ }
+ }
+
+ }
+ }
+ }(ch)
+
+ return c, nil
+}
diff --git a/server/server.go b/server/server.go
index ef0b2ce3..dfc7058a 100644
--- a/server/server.go
+++ b/server/server.go
@@ -79,9 +79,10 @@ type BgpServer struct {
neighborMap map[string]*Peer
localRibMap map[string]*LocalRib
zclient *zebra.Client
+ roaClient *roaClient
}
-func NewBgpServer(port int) *BgpServer {
+func NewBgpServer(port int, roaURL string) *BgpServer {
b := BgpServer{}
b.globalTypeCh = make(chan config.Global)
b.addedPeerCh = make(chan config.Neighbor)
@@ -91,6 +92,7 @@ func NewBgpServer(port int) *BgpServer {
b.localRibMap = make(map[string]*LocalRib)
b.neighborMap = make(map[string]*Peer)
b.listenPort = port
+ b.roaClient, _ = newROAClient(roaURL)
return &b
}
@@ -214,6 +216,8 @@ func (server *BgpServer) Serve() {
}
select {
+ case rmsg := <-server.roaClient.recieveROA():
+ server.roaClient.handleRTRMsg(rmsg)
case zmsg := <-zapiMsgCh:
handleZapiMsg(zmsg)
case conn := <-acceptCh:
@@ -1289,6 +1293,8 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
server.broadcastReqs = append(server.broadcastReqs, grpcReq)
case REQ_MRT_GLOBAL_RIB:
server.handleMrt(grpcReq)
+ case REQ_RPKI:
+ server.roaClient.handleGRPC(grpcReq)
default:
errmsg := fmt.Errorf("Unknown request type: %v", grpcReq.RequestType)
result := &GrpcResponse{